runtime-rs: agent implements

Responsible for communicating with the agent, such as kata-agent in the VM

Fixes: #3785
Signed-off-by: Quanwei Zhou <quanweiZhou@linux.alibaba.com>
This commit is contained in:
Quanwei Zhou 2021-12-03 18:53:48 +08:00 committed by Fupan Li
parent d3da156eea
commit 4296e3069f
14 changed files with 2317 additions and 34 deletions

View File

@ -33,9 +33,29 @@ pub struct Agent {
#[serde(default)]
pub debug_console_enabled: bool,
/// Agent connection dialing timeout value in seconds
/// Agent server port
#[serde(default)]
pub dial_timeout: u32,
pub server_port: u32,
/// Agent log port
#[serde(default)]
pub log_port: u32,
/// Agent connection dialing timeout value in millisecond
#[serde(default = "default_dial_timeout")]
pub dial_timeout_ms: u32,
/// Agent reconnect timeout value in millisecond
#[serde(default = "default_reconnect_timeout")]
pub reconnect_timeout_ms: u32,
/// Agent request timeout value in millisecond
#[serde(default = "default_request_timeout")]
pub request_timeout_ms: u32,
/// Agent health check request timeout value in millisecond
#[serde(default = "default_health_check_timeout")]
pub health_check_request_timeout_ms: u32,
/// Comma separated list of kernel modules and their parameters.
///
@ -55,6 +75,26 @@ pub struct Agent {
pub container_pipe_size: u32,
}
fn default_dial_timeout() -> u32 {
// 10ms
10
}
fn default_reconnect_timeout() -> u32 {
// 3s
3_000
}
fn default_request_timeout() -> u32 {
// 30s
30_000
}
fn default_health_check_timeout() -> u32 {
// 90s
90_000
}
impl ConfigOps for Agent {
fn adjust_config(conf: &mut TomlConfig) -> Result<()> {
AgentVendor::adjust_config(conf)?;

View File

@ -21,7 +21,7 @@ pub mod default;
mod agent;
pub mod hypervisor;
use self::agent::Agent;
pub use self::agent::Agent;
pub use self::hypervisor::{
BootInfo, DragonballConfig, Hypervisor, QemuConfig, HYPERVISOR_NAME_DRAGONBALL,
HYPERVISOR_NAME_QEMU,

View File

@ -17,6 +17,27 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "agent"
version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"futures 0.1.31",
"kata-types",
"log",
"oci",
"protobuf",
"protocols",
"serde",
"serde_json",
"slog",
"slog-scope",
"tokio",
"ttrpc",
"url",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -28,9 +49,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.55"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]]
name = "arc-swap"
@ -178,9 +199,9 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]]
name = "crossbeam-channel"
version = "0.5.2"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
@ -188,14 +209,25 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
"cfg-if 1.0.0",
"lazy_static",
]
[[package]]
name = "derive-new"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.9.0"
@ -205,6 +237,12 @@ dependencies = [
"generic-array",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "enum-iterator"
version = "0.7.0"
@ -245,6 +283,12 @@ dependencies = [
"instant",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
@ -255,6 +299,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "futures"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
[[package]]
name = "futures"
version = "0.3.21"
@ -356,13 +406,13 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
@ -385,9 +435,9 @@ checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
[[package]]
name = "git2"
version = "0.13.25"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6"
checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c"
dependencies = [
"bitflags",
"libc",
@ -411,6 +461,21 @@ dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -431,6 +496,16 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -449,6 +524,15 @@ dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.1"
@ -510,15 +594,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.119"
version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]]
name = "libgit2-sys"
version = "0.12.26+1.3.0"
version = "0.13.2+1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494"
checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b"
dependencies = [
"cc",
"libc",
@ -528,9 +612,9 @@ dependencies = [
[[package]]
name = "libz-sys"
version = "1.1.3"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66"
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
dependencies = [
"cc",
"libc",
@ -600,14 +684,15 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.0"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2"
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
dependencies = [
"libc",
"log",
"miow",
"ntapi",
"wasi 0.11.0+wasi-snapshot-preview1",
"winapi",
]
@ -620,6 +705,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "multimap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "nix"
version = "0.16.1"
@ -686,9 +777,9 @@ dependencies = [
[[package]]
name = "num_threads"
version = "0.1.3"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15"
checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0"
dependencies = [
"libc",
]
@ -755,6 +846,16 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "pin-project-lite"
version = "0.2.8"
@ -812,11 +913,66 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "prost"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020"
dependencies = [
"bytes 1.1.0",
"prost-derive",
]
[[package]]
name = "prost-build"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
dependencies = [
"bytes 1.1.0",
"heck",
"itertools",
"log",
"multimap",
"petgraph",
"prost",
"prost-types",
"tempfile",
"which",
]
[[package]]
name = "prost-derive"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b"
dependencies = [
"bytes 1.1.0",
"prost",
]
[[package]]
name = "protobuf"
version = "2.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96"
dependencies = [
"serde",
"serde_derive",
]
[[package]]
name = "protobuf-codegen"
@ -837,11 +993,22 @@ dependencies = [
"protobuf-codegen",
]
[[package]]
name = "protocols"
version = "0.1.0"
dependencies = [
"async-trait",
"oci",
"protobuf",
"ttrpc",
"ttrpc-codegen",
]
[[package]]
name = "quote"
version = "1.0.15"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57"
dependencies = [
"proc-macro2",
]
@ -878,18 +1045,18 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.5.4"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
@ -1132,9 +1299,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.86"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
dependencies = [
"proc-macro2",
"quote",
@ -1268,7 +1435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e0723fc001950a3b018947b05eeb45014fd2b7c6e8f292502193ab74486bdb6"
dependencies = [
"bytes 0.4.12",
"futures",
"futures 0.3.21",
"libc",
"tokio",
"vsock",
@ -1291,7 +1458,7 @@ checksum = "0c7d6c992964a013c17814c08d31708d577b0aae44ebadb58755659dd824c2d1"
dependencies = [
"async-trait",
"byteorder",
"futures",
"futures 0.3.21",
"libc",
"log",
"nix 0.23.1",
@ -1302,6 +1469,33 @@ dependencies = [
"tokio-vsock",
]
[[package]]
name = "ttrpc-codegen"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809eda4e459820237104e4b61d6b41bbe6c9e1ce6adf4057955e6e6722a90408"
dependencies = [
"protobuf",
"protobuf-codegen",
"protobuf-codegen-pure",
"ttrpc-compiler",
]
[[package]]
name = "ttrpc-compiler"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2978ed3fa047d8fd55cbeb4d4a61d461fb3021a90c9618519c73ce7e5bb66c15"
dependencies = [
"derive-new",
"prost",
"prost-build",
"prost-types",
"protobuf",
"protobuf-codegen",
"tempfile",
]
[[package]]
name = "typenum"
version = "1.15.0"
@ -1323,6 +1517,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-xid"
version = "0.2.2"
@ -1401,6 +1601,23 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
dependencies = [
"either",
"lazy_static",
"libc",
]
[[package]]
name = "winapi"
version = "0.3.9"

View File

@ -1,4 +1,6 @@
[workspace]
members = [
"crates/shim",
# TODO: current only for check, delete after use the agent crate
"crates/agent",
]

View File

@ -0,0 +1,28 @@
[package]
name = "agent"
version = "0.1.0"
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
edition = "2018"
[dev-dependencies]
futures = "0.1.27"
[dependencies]
anyhow = "1.0.26"
async-trait = "0.1.48"
log = "0.4.14"
protobuf = "2.23.0"
serde = { version = "^1.0", features = ["derive"] }
serde_json = ">=1.0.9"
slog = "2.5.2"
slog-scope = "4.4.0"
ttrpc = { version = "0.6.0" }
tokio = { version = "1.8.0", features = ["fs", "rt"] }
url = "2.2.2"
kata-types = { path = "../../../libs/kata-types"}
oci = { path = "../../../libs/oci" }
protocols = { path = "../../../libs/protocols", features=["async"] }
[features]
default = []

View File

@ -0,0 +1,110 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::{Context, Result};
use async_trait::async_trait;
use ttrpc::context as ttrpc_ctx;
use crate::{kata::KataAgent, Agent, AgentManager, HealthService};
/// millisecond to nanosecond
const MILLISECOND_TO_NANOSECOND: i64 = 1_000_000;
/// new ttrpc context with timeout
fn new_ttrpc_ctx(timeout: i64) -> ttrpc_ctx::Context {
ttrpc_ctx::with_timeout(timeout)
}
#[async_trait]
impl AgentManager for KataAgent {
async fn set_socket_address(&self, address: &str) -> Result<()> {
let mut inner = self.inner.lock().await;
inner.socket_address = address.to_string();
Ok(())
}
async fn start(&self) -> Result<()> {
info!(sl!(), "begin to connect agent");
self.connect_agent_server()
.await
.context("connect agent server")?;
self.start_log_forwarder()
.await
.context("connect log forwarder")?;
Ok(())
}
async fn stop(&self) {
self.stop_log_forwarder().await;
}
}
// implement for health service
macro_rules! impl_health_service {
($($name: tt | $req: ty | $resp: ty),*) => {
#[async_trait]
impl HealthService for KataAgent {
$(async fn $name(&self, req: $req) -> Result<$resp> {
let r = req.into();
let (mut client, timeout, _) = self.get_health_client().await.context("get health client")?;
let resp = client.$name(new_ttrpc_ctx(timeout * MILLISECOND_TO_NANOSECOND), &r).await?;
Ok(resp.into())
})*
}
};
}
impl_health_service!(
check | crate::CheckRequest | crate::HealthCheckResponse,
version | crate::CheckRequest | crate::VersionCheckResponse
);
macro_rules! impl_agent {
($($name: tt | $req: ty | $resp: ty | $new_timeout: expr),*) => {
#[async_trait]
impl Agent for KataAgent {
$(async fn $name(&self, req: $req) -> Result<$resp> {
let r = req.into();
let (mut client, mut timeout, _) = self.get_agent_client().await.context("get client")?;
// update new timeout
if let Some(v) = $new_timeout {
timeout = v;
}
let resp = client.$name(new_ttrpc_ctx(timeout * MILLISECOND_TO_NANOSECOND), &r).await?;
Ok(resp.into())
})*
}
};
}
impl_agent!(
create_container | crate::CreateContainerRequest | crate::Empty | None,
start_container | crate::ContainerID | crate::Empty | None,
remove_container | crate::RemoveContainerRequest | crate::Empty | None,
exec_process | crate::ExecProcessRequest | crate::Empty | None,
signal_process | crate::SignalProcessRequest | crate::Empty | None,
wait_process | crate::WaitProcessRequest | crate::WaitProcessResponse | Some(0),
update_container | crate::UpdateContainerRequest | crate::Empty | None,
stats_container | crate::ContainerID | crate::StatsContainerResponse | None,
pause_container | crate::ContainerID | crate::Empty | None,
resume_container | crate::ContainerID | crate::Empty | None,
write_stdin | crate::WriteStreamRequest | crate::WriteStreamResponse | None,
read_stdout | crate::ReadStreamRequest | crate::ReadStreamResponse | None,
read_stderr | crate::ReadStreamRequest | crate::ReadStreamResponse | None,
close_stdin | crate::CloseStdinRequest | crate::Empty | None,
tty_win_resize | crate::TtyWinResizeRequest | crate::Empty | None,
update_interface | crate::UpdateInterfaceRequest | crate::Interface | None,
update_routes | crate::UpdateRoutesRequest | crate::Routes | None,
add_arp_neighbors | crate::AddArpNeighborRequest | crate::Empty | None,
list_interfaces | crate::Empty | crate::Interfaces | None,
list_routes | crate::Empty | crate::Routes | None,
create_sandbox | crate::CreateSandboxRequest | crate::Empty | None,
destroy_sandbox | crate::Empty | crate::Empty | None,
copy_file | crate::CopyFileRequest | crate::Empty | None,
get_oom_event | crate::Empty | crate::OomEventResponse | Some(0)
);

View File

@ -0,0 +1,123 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
mod agent;
mod trans;
use std::os::unix::io::{IntoRawFd, RawFd};
use anyhow::{Context, Result};
use kata_types::config::Agent as AgentConfig;
use protocols::{agent_ttrpc_async as agent_ttrpc, health_ttrpc_async as health_ttrpc};
use tokio::sync::Mutex;
use ttrpc::asynchronous::Client;
use crate::{log_forwarder::LogForwarder, sock};
// https://github.com/firecracker-microvm/firecracker/blob/master/docs/vsock.md
#[derive(Debug, Default)]
pub struct Vsock {
pub context_id: u64,
pub port: u32,
}
pub(crate) struct KataAgentInner {
/// TTRPC client
pub client: Option<Client>,
/// Client fd
pub client_fd: RawFd,
/// Unix domain socket address
pub socket_address: String,
/// Agent config
config: AgentConfig,
/// Log forwarder
log_forwarder: LogForwarder,
}
unsafe impl Send for KataAgent {}
unsafe impl Sync for KataAgent {}
pub struct KataAgent {
pub(crate) inner: Mutex<KataAgentInner>,
}
impl KataAgent {
pub fn new(config: AgentConfig) -> Self {
KataAgent {
inner: Mutex::new(KataAgentInner {
client: None,
client_fd: -1,
socket_address: "".to_string(),
config,
log_forwarder: LogForwarder::new(),
}),
}
}
pub async fn get_health_client(&self) -> Option<(health_ttrpc::HealthClient, i64, RawFd)> {
let inner = self.inner.lock().await;
inner.client.as_ref().map(|c| {
(
health_ttrpc::HealthClient::new(c.clone()),
inner.config.health_check_request_timeout_ms as i64,
inner.client_fd,
)
})
}
pub async fn get_agent_client(&self) -> Option<(agent_ttrpc::AgentServiceClient, i64, RawFd)> {
let inner = self.inner.lock().await;
inner.client.as_ref().map(|c| {
(
agent_ttrpc::AgentServiceClient::new(c.clone()),
inner.config.request_timeout_ms as i64,
inner.client_fd,
)
})
}
pub(crate) async fn connect_agent_server(&self) -> Result<()> {
let mut inner = self.inner.lock().await;
let config = sock::ConnectConfig::new(
inner.config.dial_timeout_ms as u64,
inner.config.reconnect_timeout_ms as u64,
);
let sock =
sock::new(&inner.socket_address, inner.config.server_port).context("new sock")?;
let stream = sock.connect(&config).await.context("connect")?;
let fd = stream.into_raw_fd();
info!(sl!(), "get stream raw fd {:?}", fd);
let c = Client::new(fd);
inner.client = Some(c);
inner.client_fd = fd;
Ok(())
}
pub(crate) async fn start_log_forwarder(&self) -> Result<()> {
let mut inner = self.inner.lock().await;
let config = sock::ConnectConfig::new(
inner.config.dial_timeout_ms as u64,
inner.config.reconnect_timeout_ms as u64,
);
let address = inner.socket_address.clone();
let port = inner.config.log_port;
inner
.log_forwarder
.start(&address, port, config)
.await
.context("start log forwarder")?;
Ok(())
}
pub(crate) async fn stop_log_forwarder(&self) {
let mut inner = self.inner.lock().await;
inner.log_forwarder.stop();
}
}

View File

@ -0,0 +1,794 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use std::convert::Into;
use protocols::{
agent::{self, OOMEvent},
empty, health, types,
};
use crate::{
types::{
ARPNeighbor, ARPNeighbors, AddArpNeighborRequest, AgentDetails, BlkioStats,
BlkioStatsEntry, CgroupStats, CheckRequest, CloseStdinRequest, ContainerID,
CopyFileRequest, CpuStats, CpuUsage, CreateContainerRequest, CreateSandboxRequest, Device,
Empty, ExecProcessRequest, GuestDetailsResponse, HealthCheckResponse, HugetlbStats,
IPAddress, IPFamily, Interface, Interfaces, KernelModule, MemHotplugByProbeRequest,
MemoryData, MemoryStats, NetworkStats, OnlineCPUMemRequest, PidsStats, ReadStreamRequest,
ReadStreamResponse, RemoveContainerRequest, ReseedRandomDevRequest, Route, Routes,
SetGuestDateTimeRequest, SignalProcessRequest, StatsContainerResponse, Storage, StringUser,
ThrottlingData, TtyWinResizeRequest, UpdateContainerRequest, UpdateInterfaceRequest,
UpdateRoutesRequest, VersionCheckResponse, WaitProcessRequest, WriteStreamRequest,
},
OomEventResponse, WaitProcessResponse, WriteStreamResponse,
};
fn from_vec<F: Into<T>, T: Sized>(from: Vec<F>) -> ::protobuf::RepeatedField<T> {
let mut to: Vec<T> = vec![];
for data in from {
to.push(data.into());
}
::protobuf::RepeatedField::from_vec(to)
}
fn into_vec<F: Sized + Clone, T: From<F>>(from: ::protobuf::RepeatedField<F>) -> Vec<T> {
let mut to: Vec<T> = vec![];
for data in from.to_vec() {
to.push(data.into());
}
to
}
fn from_option<F: Sized, T: From<F>>(from: Option<F>) -> ::protobuf::SingularPtrField<T> {
match from {
Some(f) => ::protobuf::SingularPtrField::from_option(Some(T::from(f))),
None => ::protobuf::SingularPtrField::none(),
}
}
fn into_option<F: Into<T>, T: Sized>(from: ::protobuf::SingularPtrField<F>) -> Option<T> {
from.into_option().map(|f| f.into())
}
fn into_hash_map<F: Into<T>, T>(
from: std::collections::HashMap<String, F>,
) -> std::collections::HashMap<String, T> {
let mut to: std::collections::HashMap<String, T> = Default::default();
for (key, value) in from {
to.insert(key, value.into());
}
to
}
impl From<empty::Empty> for Empty {
fn from(_: empty::Empty) -> Self {
Self {}
}
}
impl From<StringUser> for agent::StringUser {
fn from(from: StringUser) -> Self {
Self {
uid: from.uid,
gid: from.gid,
additionalGids: ::protobuf::RepeatedField::from_vec(from.additional_gids),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<Device> for agent::Device {
fn from(from: Device) -> Self {
Self {
id: from.id,
field_type: from.field_type,
vm_path: from.vm_path,
container_path: from.container_path,
options: from_vec(from.options),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<Storage> for agent::Storage {
fn from(from: Storage) -> Self {
Self {
driver: from.driver,
driver_options: from_vec(from.driver_options),
source: from.source,
fstype: from.fs_type,
options: from_vec(from.options),
mount_point: from.mount_point,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<KernelModule> for agent::KernelModule {
fn from(from: KernelModule) -> Self {
Self {
name: from.name,
parameters: from_vec(from.parameters),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<IPFamily> for types::IPFamily {
fn from(from: IPFamily) -> Self {
if from == IPFamily::V4 {
types::IPFamily::v4
} else {
types::IPFamily::v6
}
}
}
impl From<types::IPFamily> for IPFamily {
fn from(src: types::IPFamily) -> Self {
match src {
types::IPFamily::v4 => IPFamily::V4,
types::IPFamily::v6 => IPFamily::V6,
}
}
}
impl From<IPAddress> for types::IPAddress {
fn from(from: IPAddress) -> Self {
Self {
family: from.family.into(),
address: from.address,
mask: from.mask,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<types::IPAddress> for IPAddress {
fn from(src: types::IPAddress) -> Self {
Self {
family: src.family.into(),
address: "".to_string(),
mask: "".to_string(),
}
}
}
impl From<Interface> for types::Interface {
fn from(from: Interface) -> Self {
Self {
device: from.device,
name: from.name,
IPAddresses: from_vec(from.ip_addresses),
mtu: from.mtu,
hwAddr: from.hw_addr,
pciPath: from.pci_addr,
field_type: from.field_type,
raw_flags: from.raw_flags,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<types::Interface> for Interface {
fn from(src: types::Interface) -> Self {
Self {
device: src.device,
name: src.name,
ip_addresses: into_vec(src.IPAddresses),
mtu: src.mtu,
hw_addr: src.hwAddr,
pci_addr: src.pciPath,
field_type: src.field_type,
raw_flags: src.raw_flags,
}
}
}
impl From<agent::Interfaces> for Interfaces {
fn from(src: agent::Interfaces) -> Self {
Self {
interfaces: into_vec(src.Interfaces),
}
}
}
impl From<Route> for types::Route {
fn from(from: Route) -> Self {
Self {
dest: from.dest,
gateway: from.gateway,
device: from.device,
source: from.source,
scope: from.scope,
family: from.family.into(),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<types::Route> for Route {
fn from(src: types::Route) -> Self {
Self {
dest: src.dest,
gateway: src.gateway,
device: src.device,
source: src.source,
scope: src.scope,
family: src.family.into(),
}
}
}
impl From<Routes> for agent::Routes {
fn from(from: Routes) -> Self {
Self {
Routes: from_vec(from.routes),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<agent::Routes> for Routes {
fn from(src: agent::Routes) -> Self {
Self {
routes: into_vec(src.Routes),
}
}
}
impl From<CreateContainerRequest> for agent::CreateContainerRequest {
fn from(from: CreateContainerRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
string_user: from_option(from.string_user),
devices: from_vec(from.devices),
storages: from_vec(from.storages),
OCI: from_option(from.oci),
sandbox_pidns: from.sandbox_pidns,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<RemoveContainerRequest> for agent::RemoveContainerRequest {
fn from(from: RemoveContainerRequest) -> Self {
Self {
container_id: from.container_id,
timeout: from.timeout,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<ContainerID> for agent::StartContainerRequest {
fn from(from: ContainerID) -> Self {
Self {
container_id: from.container_id,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<ContainerID> for agent::StatsContainerRequest {
fn from(from: ContainerID) -> Self {
Self {
container_id: from.container_id,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<ContainerID> for agent::PauseContainerRequest {
fn from(from: ContainerID) -> Self {
Self {
container_id: from.container_id,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<ContainerID> for agent::ResumeContainerRequest {
fn from(from: ContainerID) -> Self {
Self {
container_id: from.container_id,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<SignalProcessRequest> for agent::SignalProcessRequest {
fn from(from: SignalProcessRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
signal: from.signal,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<WaitProcessRequest> for agent::WaitProcessRequest {
fn from(from: WaitProcessRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<UpdateContainerRequest> for agent::UpdateContainerRequest {
fn from(from: UpdateContainerRequest) -> Self {
Self {
container_id: from.container_id,
resources: from_option(Some(from.resources)),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<WriteStreamRequest> for agent::WriteStreamRequest {
fn from(from: WriteStreamRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
data: from.data,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<agent::WriteStreamResponse> for WriteStreamResponse {
fn from(from: agent::WriteStreamResponse) -> Self {
Self { length: from.len }
}
}
impl From<ExecProcessRequest> for agent::ExecProcessRequest {
fn from(from: ExecProcessRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
string_user: from_option(from.string_user),
process: from_option(from.process),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<agent::CpuUsage> for CpuUsage {
fn from(src: agent::CpuUsage) -> Self {
Self {
total_usage: src.total_usage,
percpu_usage: src.percpu_usage,
usage_in_kernelmode: src.usage_in_kernelmode,
usage_in_usermode: src.usage_in_usermode,
}
}
}
impl From<agent::ThrottlingData> for ThrottlingData {
fn from(src: agent::ThrottlingData) -> Self {
Self {
periods: src.periods,
throttled_periods: src.throttled_periods,
throttled_time: src.throttled_time,
}
}
}
impl From<agent::CpuStats> for CpuStats {
fn from(src: agent::CpuStats) -> Self {
Self {
cpu_usage: into_option(src.cpu_usage),
throttling_data: into_option(src.throttling_data),
}
}
}
impl From<agent::MemoryData> for MemoryData {
fn from(src: agent::MemoryData) -> Self {
Self {
usage: src.usage,
max_usage: src.max_usage,
failcnt: src.failcnt,
limit: src.limit,
}
}
}
impl From<agent::MemoryStats> for MemoryStats {
fn from(src: agent::MemoryStats) -> Self {
Self {
cache: src.cache,
usage: into_option(src.usage),
swap_usage: into_option(src.swap_usage),
kernel_usage: into_option(src.kernel_usage),
use_hierarchy: src.use_hierarchy,
stats: into_hash_map(src.stats),
}
}
}
impl From<agent::PidsStats> for PidsStats {
fn from(src: agent::PidsStats) -> Self {
Self {
current: src.current,
limit: src.limit,
}
}
}
impl From<agent::BlkioStatsEntry> for BlkioStatsEntry {
fn from(src: agent::BlkioStatsEntry) -> Self {
Self {
major: src.major,
minor: src.minor,
op: src.op,
value: src.value,
}
}
}
impl From<agent::BlkioStats> for BlkioStats {
fn from(src: agent::BlkioStats) -> Self {
Self {
io_service_bytes_recursive: into_vec(src.io_service_bytes_recursive),
io_serviced_recursive: into_vec(src.io_serviced_recursive),
io_queued_recursive: into_vec(src.io_queued_recursive),
io_service_time_recursive: into_vec(src.io_service_time_recursive),
io_wait_time_recursive: into_vec(src.io_wait_time_recursive),
io_merged_recursive: into_vec(src.io_merged_recursive),
io_time_recursive: into_vec(src.io_time_recursive),
sectors_recursive: into_vec(src.sectors_recursive),
}
}
}
impl From<agent::HugetlbStats> for HugetlbStats {
fn from(src: agent::HugetlbStats) -> Self {
Self {
usage: src.usage,
max_usage: src.max_usage,
failcnt: src.failcnt,
}
}
}
impl From<agent::CgroupStats> for CgroupStats {
fn from(src: agent::CgroupStats) -> Self {
Self {
cpu_stats: into_option(src.cpu_stats),
memory_stats: into_option(src.memory_stats),
pids_stats: into_option(src.pids_stats),
blkio_stats: into_option(src.blkio_stats),
hugetlb_stats: into_hash_map(src.hugetlb_stats),
}
}
}
impl From<agent::NetworkStats> for NetworkStats {
fn from(src: agent::NetworkStats) -> Self {
Self {
name: src.name,
rx_bytes: src.rx_bytes,
rx_packets: src.rx_packets,
rx_errors: src.rx_errors,
rx_dropped: src.rx_dropped,
tx_bytes: src.tx_bytes,
tx_packets: src.tx_packets,
tx_errors: src.tx_errors,
tx_dropped: src.tx_dropped,
}
}
}
// translate ttrpc::agent response to interface::agent response
impl From<agent::StatsContainerResponse> for StatsContainerResponse {
fn from(src: agent::StatsContainerResponse) -> Self {
Self {
cgroup_stats: into_option(src.cgroup_stats),
network_stats: into_vec(src.network_stats),
}
}
}
impl From<ReadStreamRequest> for agent::ReadStreamRequest {
fn from(from: ReadStreamRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
len: from.len,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<agent::ReadStreamResponse> for ReadStreamResponse {
fn from(from: agent::ReadStreamResponse) -> Self {
Self { data: from.data }
}
}
impl From<CloseStdinRequest> for agent::CloseStdinRequest {
fn from(from: CloseStdinRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<TtyWinResizeRequest> for agent::TtyWinResizeRequest {
fn from(from: TtyWinResizeRequest) -> Self {
Self {
container_id: from.container_id,
exec_id: from.exec_id,
row: from.row,
column: from.column,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<UpdateInterfaceRequest> for agent::UpdateInterfaceRequest {
fn from(from: UpdateInterfaceRequest) -> Self {
Self {
interface: from_option(from.interface),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<Empty> for agent::ListInterfacesRequest {
fn from(_: Empty) -> Self {
Self {
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<UpdateRoutesRequest> for agent::UpdateRoutesRequest {
fn from(from: UpdateRoutesRequest) -> Self {
Self {
routes: from_option(from.route),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<Empty> for agent::ListRoutesRequest {
fn from(_: Empty) -> Self {
Self {
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<ARPNeighbor> for types::ARPNeighbor {
fn from(from: ARPNeighbor) -> Self {
Self {
toIPAddress: from_option(from.to_ip_address),
device: from.device,
lladdr: from.ll_addr,
state: from.state,
flags: from.flags,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<ARPNeighbors> for agent::ARPNeighbors {
fn from(from: ARPNeighbors) -> Self {
Self {
ARPNeighbors: from_vec(from.neighbors),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<AddArpNeighborRequest> for agent::AddARPNeighborsRequest {
fn from(from: AddArpNeighborRequest) -> Self {
Self {
neighbors: from_option(from.neighbors),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<CreateSandboxRequest> for agent::CreateSandboxRequest {
fn from(from: CreateSandboxRequest) -> Self {
Self {
hostname: from.hostname,
dns: from_vec(from.dns),
storages: from_vec(from.storages),
sandbox_pidns: from.sandbox_pidns,
sandbox_id: from.sandbox_id,
guest_hook_path: from.guest_hook_path,
kernel_modules: from_vec(from.kernel_modules),
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<Empty> for agent::DestroySandboxRequest {
fn from(_: Empty) -> Self {
Self {
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<OnlineCPUMemRequest> for agent::OnlineCPUMemRequest {
fn from(from: OnlineCPUMemRequest) -> Self {
Self {
wait: from.wait,
nb_cpus: from.nb_cpus,
cpu_only: from.cpu_only,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<ReseedRandomDevRequest> for agent::ReseedRandomDevRequest {
fn from(from: ReseedRandomDevRequest) -> Self {
Self {
data: from.data,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<MemHotplugByProbeRequest> for agent::MemHotplugByProbeRequest {
fn from(from: MemHotplugByProbeRequest) -> Self {
Self {
memHotplugProbeAddr: from.mem_hotplug_probe_addr,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<SetGuestDateTimeRequest> for agent::SetGuestDateTimeRequest {
fn from(from: SetGuestDateTimeRequest) -> Self {
Self {
Sec: from.sec,
Usec: from.usec,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<agent::AgentDetails> for AgentDetails {
fn from(src: agent::AgentDetails) -> Self {
Self {
version: src.version,
init_daemon: src.init_daemon,
device_handlers: into_vec(src.device_handlers),
storage_handlers: into_vec(src.storage_handlers),
supports_seccomp: src.supports_seccomp,
}
}
}
impl From<agent::GuestDetailsResponse> for GuestDetailsResponse {
fn from(src: agent::GuestDetailsResponse) -> Self {
Self {
mem_block_size_bytes: src.mem_block_size_bytes,
agent_details: into_option(src.agent_details),
support_mem_hotplug_probe: src.support_mem_hotplug_probe,
}
}
}
impl From<CopyFileRequest> for agent::CopyFileRequest {
fn from(from: CopyFileRequest) -> Self {
Self {
path: from.path,
file_size: from.file_size,
file_mode: from.file_mode,
dir_mode: from.dir_mode,
uid: from.uid,
gid: from.gid,
offset: from.offset,
data: from.data,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<agent::WaitProcessResponse> for WaitProcessResponse {
fn from(from: agent::WaitProcessResponse) -> Self {
Self {
status: from.status,
}
}
}
impl From<Empty> for agent::GetOOMEventRequest {
fn from(_: Empty) -> Self {
Self {
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<CheckRequest> for health::CheckRequest {
fn from(from: CheckRequest) -> Self {
Self {
service: from.service,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
impl From<health::HealthCheckResponse> for HealthCheckResponse {
fn from(from: health::HealthCheckResponse) -> Self {
Self {
status: from.status as u32,
}
}
}
impl From<health::VersionCheckResponse> for VersionCheckResponse {
fn from(from: health::VersionCheckResponse) -> Self {
Self {
grpc_version: from.grpc_version,
agent_version: from.agent_version,
}
}
}
impl From<agent::OOMEvent> for OomEventResponse {
fn from(from: OOMEvent) -> Self {
Self {
container_id: from.container_id,
}
}
}

View File

@ -0,0 +1,84 @@
// 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" => "agent"))
};
}
pub mod kata;
mod log_forwarder;
mod sock;
mod types;
pub use types::{
ARPNeighbor, ARPNeighbors, AddArpNeighborRequest, BlkioStatsEntry, CheckRequest,
CloseStdinRequest, ContainerID, CopyFileRequest, CreateContainerRequest, CreateSandboxRequest,
Empty, ExecProcessRequest, GetGuestDetailsRequest, GuestDetailsResponse, HealthCheckResponse,
IPAddress, IPFamily, Interface, Interfaces, ListProcessesRequest, MemHotplugByProbeRequest,
OnlineCPUMemRequest, OomEventResponse, ReadStreamRequest, ReadStreamResponse,
RemoveContainerRequest, ReseedRandomDevRequest, Route, Routes, SetGuestDateTimeRequest,
SignalProcessRequest, StatsContainerResponse, Storage, TtyWinResizeRequest,
UpdateContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest, VersionCheckResponse,
WaitProcessRequest, WaitProcessResponse, WriteStreamRequest, WriteStreamResponse,
};
use anyhow::Result;
use async_trait::async_trait;
#[async_trait]
pub trait AgentManager: Send + Sync {
async fn set_socket_address(&self, address: &str) -> Result<()>;
async fn start(&self) -> Result<()>;
async fn stop(&self);
}
#[async_trait]
pub trait HealthService: Send + Sync {
async fn check(&self, req: CheckRequest) -> Result<HealthCheckResponse>;
async fn version(&self, req: CheckRequest) -> Result<VersionCheckResponse>;
}
#[async_trait]
pub trait Agent: AgentManager + HealthService + Send + Sync {
// sandbox
async fn create_sandbox(&self, req: CreateSandboxRequest) -> Result<Empty>;
async fn destroy_sandbox(&self, req: Empty) -> Result<Empty>;
// network
async fn add_arp_neighbors(&self, req: AddArpNeighborRequest) -> Result<Empty>;
async fn list_interfaces(&self, req: Empty) -> Result<Interfaces>;
async fn list_routes(&self, req: Empty) -> Result<Routes>;
async fn update_interface(&self, req: UpdateInterfaceRequest) -> Result<Interface>;
async fn update_routes(&self, req: UpdateRoutesRequest) -> Result<Routes>;
// container
async fn create_container(&self, req: CreateContainerRequest) -> Result<Empty>;
async fn pause_container(&self, req: ContainerID) -> Result<Empty>;
async fn remove_container(&self, req: RemoveContainerRequest) -> Result<Empty>;
async fn resume_container(&self, req: ContainerID) -> Result<Empty>;
async fn start_container(&self, req: ContainerID) -> Result<Empty>;
async fn stats_container(&self, req: ContainerID) -> Result<StatsContainerResponse>;
async fn update_container(&self, req: UpdateContainerRequest) -> Result<Empty>;
// process
async fn exec_process(&self, req: ExecProcessRequest) -> Result<Empty>;
async fn signal_process(&self, req: SignalProcessRequest) -> Result<Empty>;
async fn wait_process(&self, req: WaitProcessRequest) -> Result<WaitProcessResponse>;
// io and tty
async fn close_stdin(&self, req: CloseStdinRequest) -> Result<Empty>;
async fn read_stderr(&self, req: ReadStreamRequest) -> Result<ReadStreamResponse>;
async fn read_stdout(&self, req: ReadStreamRequest) -> Result<ReadStreamResponse>;
async fn tty_win_resize(&self, req: TtyWinResizeRequest) -> Result<Empty>;
async fn write_stdin(&self, req: WriteStreamRequest) -> Result<WriteStreamResponse>;
// utils
async fn copy_file(&self, req: CopyFileRequest) -> Result<Empty>;
async fn get_oom_event(&self, req: Empty) -> Result<OomEventResponse>;
}

View File

@ -0,0 +1,159 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::Result;
use tokio::io::{AsyncBufReadExt, BufReader};
use crate::sock;
// https://github.com/slog-rs/slog/blob/master/src/lib.rs#L2082
const LOG_LEVEL_TRACE: &str = "TRCE";
const LOG_LEVEL_DEBUG: &str = "DEBG";
const LOG_LEVEL_INFO: &str = "INFO";
const LOG_LEVEL_WARNING: &str = "WARN";
const LOG_LEVEL_ERROR: &str = "ERRO";
const LOG_LEVEL_CRITICAL: &str = "CRIT";
pub(crate) struct LogForwarder {
task_handler: Option<tokio::task::JoinHandle<()>>,
}
impl LogForwarder {
pub(crate) fn new() -> Self {
Self { task_handler: None }
}
pub(crate) fn stop(&mut self) {
let task_handler = self.task_handler.take();
if let Some(handler) = task_handler {
handler.abort();
info!(sl!(), "abort log forwarder thread");
}
}
// start connect kata-agent log vsock and copy data to hypervisor's log stream
pub(crate) async fn start(
&mut self,
address: &str,
port: u32,
config: sock::ConnectConfig,
) -> Result<()> {
let logger = sl!().clone();
let address = address.to_string();
let task_handler = tokio::spawn(async move {
loop {
info!(logger, "try to connect to get agent log");
let sock = match sock::new(&address, port) {
Ok(sock) => sock,
Err(err) => {
error!(
sl!(),
"failed to new sock for address {:?} port {} error {:?}",
address,
port,
err
);
return;
}
};
match sock.connect(&config).await {
Ok(stream) => {
let stream = BufReader::new(stream);
let mut lines = stream.lines();
while let Ok(line) = lines.next_line().await {
if let Some(l) = line {
match parse_agent_log_level(&l) {
LOG_LEVEL_TRACE => trace!(sl!(), "{}", l),
LOG_LEVEL_DEBUG => debug!(sl!(), "{}", l),
LOG_LEVEL_WARNING => warn!(sl!(), "{}", l),
LOG_LEVEL_ERROR => error!(sl!(), "{}", l),
LOG_LEVEL_CRITICAL => crit!(sl!(), "{}", l),
_ => info!(sl!(), "{}", l),
}
}
}
}
Err(err) => {
warn!(logger, "connect agent vsock failed: {:?}", err);
}
}
}
});
self.task_handler = Some(task_handler);
Ok(())
}
}
pub fn parse_agent_log_level(s: &str) -> &str {
let v: serde_json::Result<serde_json::Value> = serde_json::from_str(s);
match v {
Err(_err) => LOG_LEVEL_INFO,
Ok(val) => {
match &val["level"] {
serde_json::Value::String(s) => match s.as_str() {
LOG_LEVEL_TRACE => LOG_LEVEL_TRACE,
LOG_LEVEL_DEBUG => LOG_LEVEL_DEBUG,
LOG_LEVEL_WARNING => LOG_LEVEL_WARNING,
LOG_LEVEL_ERROR => LOG_LEVEL_ERROR,
LOG_LEVEL_CRITICAL => LOG_LEVEL_CRITICAL,
_ => LOG_LEVEL_INFO, // info or other values will return info,
},
_ => LOG_LEVEL_INFO, // info or other values will return info,
}
}
}
}
#[cfg(test)]
mod tests {
use super::parse_agent_log_level;
#[test]
fn test_parse_agent_log_level() {
let cases = vec![
// normal cases
(
r#"{"msg":"child exited unexpectedly","level":"TRCE"}"#,
super::LOG_LEVEL_TRACE,
),
(
r#"{"msg":"child exited unexpectedly","level":"DEBG"}"#,
super::LOG_LEVEL_DEBUG,
),
(
r#"{"msg":"child exited unexpectedly","level":"INFO"}"#,
super::LOG_LEVEL_INFO,
),
(
r#"{"msg":"child exited unexpectedly","level":"WARN"}"#,
super::LOG_LEVEL_WARNING,
),
(
r#"{"msg":"child exited unexpectedly","level":"ERRO"}"#,
super::LOG_LEVEL_ERROR,
),
(
r#"{"msg":"child exited unexpectedly","level":"CRIT"}"#,
super::LOG_LEVEL_CRITICAL,
),
(
r#"{"msg":"child exited unexpectedly","level":"abc"}"#,
super::LOG_LEVEL_INFO,
),
// exception cases
(r#"{"not a valid json struct"}"#, super::LOG_LEVEL_INFO),
("not a valid json struct", super::LOG_LEVEL_INFO),
];
for case in cases.iter() {
let s = case.0;
let result = parse_agent_log_level(s);
let excepted = case.1;
assert_eq!(result, excepted);
}
}
}

View File

@ -0,0 +1,81 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use std::os::unix::prelude::AsRawFd;
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
net::UnixStream,
};
use super::{ConnectConfig, Sock, Stream};
unsafe impl Send for HybridVsock {}
unsafe impl Sync for HybridVsock {}
#[derive(Debug, PartialEq)]
pub struct HybridVsock {
uds: String,
port: u32,
}
impl HybridVsock {
pub fn new(uds: &str, port: u32) -> Self {
Self {
uds: uds.to_string(),
port,
}
}
}
#[async_trait]
impl Sock for HybridVsock {
async fn connect(&self, config: &ConnectConfig) -> Result<Stream> {
let retry_times = config.reconnect_timeout_ms / config.dial_timeout_ms;
for i in 0..retry_times {
match connect_helper(&self.uds, self.port).await {
Ok(stream) => {
info!(
sl!(),
"connect success on {} current client fd {}",
i,
stream.as_raw_fd()
);
return Ok(Stream::Unix(stream));
}
Err(err) => {
debug!(sl!(), "connect on {} err : {:?}", i, err);
tokio::time::sleep(std::time::Duration::from_millis(config.dial_timeout_ms))
.await;
continue;
}
}
}
Err(anyhow!("cannot connect to agent ttrpc server"))
}
}
async fn connect_helper(uds: &str, port: u32) -> Result<UnixStream> {
info!(sl!(), "connect uds {:?} port {}", &uds, port);
let mut stream = UnixStream::connect(&uds).await.context("connect")?;
stream
.write_all(format!("connect {}\n", port).as_bytes())
.await
.context("write all")?;
let mut reads = BufReader::new(&mut stream);
let mut response = String::new();
reads.read_line(&mut response).await.context("read line")?;
//info!(sl!(), "get socket resp: {}", response);
if !response.contains("OK") {
return Err(anyhow!(
"handshake error: malformed response code: {:?}",
response
));
}
Ok(stream)
}

View File

@ -0,0 +1,159 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
mod hybrid_vsock;
pub use hybrid_vsock::HybridVsock;
mod vsock;
pub use vsock::Vsock;
use std::{
pin::Pin,
task::{Context as TaskContext, Poll},
{
os::unix::{io::IntoRawFd, prelude::RawFd},
sync::Arc,
},
};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use tokio::{
io::{AsyncRead, ReadBuf},
net::UnixStream,
};
use url::Url;
const VSOCK_SCHEME: &str = "vsock";
const HYBRID_VSOCK_SCHEME: &str = "hvsock";
/// Socket stream
pub enum Stream {
// hvsock://<path>:<port>. Firecracker/Dragonball implements the virtio-vsock device
// model, and mediates communication between AF_UNIX sockets (on the host end)
// and AF_VSOCK sockets (on the guest end).
Unix(UnixStream),
// TODO: support vsock
// vsock://<cid>:<port>
}
impl Stream {
fn poll_read_priv(
&mut self,
cx: &mut TaskContext<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
// Safety: `UnixStream::read` correctly handles reads into uninitialized memory
match self {
Stream::Unix(stream) => Pin::new(stream).poll_read(cx, buf),
}
}
}
impl IntoRawFd for Stream {
fn into_raw_fd(self) -> RawFd {
match self {
Stream::Unix(stream) => match stream.into_std() {
Ok(stream) => stream.into_raw_fd(),
Err(err) => {
error!(sl!(), "failed to into std unix stream {:?}", err);
-1
}
},
}
}
}
impl AsyncRead for Stream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut TaskContext<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
// we know this is safe because doesn't moved
let me = unsafe { self.get_unchecked_mut() };
me.poll_read_priv(cx, buf)
}
}
/// Connect config
pub struct ConnectConfig {
dial_timeout_ms: u64,
reconnect_timeout_ms: u64,
}
impl ConnectConfig {
pub fn new(dial_timeout_ms: u64, reconnect_timeout_ms: u64) -> Self {
Self {
dial_timeout_ms,
reconnect_timeout_ms,
}
}
}
#[derive(Debug, PartialEq)]
enum SockType {
Vsock(Vsock),
HybridVsock(HybridVsock),
}
#[async_trait]
pub trait Sock: Send + Sync {
async fn connect(&self, config: &ConnectConfig) -> Result<Stream>;
}
// Supported sock address formats are:
// - vsock://<cid>:<port>
// - hvsock://<path>:<port>. Firecracker implements the virtio-vsock device
// model, and mediates communication between AF_UNIX sockets (on the host end)
// and AF_VSOCK sockets (on the guest end).
pub fn new(address: &str, port: u32) -> Result<Arc<dyn Sock>> {
match parse(address, port).context("parse url")? {
SockType::Vsock(sock) => Ok(Arc::new(sock)),
SockType::HybridVsock(sock) => Ok(Arc::new(sock)),
}
}
fn parse(address: &str, port: u32) -> Result<SockType> {
let url = Url::parse(address).context("parse url")?;
match url.scheme() {
VSOCK_SCHEME => {
let cid = url
.host_str()
.unwrap_or_default()
.parse::<u32>()
.context("parse cid")?;
Ok(SockType::Vsock(Vsock::new(cid, port)))
}
HYBRID_VSOCK_SCHEME => {
let path: Vec<&str> = url.path().split(':').collect();
if path.len() != 1 {
return Err(anyhow!("invalid path {:?}", path));
}
let uds = path[0];
Ok(SockType::HybridVsock(HybridVsock::new(uds, port)))
}
_ => Err(anyhow!("Unsupported scheme")),
}
}
#[cfg(test)]
mod test {
use super::{hybrid_vsock::HybridVsock, parse, vsock::Vsock, SockType};
#[test]
fn test_parse_url() {
// check vsock
let vsock = parse("vsock://123", 456).unwrap();
assert_eq!(vsock, SockType::Vsock(Vsock::new(123, 456)));
// check hybrid vsock
let hvsock = parse("hvsock:///tmp/test.hvsock", 456).unwrap();
assert_eq!(
hvsock,
SockType::HybridVsock(HybridVsock::new("/tmp/test.hvsock", 456))
);
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::Result;
use async_trait::async_trait;
use super::{ConnectConfig, Sock, Stream};
unsafe impl Send for Vsock {}
unsafe impl Sync for Vsock {}
#[derive(Debug, PartialEq)]
pub struct Vsock {
cid: u32,
port: u32,
}
impl Vsock {
pub fn new(cid: u32, port: u32) -> Self {
Self { cid, port }
}
}
#[async_trait]
impl Sock for Vsock {
async fn connect(&self, _config: &ConnectConfig) -> Result<Stream> {
todo!()
}
}

View File

@ -0,0 +1,454 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use serde::Deserialize;
#[derive(PartialEq, Clone, Default)]
pub struct Empty {}
impl Empty {
pub fn new() -> Self {
Self::default()
}
}
#[derive(PartialEq, Clone, Default)]
pub struct StringUser {
pub uid: String,
pub gid: String,
pub additional_gids: Vec<String>,
}
#[derive(PartialEq, Clone, Default)]
pub struct Device {
pub id: String,
pub field_type: String,
pub vm_path: String,
pub container_path: String,
pub options: Vec<String>,
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Storage {
pub driver: String,
pub driver_options: Vec<String>,
pub source: String,
pub fs_type: String,
pub options: Vec<String>,
pub mount_point: String,
}
#[derive(Deserialize, Clone, PartialEq, Eq, Debug, Hash)]
pub enum IPFamily {
V4 = 0,
V6 = 1,
}
impl ::std::default::Default for IPFamily {
fn default() -> Self {
IPFamily::V4
}
}
#[derive(Deserialize, Debug, PartialEq, Clone, Default)]
pub struct IPAddress {
pub family: IPFamily,
pub address: String,
pub mask: String,
}
#[derive(Deserialize, Debug, PartialEq, Clone, Default)]
pub struct Interface {
pub device: String,
pub name: String,
pub ip_addresses: Vec<IPAddress>,
pub mtu: u64,
pub hw_addr: String,
#[serde(default)]
pub pci_addr: String,
#[serde(default)]
pub field_type: String,
#[serde(default)]
pub raw_flags: u32,
}
#[derive(PartialEq, Clone, Default)]
pub struct Interfaces {
pub interfaces: Vec<Interface>,
}
#[derive(Deserialize, Debug, PartialEq, Clone, Default)]
pub struct Route {
pub dest: String,
pub gateway: String,
pub device: String,
pub source: String,
pub scope: u32,
pub family: IPFamily,
}
#[derive(Deserialize, Debug, PartialEq, Clone, Default)]
pub struct Routes {
pub routes: Vec<Route>,
}
#[derive(PartialEq, Clone, Default)]
pub struct CreateContainerRequest {
pub container_id: String,
pub exec_id: String,
pub string_user: Option<StringUser>,
pub devices: Vec<Device>,
pub storages: Vec<Storage>,
pub oci: Option<oci::Spec>,
pub guest_hooks: Option<oci::Hooks>,
pub sandbox_pidns: bool,
pub rootfs_mounts: Vec<oci::Mount>,
}
#[derive(PartialEq, Clone, Default)]
pub struct ContainerID {
pub container_id: String,
}
impl ContainerID {
pub fn new(id: &str) -> Self {
Self {
container_id: id.to_string(),
}
}
}
#[derive(PartialEq, Clone, Debug, Default)]
pub struct RemoveContainerRequest {
pub container_id: String,
pub timeout: u32,
}
impl RemoveContainerRequest {
pub fn new(id: &str, timeout: u32) -> Self {
Self {
container_id: id.to_string(),
timeout,
}
}
}
#[derive(PartialEq, Clone, Default)]
pub struct SignalProcessRequest {
pub container_id: String,
pub exec_id: String,
pub signal: u32,
}
#[derive(PartialEq, Clone, Default)]
pub struct WaitProcessRequest {
pub container_id: String,
pub exec_id: String,
}
#[derive(PartialEq, Clone, Default)]
pub struct ListProcessesRequest {
pub container_id: String,
pub format: String,
pub args: Vec<String>,
}
#[derive(PartialEq, Clone, Default)]
pub struct UpdateContainerRequest {
pub container_id: String,
pub resources: oci::LinuxResources,
pub mounts: Vec<oci::Mount>,
}
#[derive(PartialEq, Clone, Default)]
pub struct WriteStreamRequest {
pub container_id: String,
pub exec_id: String,
pub data: Vec<u8>,
}
#[derive(PartialEq, Clone, Default)]
pub struct WriteStreamResponse {
pub length: u32,
}
#[derive(PartialEq, Clone, Default)]
pub struct ExecProcessRequest {
pub container_id: String,
pub exec_id: String,
pub string_user: Option<StringUser>,
pub process: Option<oci::Process>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct CpuUsage {
pub total_usage: u64,
pub percpu_usage: ::std::vec::Vec<u64>,
pub usage_in_kernelmode: u64,
pub usage_in_usermode: u64,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct ThrottlingData {
pub periods: u64,
pub throttled_periods: u64,
pub throttled_time: u64,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct LoadData {
pub one: String,
pub five: String,
pub fifteen: String,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct CpuStats {
pub cpu_usage: Option<CpuUsage>,
pub throttling_data: Option<ThrottlingData>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct MemoryData {
pub usage: u64,
pub max_usage: u64,
pub failcnt: u64,
pub limit: u64,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct MemoryStats {
pub cache: u64,
pub usage: Option<MemoryData>,
pub swap_usage: Option<MemoryData>,
pub kernel_usage: Option<MemoryData>,
pub use_hierarchy: bool,
pub stats: ::std::collections::HashMap<String, u64>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct PidsStats {
pub current: u64,
pub limit: u64,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct BlkioStatsEntry {
pub major: u64,
pub minor: u64,
pub op: String,
pub value: u64,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct BlkioStats {
pub io_service_bytes_recursive: Vec<BlkioStatsEntry>,
pub io_serviced_recursive: Vec<BlkioStatsEntry>,
pub io_queued_recursive: Vec<BlkioStatsEntry>,
pub io_service_time_recursive: Vec<BlkioStatsEntry>,
pub io_wait_time_recursive: Vec<BlkioStatsEntry>,
pub io_merged_recursive: Vec<BlkioStatsEntry>,
pub io_time_recursive: Vec<BlkioStatsEntry>,
pub sectors_recursive: Vec<BlkioStatsEntry>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct HugetlbStats {
pub usage: u64,
pub max_usage: u64,
pub failcnt: u64,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct CgroupStats {
pub cpu_stats: Option<CpuStats>,
pub memory_stats: Option<MemoryStats>,
pub pids_stats: Option<PidsStats>,
pub blkio_stats: Option<BlkioStats>,
pub hugetlb_stats: ::std::collections::HashMap<String, HugetlbStats>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct NetworkStats {
pub name: String,
pub rx_bytes: u64,
pub rx_packets: u64,
pub rx_errors: u64,
pub rx_dropped: u64,
pub tx_bytes: u64,
pub tx_packets: u64,
pub tx_errors: u64,
pub tx_dropped: u64,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct StatsContainerResponse {
pub cgroup_stats: Option<CgroupStats>,
pub network_stats: Vec<NetworkStats>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct WaitProcessResponse {
pub status: i32,
}
#[derive(PartialEq, Clone, Default)]
pub struct ReadStreamRequest {
pub container_id: String,
pub exec_id: String,
pub len: u32,
}
#[derive(PartialEq, Clone, Default)]
pub struct ReadStreamResponse {
pub data: Vec<u8>,
}
#[derive(PartialEq, Clone, Default)]
pub struct CloseStdinRequest {
pub container_id: String,
pub exec_id: String,
}
#[derive(PartialEq, Clone, Default)]
pub struct TtyWinResizeRequest {
pub container_id: String,
pub exec_id: String,
pub row: u32,
pub column: u32,
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct UpdateInterfaceRequest {
pub interface: Option<Interface>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct UpdateRoutesRequest {
pub route: Option<Routes>,
}
#[derive(Deserialize, PartialEq, Clone, Default, Debug)]
pub struct ARPNeighbor {
pub to_ip_address: Option<IPAddress>,
pub device: String,
pub ll_addr: String,
pub state: i32,
pub flags: i32,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct ARPNeighbors {
pub neighbors: Vec<ARPNeighbor>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct AddArpNeighborRequest {
pub neighbors: Option<ARPNeighbors>,
}
#[derive(PartialEq, Clone, Default)]
pub struct KernelModule {
pub name: String,
pub parameters: Vec<String>,
}
#[derive(PartialEq, Clone, Default)]
pub struct CreateSandboxRequest {
pub hostname: String,
pub dns: Vec<String>,
pub storages: Vec<Storage>,
pub sandbox_pidns: bool,
pub sandbox_id: String,
pub guest_hook_path: String,
pub kernel_modules: Vec<KernelModule>,
}
#[derive(PartialEq, Clone, Default)]
pub struct OnlineCPUMemRequest {
pub wait: bool,
pub nb_cpus: u32,
pub cpu_only: bool,
}
#[derive(PartialEq, Clone, Default)]
pub struct ReseedRandomDevRequest {
pub data: ::std::vec::Vec<u8>,
}
#[derive(PartialEq, Clone, Default)]
pub struct GetGuestDetailsRequest {
pub mem_block_size: bool,
pub mem_hotplug_probe: bool,
}
#[derive(PartialEq, Clone, Default)]
pub struct MemHotplugByProbeRequest {
pub mem_hotplug_probe_addr: ::std::vec::Vec<u64>,
}
#[derive(PartialEq, Clone, Default)]
pub struct SetGuestDateTimeRequest {
pub sec: i64,
pub usec: i64,
}
#[derive(PartialEq, Clone, Default)]
pub struct AgentDetails {
pub version: String,
pub init_daemon: bool,
pub device_handlers: Vec<String>,
pub storage_handlers: Vec<std::string::String>,
pub supports_seccomp: bool,
}
#[derive(PartialEq, Clone, Default)]
pub struct GuestDetailsResponse {
pub mem_block_size_bytes: u64,
pub agent_details: Option<AgentDetails>,
pub support_mem_hotplug_probe: bool,
}
#[derive(PartialEq, Clone, Default)]
pub struct CopyFileRequest {
pub path: String,
pub file_size: i64,
pub file_mode: u32,
pub dir_mode: u32,
pub uid: i32,
pub gid: i32,
pub offset: i64,
pub data: ::std::vec::Vec<u8>,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct CheckRequest {
pub service: String,
}
impl CheckRequest {
pub fn new(service: &str) -> Self {
Self {
service: service.to_string(),
}
}
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct HealthCheckResponse {
pub status: u32,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct VersionCheckResponse {
pub grpc_version: String,
pub agent_version: String,
}
#[derive(PartialEq, Clone, Default, Debug)]
pub struct OomEventResponse {
pub container_id: String,
}