From a116a1909a60ab8e6b372f896ac1edc48208da9d Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Mon, 18 Mar 2024 15:17:28 +0100 Subject: [PATCH] Add streaming server Signed-off-by: Sascha Grunert --- Cargo.lock | 285 ++++++- conmon-rs/common/proto/conmon.capnp | 18 + conmon-rs/server/Cargo.toml | 2 + conmon-rs/server/src/config.rs | 4 +- conmon-rs/server/src/container_io.rs | 27 + conmon-rs/server/src/lib.rs | 1 + conmon-rs/server/src/rpc.rs | 42 + conmon-rs/server/src/server.rs | 30 +- conmon-rs/server/src/streaming_server.rs | 387 ++++++++++ internal/proto/conmon.capnp.go | 931 +++++++++++++++++------ pkg/client/client.go | 92 +++ 11 files changed, 1576 insertions(+), 243 deletions(-) create mode 100644 conmon-rs/server/src/streaming_server.rs diff --git a/Cargo.lock b/Cargo.lock index 31d068ea86..f6cac4e411 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,13 +136,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", "itoa", "matchit", "memchr", @@ -157,6 +157,43 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +dependencies = [ + "async-trait", + "axum-core 0.4.3", + "base64", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.2.0", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "axum-core" version = "0.3.4" @@ -166,14 +203,35 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "mime", "rustversion", "tower-layer", "tower-service", ] +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -222,6 +280,12 @@ version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -365,6 +429,7 @@ name = "conmonrs" version = "0.6.1" dependencies = [ "anyhow", + "axum 0.7.4", "capnp", "capnp-rpc", "clap", @@ -400,6 +465,7 @@ dependencies = [ "tokio-eventfd", "tokio-seqpacket", "tokio-util", + "tower-http", "tracing", "tracing-opentelemetry", "tracing-subscriber", @@ -500,6 +566,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + [[package]] name = "deranged" version = "0.3.11" @@ -793,7 +865,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", + "indexmap 2.0.1", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.1.0", "indexmap 2.0.1", "slab", "tokio", @@ -845,6 +936,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -852,7 +954,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -878,9 +1003,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.25", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -892,18 +1017,54 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.3", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + [[package]] name = "hyper-timeout" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.28", "pin-project-lite", "tokio", "tokio-io-timeout", ] +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.2.0", + "pin-project-lite", + "socket2", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1378,7 +1539,7 @@ checksum = "1a016b8d9495c639af2145ac22387dcb88e44118e45320d9238fbf4e7889abcb" dependencies = [ "async-trait", "futures-core", - "http", + "http 0.2.12", "opentelemetry", "opentelemetry-proto", "opentelemetry-semantic-conventions", @@ -1789,6 +1950,39 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -2106,6 +2300,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.10" @@ -2129,13 +2335,13 @@ checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64", "bytes", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.25", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", "hyper-timeout", "percent-encoding", "pin-project", @@ -2168,6 +2374,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags 2.4.1", + "bytes", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.2" @@ -2186,6 +2409,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2261,6 +2485,25 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typenum" version = "1.17.0" @@ -2355,6 +2598,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/conmon-rs/common/proto/conmon.capnp b/conmon-rs/common/proto/conmon.capnp index a5b3ded083..30ebc56c3d 100644 --- a/conmon-rs/common/proto/conmon.capnp +++ b/conmon-rs/common/proto/conmon.capnp @@ -194,4 +194,22 @@ interface Conmon { key @0 :Text; value @1 :Text; } + + ############################################### + # ServeExecContainer + struct ServeExecContainerRequest { + metadata @0 :Metadata; # Standard metadata to carry. + id @1 :Text; + cmd @2 :List(Text); + tty @3 :Bool; + stdin @4 :Bool; + stdout @5 :Bool; + stderr @6 :Bool; + } + + struct ServeExecContainerResponse { + url @0 :Text; + } + + serveExecContainer @8 (request: ServeExecContainerRequest) -> (response: ServeExecContainerResponse); } diff --git a/conmon-rs/server/Cargo.toml b/conmon-rs/server/Cargo.toml index 960f0aafe1..27d2b2af6e 100644 --- a/conmon-rs/server/Cargo.toml +++ b/conmon-rs/server/Cargo.toml @@ -9,6 +9,7 @@ path = "src/main.rs" [dependencies] anyhow = "1.0.81" +axum = { version = "0.7.4", features = ["ws"]} capnp = "0.19.2" capnp-rpc = "0.19.0" clap = { version = "4.3.8", features = ["color", "cargo", "deprecated", "derive", "deprecated", "env", "string", "unicode", "wrap_help"] } @@ -41,6 +42,7 @@ tokio = { version = "1.36.0", features = ["fs", "io-std", "io-util", "macros", " tokio-eventfd = "0.2.1" tokio-seqpacket = "0.7.1" tokio-util = { version = "0.7.10", features = ["compat"] } +tower-http = { version = "0.5.2", features = ["trace"] } tracing = "0.1.40" tracing-opentelemetry = "0.23.0" tracing-subscriber = "0.3.18" diff --git a/conmon-rs/server/src/config.rs b/conmon-rs/server/src/config.rs index 5165ebf0cb..2e41b4f09e 100644 --- a/conmon-rs/server/src/config.rs +++ b/conmon-rs/server/src/config.rs @@ -12,7 +12,9 @@ macro_rules! prefix { }; } -#[derive(CopyGetters, Debug, Deserialize, Eq, Getters, Parser, PartialEq, Serialize, Setters)] +#[derive( + Clone, CopyGetters, Debug, Deserialize, Eq, Getters, Parser, PartialEq, Serialize, Setters, +)] #[serde(rename_all = "kebab-case")] #[command( after_help("More info at: https://github.com/containers/conmon-rs"), diff --git a/conmon-rs/server/src/container_io.rs b/conmon-rs/server/src/container_io.rs index 19c555ad1e..6e3e3267ac 100644 --- a/conmon-rs/server/src/container_io.rs +++ b/conmon-rs/server/src/container_io.rs @@ -59,6 +59,11 @@ impl SharedContainerIO { pub async fn attach(&self) -> SharedContainerAttach { self.0.read().await.attach().clone() } + + /// Retrieve the underlying ContainerIO instance. + pub fn container_io(&mut self) -> Arc> { + self.0.clone() + } } #[derive(Debug, Getters, MutGetters)] @@ -155,6 +160,28 @@ impl ContainerIO { Ok(path) } + pub fn channels( + &mut self, + ) -> Result<( + &mut UnboundedReceiver, + Option<&mut UnboundedReceiver>, + )> { + match self.typ_mut() { + ContainerIOType::Terminal(t) => { + if let Some(message_rx) = t.message_rx_mut() { + Ok((message_rx, None)) + } else { + bail!("read_all_with_timeout called before message_rx was registered"); + } + } + ContainerIOType::Streams(s) => { + let stdout_rx = &mut s.message_rx_stdout; + let stderr_rx = &mut s.message_rx_stderr; + Ok((stdout_rx, Some(stderr_rx))) + } + } + } + pub async fn read_all_with_timeout( &mut self, time_to_timeout: Option, diff --git a/conmon-rs/server/src/lib.rs b/conmon-rs/server/src/lib.rs index c47ef04cc2..8d2a4e7543 100644 --- a/conmon-rs/server/src/lib.rs +++ b/conmon-rs/server/src/lib.rs @@ -24,6 +24,7 @@ mod oom_watcher; mod pause; mod rpc; mod server; +mod streaming_server; mod streams; mod telemetry; mod terminal; diff --git a/conmon-rs/server/src/rpc.rs b/conmon-rs/server/src/rpc.rs index 6acc98aa62..f4d57fbecc 100644 --- a/conmon-rs/server/src/rpc.rs +++ b/conmon-rs/server/src/rpc.rs @@ -462,4 +462,46 @@ impl conmon::Server for Server { .instrument(debug_span!("promise")), ) } + + fn serve_exec_container( + &mut self, + params: conmon::ServeExecContainerParams, + mut results: conmon::ServeExecContainerResults, + ) -> Promise<(), capnp::Error> { + debug!("Got a serve exec container request"); + let req = pry!(pry!(params.get()).get_request()); + + let span = debug_span!( + "serve_exec_container", + uuid = Uuid::new_v4().to_string().as_str() + ); + let _enter = span.enter(); + pry_err!(Telemetry::set_parent_context(pry!(req.get_metadata()))); + + let id = pry_err!(pry_err!(req.get_id()).to_string()); + let cmd = capnp_vec_str!(req.get_cmd()); + let (tty, stdin, stdout, stderr) = ( + req.get_tty(), + req.get_stdin(), + req.get_stdout(), + req.get_stderr(), + ); + let mut streaming_server = self.streaming_server().clone(); + let child_reaper = self.reaper().clone(); + let config = self.config().clone(); + + Promise::from_future( + async move { + let url = capnp_err!( + streaming_server + .exec_url(child_reaper, config, id, cmd, tty, stdin, stdout, stderr) + .await + )?; + + results.get().init_response().set_url(&url); + Ok(()) + } + .instrument(debug_span!("promise")), + ) + } } diff --git a/conmon-rs/server/src/server.rs b/conmon-rs/server/src/server.rs index 3d0a0adbff..6d9dc99116 100644 --- a/conmon-rs/server/src/server.rs +++ b/conmon-rs/server/src/server.rs @@ -9,6 +9,7 @@ use crate::{ journal::Journal, listener::{DefaultListener, Listener}, pause::Pause, + streaming_server::StreamingServer, telemetry::Telemetry, version::Version, }; @@ -53,6 +54,9 @@ pub struct Server { /// Fd socket instance. #[getset(get = "pub(crate)")] fd_socket: Arc, + + #[getset(get = "pub(crate)")] + streaming_server: Box, } impl Server { @@ -62,6 +66,7 @@ impl Server { config: Default::default(), reaper: Default::default(), fd_socket: Default::default(), + streaming_server: Default::default(), }; if let Some(v) = server.config().version() { @@ -273,7 +278,12 @@ impl Server { .context("remove existing fd socket file") } - async fn start_backend(self, mut shutdown_rx: oneshot::Receiver<()>) -> Result<()> { + async fn start_backend(mut self, mut shutdown_rx: oneshot::Receiver<()>) -> Result<()> { + self.streaming_server + .start() + .await + .context("start streaming server")?; + let listener = Listener::::default().bind_long_path(self.config().socket())?; let client: conmon::Client = capnp_rpc::new_client(self); @@ -357,6 +367,17 @@ impl GenerateRuntimeArgs<'_> { /// Generate the OCI runtime CLI arguments from the provided parameters. pub(crate) fn exec_sync_args(&self, command: Reader) -> Result> { + let mut args = self.exec_sync_args_without_command(); + + for arg in command { + args.push(arg?.to_string()?); + } + + debug!("Exec args {:?}", args.join(" ")); + Ok(args) + } + + pub(crate) fn exec_sync_args_without_command(&self) -> Vec { let mut args = vec![]; if let Some(rr) = self.config.runtime_root() { @@ -378,11 +399,6 @@ impl GenerateRuntimeArgs<'_> { args.push(format!("--pid-file={}", self.pidfile.display())); args.push(self.id.into()); - for arg in command { - args.push(arg?.to_string()?); - } - - debug!("Exec args {:?}", args.join(" ")); - Ok(args) + args } } diff --git a/conmon-rs/server/src/streaming_server.rs b/conmon-rs/server/src/streaming_server.rs new file mode 100644 index 0000000000..d0f9a1c4ac --- /dev/null +++ b/conmon-rs/server/src/streaming_server.rs @@ -0,0 +1,387 @@ +use crate::{ + child::Child, + child_reaper::ChildReaper, + config::Config, + container_io::{ContainerIO, Message as IOMessage, Pipe, SharedContainerIO}, + container_log::ContainerLog, + server::GenerateRuntimeArgs, +}; +use anyhow::{Context, Result}; +use axum::{ + extract::{ + ws::{close_code, CloseFrame, Message, WebSocket, WebSocketUpgrade}, + Path, State as AxumState, + }, + http::StatusCode, + response::IntoResponse, + routing::get, + Router, +}; +use conmon_common::conmon_capnp::conmon::CgroupManager; +use futures::{ + sink::SinkExt, + stream::{SplitSink, StreamExt}, +}; +use serde_json::json; +use std::{collections::HashMap, ops::ControlFlow, sync::Arc}; +use tokio::{ + net::TcpListener, + sync::{mpsc::unbounded_channel, RwLock}, + task, +}; +use tower_http::trace::{DefaultMakeSpan, TraceLayer}; +use tracing::{debug, debug_span, error, info, warn}; +use uuid::Uuid; + +const ADDR: &str = "127.0.0.1"; +const PROTOCOL: &str = "v5.channel.k8s.io"; + +const EXEC_PATH: &str = "exec"; +const ATTACH_PATH: &str = "attach"; +const PORTFORWARD_PATH: &str = "portforward"; + +const STDIN_BYTE: u8 = 0; +const STDOUT_BYTE: u8 = 1; +const STDERR_BYTE: u8 = 2; +const STREAM_ERR_BYTE: u8 = 3; + +#[derive(Clone, Debug, Default)] +pub struct StreamingServer { + port: u16, + state: State, +} + +#[derive(Clone, Debug, Default)] +struct State { + exec: Arc>>, +} + +#[derive(Clone, Debug, Default)] +struct ExecSession { + child_reaper: Arc, + server_config: Config, + container_id: String, + cmd: Vec, + tty: bool, + stdin: bool, + stdout: bool, + stderr: bool, +} + +impl StreamingServer { + pub async fn start(&mut self) -> Result<()> { + let listener = TcpListener::bind(ADDR.to_string() + ":0") + .await + .context("bind streaming server")?; + + let local_addr = listener.local_addr()?; + let state: State = Default::default(); + + self.port = local_addr.port(); + self.state = state.clone(); + + info!("Starting streaming server on {}", local_addr); + task::spawn_local(Self::serve(listener, state)); + + Ok(()) + } + + async fn serve(listener: TcpListener, state: State) -> Result<()> { + let router = Router::new() + .route(&Self::path_for(EXEC_PATH), get(Self::handle_exec)) + .route(&Self::path_for(ATTACH_PATH), get(Self::handle_attach)) + .route( + &Self::path_for(PORTFORWARD_PATH), + get(Self::handle_portforward), + ) + .fallback(Self::fallback) + .with_state(state) + .layer( + TraceLayer::new_for_http() + .make_span_with(DefaultMakeSpan::default().include_headers(true)), + ); + axum::serve(listener, router) + .await + .context("start streaming server") + } + + fn path_for(p: &str) -> String { + format!("/{}/:token", p) + } + + pub async fn fallback() -> impl IntoResponse { + "not found" + } + + #[allow(clippy::too_many_arguments)] + /// Returns the URL used for the provided exec parameters + pub async fn exec_url( + &mut self, + child_reaper: Arc, + server_config: Config, + container_id: String, + cmd: Vec, + tty: bool, + stdin: bool, + stdout: bool, + stderr: bool, + ) -> Result { + let mut state_lock = self.state.exec.write().await; + let uuid = Uuid::new_v4(); + state_lock.insert( + uuid, + ExecSession { + child_reaper, + server_config, + container_id, + cmd, + tty, + stdin, + stdout, + stderr, + }, + ); + Ok(format!( + "http://{}:{}/{}/{}", + ADDR, self.port, EXEC_PATH, uuid + )) + } + + async fn handle_attach( + _ws: WebSocketUpgrade, + Path(token): Path, + AxumState(_state): AxumState, + ) -> impl IntoResponse { + let span = debug_span!("handle_attach", token = token.to_string().as_str()); + let _enter = span.enter(); + + unimplemented!() + } + + async fn handle_portforward( + _ws: WebSocketUpgrade, + Path(token): Path, + AxumState(_state): AxumState, + ) -> impl IntoResponse { + let span = debug_span!("handle_portforward", token = token.to_string().as_str()); + let _enter = span.enter(); + + unimplemented!() + } + + async fn handle_exec( + ws: WebSocketUpgrade, + Path(token): Path, + AxumState(state): AxumState, + ) -> impl IntoResponse { + let span = debug_span!("handle_exec", token = token.to_string().as_str()); + let _enter = span.enter(); + + info!("Got exec request for token: {}", token); + let mut state_lock = state.exec.write().await; + + match state_lock.remove(&token) { + Some(session) => { + info!("Got valid exec session: {:?}", session); + let session_clone: ExecSession = session.clone(); + ws.protocols([PROTOCOL]) + .on_upgrade(move |socket| Self::handle_exec_socket(socket, session_clone)) + } + None => ( + StatusCode::NOT_FOUND, + format!("unable to find exec session for token: {}", token), + ) + .into_response(), + } + } + + async fn handle_exec_socket(socket: WebSocket, session: ExecSession) { + let (mut sender, mut receiver) = socket.split(); + + let mut send_task = tokio::spawn(async move { + if let Err(e) = Self::exec_in_container(&session, &mut sender).await { + error!("Unable to exec in container: {}", e); + } + + if let Err(e) = sender + .send(Message::Close( + CloseFrame { + code: close_code::NORMAL, + reason: "exec done".into(), + } + .into(), + )) + .await + { + error!("Unable to send close message: {}", e) + } + }); + + let mut recv_task = tokio::spawn(async move { + while let Some(Ok(msg)) = receiver.next().await { + if Self::process_message(msg).is_break() { + break; + } + } + }); + + tokio::select! { + rv_a = (&mut send_task) => { + match rv_a { + Ok(_) => info!("All messages sent"), + Err(a) => error!("Error sending messages: {a:?}") + } + recv_task.abort(); + }, + rv_b = (&mut recv_task) => { + match rv_b { + Ok(_) => info!("All messages received"), + Err(b) => error!("Error receiving messages: {b:?}") + } + send_task.abort(); + } + } + + info!("Closing websocket connection"); + } + + fn process_message(msg: Message) -> ControlFlow<(), ()> { + match msg { + Message::Binary(data) => { + debug!("Got {} binary bytes", data.len()); + } + Message::Close(c) => { + if let Some(cf) = c { + info!( + "Got websocket close with code {} and reason `{}`", + cf.code, cf.reason + ); + } else { + warn!("Got close message without CloseFrame"); + } + return ControlFlow::Break(()); + } + Message::Text(t) => debug!("Got text message: {t:?}"), + Message::Pong(_) => debug!("Got pong"), + Message::Ping(_) => debug!("Got ping"), + } + + ControlFlow::Continue(()) + } + + async fn exec_in_container( + session: &ExecSession, + sender: &mut SplitSink, + ) -> Result<()> { + let logger = ContainerLog::new(); + let mut container_io = + ContainerIO::new(session.tty, logger).context("create new container IO")?; + let config = session.server_config.clone(); + let pidfile = ContainerIO::temp_file_name(Some(config.runtime_dir()), "serve_exec", "pid") + .context("build pidfile path")?; + + let args = GenerateRuntimeArgs { + config: &config, + id: &session.container_id, + container_io: &container_io, + pidfile: &pidfile, + cgroup_manager: CgroupManager::Systemd, + }; + let mut args = args.exec_sync_args_without_command(); + let mut cmd_clone = session.cmd.clone(); + args.append(&mut cmd_clone); + + let (grandchild_pid, token) = session + .child_reaper + .create_child( + config.runtime(), + &args, + false, + &mut container_io, + &pidfile, + vec![], + vec![], + ) + .await + .context("create new child process")?; + + let mut io = SharedContainerIO::new(container_io); + let io_clone = io.clone(); + let child = Child::new( + session.container_id.clone(), + grandchild_pid, + vec![], + vec![], + None, + io_clone, + vec![], + token.clone(), + ); + + let mut exit_rx = session + .child_reaper + .watch_grandchild(child, vec![]) + .context("watch grandchild for pid")?; + + let cio = io.container_io(); + let mut lock_cio = cio.write().await; + let (stdout_rx, maybe_stderr_rx) = lock_cio.channels().context("retrieve IO channels")?; + let (_, mut temp_rx) = unbounded_channel(); + let stderr_rx = maybe_stderr_rx.unwrap_or(&mut temp_rx); + + loop { + tokio::select! { + Some(IOMessage::Data(mut data, pipe))= stdout_rx.recv() => { + if !session.stdout { + continue + } + + let byte = match pipe { + Pipe::StdOut => STDOUT_BYTE, + Pipe::StdErr => STDERR_BYTE, + }; + data.insert(0, byte); + sender.send(Message::Binary(data)).await.context("send to stdout")?; + }, + + Some(IOMessage::Data(mut data, pipe)) = stderr_rx.recv() => { + if !session.stderr { + continue + } + + let byte = match pipe { + Pipe::StdOut => STDOUT_BYTE, + Pipe::StdErr => STDERR_BYTE, + }; + data.insert(0, byte); + sender.send(Message::Binary(data)).await.context("send to stderr")?; + }, + + Ok(exit_data) = exit_rx.recv() => { + if exit_data.exit_code != 0 { + let mut err = vec![STREAM_ERR_BYTE]; + err.extend( + json!({ + "status": "Failure", + "reason": "NonZeroExitCode", + "details": { + "causes": [{ + "reason": "ExitCode", + "message": exit_data.exit_code.to_string(), + }], + }, + "message": "command terminated with non-zero exit code", + }) + .to_string() + .as_bytes(), + ); + sender.send(Message::Binary(err)).await.context("send exit failure message")?; + } + break + }, + } + } + + Ok(()) + } +} diff --git a/internal/proto/conmon.capnp.go b/internal/proto/conmon.capnp.go index 1e636b4229..d29d7bbede 100644 --- a/internal/proto/conmon.capnp.go +++ b/internal/proto/conmon.capnp.go @@ -176,6 +176,26 @@ func (c Conmon) StartFdSocket(ctx context.Context, params func(Conmon_startFdSoc } +func (c Conmon) ServeExecContainer(ctx context.Context, params func(Conmon_serveExecContainer_Params) error) (Conmon_serveExecContainer_Results_Future, capnp.ReleaseFunc) { + + s := capnp.Send{ + Method: capnp.Method{ + InterfaceID: 0xb737e899dd6633f1, + MethodID: 8, + InterfaceName: "internal/proto/conmon.capnp:Conmon", + MethodName: "serveExecContainer", + }, + } + if params != nil { + s.ArgsSize = capnp.ObjectSize{DataSize: 0, PointerCount: 1} + s.PlaceArgs = func(s capnp.Struct) error { return params(Conmon_serveExecContainer_Params(s)) } + } + + ans, release := capnp.Client(c).SendCall(ctx, s) + return Conmon_serveExecContainer_Results_Future{Future: ans.Future()}, release + +} + func (c Conmon) WaitStreaming() error { return capnp.Client(c).WaitStreaming() } @@ -264,6 +284,8 @@ type Conmon_Server interface { CreateNamespaces(context.Context, Conmon_createNamespaces) error StartFdSocket(context.Context, Conmon_startFdSocket) error + + ServeExecContainer(context.Context, Conmon_serveExecContainer) error } // Conmon_NewServer creates a new Server from an implementation of Conmon_Server. @@ -282,7 +304,7 @@ func Conmon_ServerToClient(s Conmon_Server) Conmon { // This can be used to create a more complicated Server. func Conmon_Methods(methods []server.Method, s Conmon_Server) []server.Method { if cap(methods) == 0 { - methods = make([]server.Method, 0, 8) + methods = make([]server.Method, 0, 9) } methods = append(methods, server.Method{ @@ -381,6 +403,18 @@ func Conmon_Methods(methods []server.Method, s Conmon_Server) []server.Method { }, }) + methods = append(methods, server.Method{ + Method: capnp.Method{ + InterfaceID: 0xb737e899dd6633f1, + MethodID: 8, + InterfaceName: "internal/proto/conmon.capnp:Conmon", + MethodName: "serveExecContainer", + }, + Impl: func(ctx context.Context, call *server.Call) error { + return s.ServeExecContainer(ctx, Conmon_serveExecContainer{call}) + }, + }) + return methods } @@ -520,6 +554,23 @@ func (c Conmon_startFdSocket) AllocResults() (Conmon_startFdSocket_Results, erro return Conmon_startFdSocket_Results(r), err } +// Conmon_serveExecContainer holds the state for a server call to Conmon.serveExecContainer. +// See server.Call for documentation. +type Conmon_serveExecContainer struct { + *server.Call +} + +// Args returns the call's arguments. +func (c Conmon_serveExecContainer) Args() Conmon_serveExecContainer_Params { + return Conmon_serveExecContainer_Params(c.Call.Args()) +} + +// AllocResults allocates the results struct. +func (c Conmon_serveExecContainer) AllocResults() (Conmon_serveExecContainer_Results, error) { + r, err := c.Call.AllocResults(capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_serveExecContainer_Results(r), err +} + // Conmon_List is a list of Conmon. type Conmon_List = capnp.CapList[Conmon] @@ -3112,6 +3163,248 @@ func (f Conmon_TextTextMapEntry_Future) Struct() (Conmon_TextTextMapEntry, error return Conmon_TextTextMapEntry(p.Struct()), err } +type Conmon_ServeExecContainerRequest capnp.Struct + +// Conmon_ServeExecContainerRequest_TypeID is the unique identifier for the type Conmon_ServeExecContainerRequest. +const Conmon_ServeExecContainerRequest_TypeID = 0xd01c697281e61c21 + +func NewConmon_ServeExecContainerRequest(s *capnp.Segment) (Conmon_ServeExecContainerRequest, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 3}) + return Conmon_ServeExecContainerRequest(st), err +} + +func NewRootConmon_ServeExecContainerRequest(s *capnp.Segment) (Conmon_ServeExecContainerRequest, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 3}) + return Conmon_ServeExecContainerRequest(st), err +} + +func ReadRootConmon_ServeExecContainerRequest(msg *capnp.Message) (Conmon_ServeExecContainerRequest, error) { + root, err := msg.Root() + return Conmon_ServeExecContainerRequest(root.Struct()), err +} + +func (s Conmon_ServeExecContainerRequest) String() string { + str, _ := text.Marshal(0xd01c697281e61c21, capnp.Struct(s)) + return str +} + +func (s Conmon_ServeExecContainerRequest) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_ServeExecContainerRequest) DecodeFromPtr(p capnp.Ptr) Conmon_ServeExecContainerRequest { + return Conmon_ServeExecContainerRequest(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_ServeExecContainerRequest) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_ServeExecContainerRequest) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_ServeExecContainerRequest) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_ServeExecContainerRequest) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_ServeExecContainerRequest) Metadata() (Conmon_TextTextMapEntry_List, error) { + p, err := capnp.Struct(s).Ptr(0) + return Conmon_TextTextMapEntry_List(p.List()), err +} + +func (s Conmon_ServeExecContainerRequest) HasMetadata() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_ServeExecContainerRequest) SetMetadata(v Conmon_TextTextMapEntry_List) error { + return capnp.Struct(s).SetPtr(0, v.ToPtr()) +} + +// NewMetadata sets the metadata field to a newly +// allocated Conmon_TextTextMapEntry_List, preferring placement in s's segment. +func (s Conmon_ServeExecContainerRequest) NewMetadata(n int32) (Conmon_TextTextMapEntry_List, error) { + l, err := NewConmon_TextTextMapEntry_List(capnp.Struct(s).Segment(), n) + if err != nil { + return Conmon_TextTextMapEntry_List{}, err + } + err = capnp.Struct(s).SetPtr(0, l.ToPtr()) + return l, err +} +func (s Conmon_ServeExecContainerRequest) Id() (string, error) { + p, err := capnp.Struct(s).Ptr(1) + return p.Text(), err +} + +func (s Conmon_ServeExecContainerRequest) HasId() bool { + return capnp.Struct(s).HasPtr(1) +} + +func (s Conmon_ServeExecContainerRequest) IdBytes() ([]byte, error) { + p, err := capnp.Struct(s).Ptr(1) + return p.TextBytes(), err +} + +func (s Conmon_ServeExecContainerRequest) SetId(v string) error { + return capnp.Struct(s).SetText(1, v) +} + +func (s Conmon_ServeExecContainerRequest) Cmd() (capnp.TextList, error) { + p, err := capnp.Struct(s).Ptr(2) + return capnp.TextList(p.List()), err +} + +func (s Conmon_ServeExecContainerRequest) HasCmd() bool { + return capnp.Struct(s).HasPtr(2) +} + +func (s Conmon_ServeExecContainerRequest) SetCmd(v capnp.TextList) error { + return capnp.Struct(s).SetPtr(2, v.ToPtr()) +} + +// NewCmd sets the cmd field to a newly +// allocated capnp.TextList, preferring placement in s's segment. +func (s Conmon_ServeExecContainerRequest) NewCmd(n int32) (capnp.TextList, error) { + l, err := capnp.NewTextList(capnp.Struct(s).Segment(), n) + if err != nil { + return capnp.TextList{}, err + } + err = capnp.Struct(s).SetPtr(2, l.ToPtr()) + return l, err +} +func (s Conmon_ServeExecContainerRequest) Tty() bool { + return capnp.Struct(s).Bit(0) +} + +func (s Conmon_ServeExecContainerRequest) SetTty(v bool) { + capnp.Struct(s).SetBit(0, v) +} + +func (s Conmon_ServeExecContainerRequest) Stdin() bool { + return capnp.Struct(s).Bit(1) +} + +func (s Conmon_ServeExecContainerRequest) SetStdin(v bool) { + capnp.Struct(s).SetBit(1, v) +} + +func (s Conmon_ServeExecContainerRequest) Stdout() bool { + return capnp.Struct(s).Bit(2) +} + +func (s Conmon_ServeExecContainerRequest) SetStdout(v bool) { + capnp.Struct(s).SetBit(2, v) +} + +func (s Conmon_ServeExecContainerRequest) Stderr() bool { + return capnp.Struct(s).Bit(3) +} + +func (s Conmon_ServeExecContainerRequest) SetStderr(v bool) { + capnp.Struct(s).SetBit(3, v) +} + +// Conmon_ServeExecContainerRequest_List is a list of Conmon_ServeExecContainerRequest. +type Conmon_ServeExecContainerRequest_List = capnp.StructList[Conmon_ServeExecContainerRequest] + +// NewConmon_ServeExecContainerRequest creates a new list of Conmon_ServeExecContainerRequest. +func NewConmon_ServeExecContainerRequest_List(s *capnp.Segment, sz int32) (Conmon_ServeExecContainerRequest_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 8, PointerCount: 3}, sz) + return capnp.StructList[Conmon_ServeExecContainerRequest](l), err +} + +// Conmon_ServeExecContainerRequest_Future is a wrapper for a Conmon_ServeExecContainerRequest promised by a client call. +type Conmon_ServeExecContainerRequest_Future struct{ *capnp.Future } + +func (f Conmon_ServeExecContainerRequest_Future) Struct() (Conmon_ServeExecContainerRequest, error) { + p, err := f.Future.Ptr() + return Conmon_ServeExecContainerRequest(p.Struct()), err +} + +type Conmon_ServeExecContainerResponse capnp.Struct + +// Conmon_ServeExecContainerResponse_TypeID is the unique identifier for the type Conmon_ServeExecContainerResponse. +const Conmon_ServeExecContainerResponse_TypeID = 0xa9e93cf268b17735 + +func NewConmon_ServeExecContainerResponse(s *capnp.Segment) (Conmon_ServeExecContainerResponse, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_ServeExecContainerResponse(st), err +} + +func NewRootConmon_ServeExecContainerResponse(s *capnp.Segment) (Conmon_ServeExecContainerResponse, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_ServeExecContainerResponse(st), err +} + +func ReadRootConmon_ServeExecContainerResponse(msg *capnp.Message) (Conmon_ServeExecContainerResponse, error) { + root, err := msg.Root() + return Conmon_ServeExecContainerResponse(root.Struct()), err +} + +func (s Conmon_ServeExecContainerResponse) String() string { + str, _ := text.Marshal(0xa9e93cf268b17735, capnp.Struct(s)) + return str +} + +func (s Conmon_ServeExecContainerResponse) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_ServeExecContainerResponse) DecodeFromPtr(p capnp.Ptr) Conmon_ServeExecContainerResponse { + return Conmon_ServeExecContainerResponse(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_ServeExecContainerResponse) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_ServeExecContainerResponse) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_ServeExecContainerResponse) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_ServeExecContainerResponse) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_ServeExecContainerResponse) Url() (string, error) { + p, err := capnp.Struct(s).Ptr(0) + return p.Text(), err +} + +func (s Conmon_ServeExecContainerResponse) HasUrl() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_ServeExecContainerResponse) UrlBytes() ([]byte, error) { + p, err := capnp.Struct(s).Ptr(0) + return p.TextBytes(), err +} + +func (s Conmon_ServeExecContainerResponse) SetUrl(v string) error { + return capnp.Struct(s).SetText(0, v) +} + +// Conmon_ServeExecContainerResponse_List is a list of Conmon_ServeExecContainerResponse. +type Conmon_ServeExecContainerResponse_List = capnp.StructList[Conmon_ServeExecContainerResponse] + +// NewConmon_ServeExecContainerResponse creates a new list of Conmon_ServeExecContainerResponse. +func NewConmon_ServeExecContainerResponse_List(s *capnp.Segment, sz int32) (Conmon_ServeExecContainerResponse_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz) + return capnp.StructList[Conmon_ServeExecContainerResponse](l), err +} + +// Conmon_ServeExecContainerResponse_Future is a wrapper for a Conmon_ServeExecContainerResponse promised by a client call. +type Conmon_ServeExecContainerResponse_Future struct{ *capnp.Future } + +func (f Conmon_ServeExecContainerResponse_Future) Struct() (Conmon_ServeExecContainerResponse, error) { + p, err := f.Future.Ptr() + return Conmon_ServeExecContainerResponse(p.Struct()), err +} + type Conmon_version_Params capnp.Struct // Conmon_version_Params_TypeID is the unique identifier for the type Conmon_version_Params. @@ -4568,222 +4861,422 @@ func (p Conmon_startFdSocket_Results_Future) Response() Conmon_StartFdSocketResp return Conmon_StartFdSocketResponse_Future{Future: p.Future.Field(0, nil)} } -const schema_ffaaf7385bc4adad = "x\xda\xc4Y}p\x14\xe7y\x7f\x9e\xdd\x93V\xa7\x0f" + - "N\xdb=\x09\x10\xa8\xd2\x10HA\x0d\xe1C\xb8&\x0c" + - "\x19I\x80B!\xe0hu`ZH\\\x96\xbbE:" + - "\xb8\xdb=v\xf7\x00\x11\xa72I=v\x94\xd81*" + - "\x9e\xd8L\x99A\xb6\xa1\x80\xa1\xc6\x1fP\x83\xc1\x03\x18" + - "\xc6\x80M]h\xa1\xc6c\\0\xa6\xb6\x19\x7fQ\xbb" + - "S\xec\x81n\xe7y\xef\xf6C'\x19\x9fTw\xf2\x07" + - "\x83\xee\xd9\xdf>\xef\xc7\xf3\xf9{v\xe2\xe7\xc1\xc6\xc0" + - "\xa4\xb27\x86\x00'\xef*(\xb4\xcd\xcb\x1d\xc6\xb6\xcd" + - "\xb3\x7f\x05\xe2w\x10\xa0\x00\x05\x80\xfa\xf9\xc2\xbb\x08(" + - ")B\x03\xa0\xfd_O\x9d\xf8\xe1\xef7|\xda\xe5\x07" + - "\xac\xcf\x00\x1ee\x80\xb7\xa7\xd6-\xdf\xc2\xcf\xfb\x8d\x1f" + - "\xb0_x\x8b\x00\xa7\x19\xe0\xaf\x97\x866\xfem\xe5\x12" + - "\x06\xb0\xaf\xd7/\xbf\xf8\xf8\x07w\xfe#\x14\x08\x04\xfc" + - "Xx\x0b\xa5`\x11\xfdYP\xf4;\x04\xb4_\xfb\xe3" + - "u\x8bB\xdb\x1ex,\x07\xcd\xd4^\x0d\xbe\x8b\x12\x16" + - "\x0b\x00\xd2\xad \xa9\xbe\xff\xc3\xbb\xf6-\xfc\xd5\xa7[" + - "\xfckO*\xfeOZ\xbb\xb9\x98\x00\x8f/\xf9`e" + - "\xf3\x9c\xd0\x13\xbd\xb5\x05\x08\x17/\xde\x89\xd2\xfab\x01" + - "x\xbb\xf2\xab+O\x9d\x8fL\xdd\x01\xf2w\xb0\xcf\xa2" + - "?#\\\x9a-\xba\xaax\x0d\xa0=\xfa\x99W\xcet" + - "M\x9f\xb0\xd3\xbf\xe8\xe9\xe2\xb3\xb4\xe8e\xb6h\xd7\xdf" + - "\xab\x7fr\xe4\xc0\x8f\x09\xc0y\xda\x00\xeb\xb1\xa4\x0b\xa5" + - "\xe1%\xa4\xaa\xa2\xe4N@{\xcd\xd2\x13\xcf\xac\x93\xaf" + - "\xee\xeag{\xd5%\xdd(\xddQB\xdb\x93fM\xdc" + - "\x7f\xbe\xbenw\xee\xf68\xc2\x89\x84\x1b\xc7t\x8e)" + - "y\x06\xd0\x9e\xd2\xf3\xfc\xbe\x87?Y\xfb\x0f\x84\xe6r" + - "\x0fs\xaed\x05J\x1f\x96\x0c\x05\x90\xae3\xf4\xcf\xcf" + - "\\\xdb\xfe\xf0o\x9a\xf6\xe6\xea\xe6\x09\xfd\xeb\xd2\xa3(" + - "\xf5\x94\xd2\x9f\x9bKk\xc8:\xfc\xa5\xf7\x8a\x1fn\x9a" + - "\xb0\xaf?\xeb\x1c/;\x85\xd2\xe52\xda\xc9\xc52\xba" + - "\x07\xf7\xb98\x92\xb7w\xef>\xb6d\xea\x7f\xef\xb4\xe9" + - "\x1en\x95Ua}\xd9\x90EH\x8aC\x02'\x05E" + - "\x01\xc0\x1e\xf7\xd1\x83\xdb\x1ex:r\xa0?\xe5\xd7\xcb" + - "\x8fb\x06&\x15\x88\xa4\xfc\xd4\xbe\x1d\xd3\xbe\xba\xb2\xe6" + - "@\xee\xc6i\xfd\xfa\x1f\x88gQZH\xe8zY|" + - "\x80\x07\xb4\xcb\x97\xbc\xf1\xc3\x8f\xee\xf9\x8f\xe3~\xa3\x1d" + - "\xaf`^z\xa1\x82\xf4\xbd\xaf\xbc\xc45\x9fN\xbc\xea" + - "\x07\xdc\xaa(\xe6\x00\xa5\x8aJ\x06x\xef\x7fV\xb4\xa5" + - "&\xbc\xee\x07\xdcQ\xd9\xcd|\x8d\x01V\x96\x9c\x08\x07" + - "\x1b\xcc\x7f\xf2\x03\xd4\xca\xa3\x04H3\xc0\x8d\x8a\x97\x7f" + - "_5\xfd@/\xc0\xa3\x95l\x0f;\x18\xa0\xaa\xe9\xcc" + - "\x94\x906\xfb\x9fs.\x80\xd9\xe2t\xe5\x13(]\xad" + - "\xa4\x0b\xb8\\I\x96{\xf2\xf3\xedK\xf7n\x08\x9f\xef" + - "\xe3e\x1b\x86\xae@i\xebPB\xf6\x0c\xed\x04\xb4o" + - "\xde?\xfd\xbe\xea\xea\xf3\x17\xfa\xf5\x9fsC\xaf\xa1t" + - "\x9d\xa1?\x1e\xfa>\xa0\xbd\xe9O\xd7\xa4\xeeY6\xed" + - "\x9d\x1c4s\xca\x93\xc3\xdeB\xe9\xea0\xb6\x89a\xb4" + - "\xe3\x9b\xd3n\xbe\xbcez\xea\xdfsU\x17\xb0\x88\x1e" + - "\xde\x85R\xf5p\xfas\xf8\xf0E\xe4>\x0bS\xb3\xc5" + - "\xef\xb6\x0e\xb9\xe4\xbf\x81\x87\xaa\xfe\x88.yk\x15\xe9" + - "\x9b\xf8\xf3\xd9;\xee\x89KW\xfc\x80\x93U\x9b\x98\x99" + - "\x18\xe0\xcf\xa4W\xf6h\x1b\xae]\xede\xa6\xaak\x04" + - "\x10G\x10\xe0\xc8\x92\xfa\x96\x7f\xbb\xf2\xdd\xcf@\x1c\xcf" + - "y\xb1\x00X?iD7JsF\xd0\xde\x9bGP" + - "\xf0\x9d\xf9\xa4f\xd7kW\x7f\xfcy\xee\xde\x83\xa4s" + - "\xe1\x88M(%G\xb0D1\xe2N\x0e\xd0\xde\xb6\xea" + - "\xc9Gn\x8c\x12\xbf\xc8\x8d+v\xd4C\xd5\xef\xa2t" + - "\xa1\x9a]h\xf5\xabt\xd4\x177m\xfc\xdd\xb1\xc9\xb3" + - "\xbf\xf0o\xf4b\x0d\xcb\x12\xd7kh\xa3\x15\x7f\xb5\xfe" + - "R\xdd\x87Wz\x01\xc4\xdaS\x04\x18SK\x80\x83\xb8" + - "\xb3\xe4\xa7+>\xb8\xe1\x07\xcc\xa9eG\xfd\x19\x03\xdc" + - "\xe8y\xba\xfe\xbe\xd3\xcf\x7f\xd9O\xf6X_{\x0a\xa5" + - "\xcd\xb5\x94=\xba\xffen\xf2\x9d[/}\x95\xe3T" + - "\xcc\xf8\x1d\xb5O\xa0\xb4\xa1\x96\xee\xe4\xa1\xda50\xde" + - "\x8ek\x96jhJ\xa2pB\xca\xd0-}BT\xd7" + - "\x92\xba\xf6\xfd\xa8\x92\xd2R\xd3ff~\xa8k\xd5h" + - "\xa4C\x8b\xce\xd45K\x89k\xaa1\xbaE1\x04%" + - "i\xca\x01>\x00\x10@\x00\xb1l\x06\x80\\\xc4\xa3\x1c" + - "\xe6\xb0\xd3PW\xa5U\xd3\xc2r\xef\x0e\x01\xb1\x1c0" + - "\xaf\xe5\xa2\x86\xaaX\xea]JR5SJT5G" + - "\xb7\xaafZHX\xbd\x96\x9b\x0b \x97\xf2(\x0f\xe3" + - "\xd06T3\xa5k\xa6\x0a\x00X\xee\xd5\x93\xff\xcb\x92" + - "-\x8a\xa1\xf0\xf9\x1c\xd0\xadu\x03Xmf\xcej\xad" + - "\xa4\x8d7\xad\x16Dy\xa4\xbb\xe0\xdee\x00\xf2\x0b<" + - "\xca\x879\x14\x11\xc3H\xc2C\x8b\x01\xe4\x83<\xcao" + - "r(r\\\x189\x00\xf1\x1c!\xff\x95G\xf93\x0e" + - "E\x9e\x0f#\x0f ~L\xc2\x8fx\x8c\x14!\x87b" + - " \x10\xc6\x00\xa5R\x9c\x0b\x10\x09 \x8f\x91r\x92\x17" + - "\x14\x84\xb1\x00@*\xc3\xc9\x00\x91\"\x92\x87I^X" + - "\x18\xc6B\x00Id\xf8r\x92\x7f\x0f9\xb4\x93\xaa\xa5" + - "\xc4\x14K\x01\xe1'\x89\x18\x96\x01\x87e\x80\xb6\x96=" + - "\x0a\xf0\xaa\x89C\x00[x\xc4\x90\x97\xaf\x00Ih\xa7" + - "\xe3\xb1\xf9J*\x15\x07Aksa\xa5\xc0\xb1\x87m" + - "\xb7{\xb8L1\xd5\x16\xc5j'\x03\x93\xac\x14\xb0&" + - "\xa5\xc7\xe6\xc4\x9c_\xde\xbe\x00\x9c\x97\xcb\xbd@\xc8n" + - "`p\xb61S\xba\xa0\x99*\x19\xc7\xe7\x0d\x8b\xb3\xfe" + - "7\x96\xeb\xff\xf8\xe5^\x8f1\x80\xd5\x0dUO\xa9\xda" + - "<\xbd\xcd\x0b\xb5V\xb5\xc6L\xe7\xed\xfcn\xfb\x93\xe3" + - "\x8e\x05\xb7Y\xb4\xd5Y\x94\xce\x1a\xd23g\xcd\xebM" + - "\xf7\x9a\xfco\xcaE\xeeF\xc7\xd5\x01\xc8\xa3y\x94'" + - "r\xe8x\xf0x\x92\x8d\xe5Q\x9e\xc2a\xc8\xeaH\xa9" + - "9\x9e\x12\x02\x0c\xa5\x14\xab\xdd5m>\xf7\xa6X\x96" + - "\x12m\xef\x95\x9f\x94$\xe6\x11\xben9\x1b\xc0}\xcd" + - "l3\xf4tj\xbe\xa2)m\xaa\x01\xc0\x8e\xcc\xe2P" + - "\x9cAj\xc4\xe0\\\x80N\xb3\xc3\xb4\xd4d\xcc\x8e2" + - "\xf0r\x13\x00\xf2R\xde\xc4N\xd2\x9a1*\xe6m\x89" + - "\xbbU\xc3\x8c\xeb\x1a\xcb$&\xb2LR\xea\x9e\xbd\x99" + - "\xce\xde\xc8\xa3<\xcf3\xc3\x1cJ\x0f\x7f\xce\xa3\xbc\x80" + - "\x12\x09f\x12\x89L\x8e\xd5\xc2\xa3\x9c\xe0\xb0s\xb5j" + - ",\xd3M\x15\x118D\xf8\xba\xd0\x1fP\xe0\x05ns" + - "\x82yz\xdb,#\x14_\xad\x1ar\x00\xfdU\x1d\xeb" + - "B\x0b:R\xaa\xff*v\xf19_\x93w\xb9\xcbv\xa2\x1f" + - "\x1a2\xee\xe7\x0ax\xc7\x08\x99\xb2\xe6&\xc8V\x07\xc8" + - "\xa2.\xbeZ\x054l'\xafA\x0d\xcbl\xb6\xf3N" + - "\x81\xf3\x92\xa3\xac9\xb7\x1ft\xbc\x1el\xe7\x11\xe7{" + - "\x96Me\xb6\x93\xda\xa0&\xb3\xb6\xfb\xbb!\xa3\xd7v" + - "\x0a\x11\xb6y\x0a\xfd2G\x91\x13q\xe8\x84\\\x88\xe9" + - "\xcb\x15\x9b5\x19\xb5NI\xe7{\xf5[\xa6\x05N\xf9" + - "B\x0f\xc3\xf5\xaa\xfb\xcc}m\x0f\xe6\xdbB\xd6\xd51" + - "\xeb\xeb\xce\x16r\xc4\xce\x16\x16\xa8k-\xfa\x87\xf3\x95" + - "T\xb3f\x19\x1d\x00r-_\x00\xe0\x92Lt\x88\x90" + - "x}\x06p\xe2U\x01=F\x81\x0e\x8f\x14/\xfc\x12" + - "8\xf1\x8c\x80\x9c;\xc6A\x874\x88\xc7\xbb\x81\x13\x8f" + - "\x08\xc8\xbb\xf3\x0at8\xb0\xb8\x97\xde\xdb-`\xc0\xa5" + - "S\xe8LR\xc4\x9eM\xc0\x89\x9b\x05,p\x191:" + - "\xacM\xdcp\x008\xf1!\x01\x0b\xdd\xa1\x0f:\xe3!" + - "q}\x17p\xe2/\x04\x14\\\x1e\x8c\x0e\xc3\x11W\x19" + - "\xc0\x89q\x81j\x08\xf9a#\xda\xd1\xac3a\xd6-" + - "\xa0\x11m\x87W\xa0\xe3,h4\xa2\xed\xd4r?\xd2" + - "p\xbd \x0b\xe5U\x82\x9a\xbd,>S\xd7\x1a2\xaf" + - "\xb8\xeb\xdd\xa5\xa0cP =f\xd6>P\xc3\x0c\xd4" + - "\x88\xfe\xfa:\x80\xd4\xe6%\xf9~\xba\xb2\xb1\xdc\xb7\xde" + - "\x8f\xe6DZ\xa6\xc07:KK\xcfb\x15@d\x17" + - "u\xe9/\xa2\xc7\x16\xa4\xbd\xb8\x18 \xf2\x02\xc9\x0f#" + - "\x87\x98\xe1\x0b\xd2!\xd6\xd4\x1f$\xf1\x09\xf4\x0a\x8dt" + - "\x9c\x91\x80\xc3$\x7f\x1d\xbdZ#\x9d\xc4V\x80\xc8\x09" + - "\x92\xbf\xc7H\x03\x9f!\x0d\x97q\x05@\xe4\x12\xc9o" + - "2\xd2\x10\xc8\x90\x86/\xd9\xb27\x18\x99\xe08\x14\x85" + - "\x820qYI\xe4H^\xce\x11\x99 yQa\x18" + - "\x8b\x00\xa4qL>\x96\xe4\xb3H\x1e\x14\xc2\x18\x04\x90" + - "\x9a\xb8e\x00\x91F\x92\xff\x94\xe4\xc5Ea,\x06\x90" + - "\xfe\x92\xc9\xff\x82\xe41\x92\x97\x04\xc3X\x02 )\x1c" + - "\x9dk)\xc9\xef%yiq\x18K\x01\xa4\x0en\x06" + - "@\xc4\"\xf9#$/\xc30\x96\x11\x03\xe6\x0c\x80\xc8" + - "oI\xfe\x18\xc9\x87\x94\x84q\x08\x80\xf4(\x93o$" + - "\xf9\x1e\x92\x87J\xc3\x18\x02\x90v3=\xdbI~\x8c" + - "\xebUv\xedei-\x96P[\x14\xe0}\x05\xcdR" + - "\x8dd\\S\x12\xe4\x04\xd9.\xaa\xc6\xb4bq\xcd\xed" + - "\xa9\xd4\xb5q\x8b\x11\x1b\xec\xc3yt=\xd9LO!" + - "\xa4X\xed}\x9e&\x9c\xbc\xcd\x1b>\xca\xe1\x9b~0" + - "T4\xa1*Z:5\x13\xf8d\xac\x0f\xe1J\xe8\xcb" + - "\x94D\x93\x01|_\xbe\x15\xd5\x93IE\x8b5\x81`" + - "\xf4}8\xf8&\xa2S\xd5V\xdf\xad\xf87\x9c\x1b\x11" + - "\xd1\xde%\x08C^\xdd\xce\xb4k\xb6\x12\x8b\xc5\xad\xb8" + - "\xaeA\x8d\x92\xf8Q\xccU\x15\xccl\xae3\xa1*+" + - "\xfb\x8a\x07\xc5!ZU3\x9d\xe0\xf3%^n{\x90" + - "C$\x84\xdb\xach\xfa;\xc7\x1c\xf2b\x02|3{" + - "q\x9b\x8d\x01\xb0\x97lJ\xce\x9f\"\xb9\xdd\xd6\x00&" + - "\x1c\xa6?]:\x07\xfa\xe6\xa5\xdcvg\xc0\xa3\x9b\xc1" + - "\x9a\xcd\xed\x04\x07\xc7\x97W\xa5\x05\xd5\xcce[U\x1e" + - ";\x11\xfb\xa7[\\_\xba\xe5O&\xff\xcfL\x8b\xf5" + - "3!*\x8a\x8c\xa5\xb0\xad\xdc1\x8aQ\xd7\xf1\xf4\x1f" + - "'\x8e\xa1\xffx\xb1\xba\x0e\x00\x03b\xc5(\x00!\x9e" + - "\x8a\x0a\x9aj\x09\xa9x,\x946UCH[f^" + - "\xf6\xe9\xa7Y\xf4\xcd\x0a\xca\xddkS\xe82\x96f." + - "\xc3\xb9\xb58\xd1\xa1\x18\x8fr\xca\xc7\x91\x92$l\xe7" + - "Q\xb6\xa8t\xd5f8\xd2*z;\xc5\xa3|/\x97" + - "\xc9\xaa3\xf5\x183q\x008\x0c\x006\x98VLO" + - "[\xcee\xd2O\xd50\xdc\xbb\xb5\xe2I5\xf6\x93\xb4" + - "\xe5\xcb\xd4\x83\xab\xce\xe4[|\x9fa\xd1\x0a\x9f\xffE" + - "\xb3`\x08\x19-\xf1\x18\x16\x01\x87Ey:\x9e\xd30" + - "g{cZd\x98\xbb\xc8\xe3\xe4v\x1by\x94\xb7\xf8" + - "\xdcn\xf3b\x00\xf9\xefx\x94\xb7\xfb\xdcn\xab\x01 " + - "?\xc5\xa3\xbc\x87C\xccN\x0bww\x03\xc8{x\x94" + - "\x0fR\xdd\xe73\x1cs?9\xed\x8b<\xca\xc7\xa8\xe8" + - "\x07X\xd1\x17\x8f\xd0M\x1f\xe6Q~\xbb\xb7\xd3\x9a," + - "\xd6s* \xeb\xf0T\xd3\x84\x9a\xb8\xae\xf9\xc6u\xa6" + - "\xa5\xa7\x9a\x96[*\x1a\x11\xaa\x87\xcd:.\xff6\xe7" + - "\x0c\x83H\xba,mX\x98g\xdap\x89\xdd \x12\xef" + - "\xc0\x12\x94Ko\x07\x90\x12\xfb\x99\"\xb6(!#\xaf" + - "\x81\xbd\xcbl\x07p2\x87D\x1a\xdf_\xd0\x91B\xd5" + - "7\x10;\xcb\xb2JE\x1d\x80\xeb\xf7\x9c\xd1\x9a\xd6(" + - "\xde\xe6\x90\xe6\xe5D\xabB+L]\x1b\xd8\x98\xcb\x17" + - "gc\xdd68\xc8\xfaTw\x88\xedt\xc1\"R\xdb" + - "VJ\xe2a\xe8%\x12\xa9\x02G9\xb3\xed\x91\xac\x0d" + - "\xe62m\xf0p\x9c\x06\x10\x09\x93\xbc\x16\xbdp\x90\xaa" + - "\x99\xfa\x91$\x1f\x8b^DHc\x18\xbe\xd6\x99\x91\x8b" + - "\x85\x05\x996x\x1cR\x9b:\x96\xe4SH.\x14f" + - "\xda\xe0I\xacm\x9eH\xf2\xe9$/\x122m\xf0\x0f" + - "\x98\xfe\xa9$\x9fE\xf2`Q\xb6\x0df\xedz#\xc9" + - "\xe7!\x87v\xca\xd0\xa3\xaai\xce\x01t\xd3\x87C\xb4" + - "\x9c\x00\x13,\xa5\xcd\xf9\xbb\x81\xba\xb9\xb8\xe5kU\xe3" + - "\x89\xd8,\xc5\x02T]\x88\xa5\x18m\xaa\x071\xd2\xa6" + - "EW\x0d\x82O\xa7\x1dU\x8c6\xfdn\xd5\x80\x90\xd9" + - "G\xbc\xc0P}\xfazE\xab\x13\xc1\x83,\x16^\x89" + - "\xadu}\xf7\x0c\xe5\xba\xd73_A\x9cTwnq" + - "\xf6#\xc8%_\xad\xb8HN\xfe&\x8f\xf2\x17d\xdf" + - "\xc6L\xae\xbbN\xd1\xf6\x19\x8f\xf2M\xdf<\xedK\xca" + - "u7x\x8c\x04\xfc\x0c\x07\xe9\xea[]\x0fq\x08\xce" + - "p\xe6Q\xccC&\xa2\x8f\xe0\x8cG\"\x0e\xdf#\xf9" + - "T\xec\x9d\x1e\xc9\xe3\xf5\xb4\x15\x01^\x8d:\xe3\xc5\xce" + - "l\x9f\x9d\xdba\xf7\xc3\x1b\xfe\xc0]\xf7`\x1a\xb1\xbc" + - "\x1bLwh7\xe8\x063\x93\xbcsZ\xe6\xaf\xcf\xa9" + - "\xee m\x00\x0b\xf6\xfd\x06\xda\xaa\x9a\xa1\xfc?\xcc\xb8" + - "\x83\xc5\x01\xac\x993Y\xf6\xcdS\xf3J\x96\xce\xd0\x89" + - "\xcd\x9c\x04\xcb\xe8\xc8\xf983\xca\xfb8\xe36\x0c\xe3" + - "'{_g\x84\x95j\x87;W^\xad$\xd2n|" + - "\xffo\x00\x00\x00\xff\xff\xfe\x11AT" +type Conmon_serveExecContainer_Params capnp.Struct + +// Conmon_serveExecContainer_Params_TypeID is the unique identifier for the type Conmon_serveExecContainer_Params. +const Conmon_serveExecContainer_Params_TypeID = 0x90a3950a51412b8b + +func NewConmon_serveExecContainer_Params(s *capnp.Segment) (Conmon_serveExecContainer_Params, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_serveExecContainer_Params(st), err +} + +func NewRootConmon_serveExecContainer_Params(s *capnp.Segment) (Conmon_serveExecContainer_Params, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_serveExecContainer_Params(st), err +} + +func ReadRootConmon_serveExecContainer_Params(msg *capnp.Message) (Conmon_serveExecContainer_Params, error) { + root, err := msg.Root() + return Conmon_serveExecContainer_Params(root.Struct()), err +} + +func (s Conmon_serveExecContainer_Params) String() string { + str, _ := text.Marshal(0x90a3950a51412b8b, capnp.Struct(s)) + return str +} + +func (s Conmon_serveExecContainer_Params) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_serveExecContainer_Params) DecodeFromPtr(p capnp.Ptr) Conmon_serveExecContainer_Params { + return Conmon_serveExecContainer_Params(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_serveExecContainer_Params) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_serveExecContainer_Params) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_serveExecContainer_Params) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_serveExecContainer_Params) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_serveExecContainer_Params) Request() (Conmon_ServeExecContainerRequest, error) { + p, err := capnp.Struct(s).Ptr(0) + return Conmon_ServeExecContainerRequest(p.Struct()), err +} + +func (s Conmon_serveExecContainer_Params) HasRequest() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_serveExecContainer_Params) SetRequest(v Conmon_ServeExecContainerRequest) error { + return capnp.Struct(s).SetPtr(0, capnp.Struct(v).ToPtr()) +} + +// NewRequest sets the request field to a newly +// allocated Conmon_ServeExecContainerRequest struct, preferring placement in s's segment. +func (s Conmon_serveExecContainer_Params) NewRequest() (Conmon_ServeExecContainerRequest, error) { + ss, err := NewConmon_ServeExecContainerRequest(capnp.Struct(s).Segment()) + if err != nil { + return Conmon_ServeExecContainerRequest{}, err + } + err = capnp.Struct(s).SetPtr(0, capnp.Struct(ss).ToPtr()) + return ss, err +} + +// Conmon_serveExecContainer_Params_List is a list of Conmon_serveExecContainer_Params. +type Conmon_serveExecContainer_Params_List = capnp.StructList[Conmon_serveExecContainer_Params] + +// NewConmon_serveExecContainer_Params creates a new list of Conmon_serveExecContainer_Params. +func NewConmon_serveExecContainer_Params_List(s *capnp.Segment, sz int32) (Conmon_serveExecContainer_Params_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz) + return capnp.StructList[Conmon_serveExecContainer_Params](l), err +} + +// Conmon_serveExecContainer_Params_Future is a wrapper for a Conmon_serveExecContainer_Params promised by a client call. +type Conmon_serveExecContainer_Params_Future struct{ *capnp.Future } + +func (f Conmon_serveExecContainer_Params_Future) Struct() (Conmon_serveExecContainer_Params, error) { + p, err := f.Future.Ptr() + return Conmon_serveExecContainer_Params(p.Struct()), err +} +func (p Conmon_serveExecContainer_Params_Future) Request() Conmon_ServeExecContainerRequest_Future { + return Conmon_ServeExecContainerRequest_Future{Future: p.Future.Field(0, nil)} +} + +type Conmon_serveExecContainer_Results capnp.Struct + +// Conmon_serveExecContainer_Results_TypeID is the unique identifier for the type Conmon_serveExecContainer_Results. +const Conmon_serveExecContainer_Results_TypeID = 0xdebaeed2a782ac80 + +func NewConmon_serveExecContainer_Results(s *capnp.Segment) (Conmon_serveExecContainer_Results, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_serveExecContainer_Results(st), err +} + +func NewRootConmon_serveExecContainer_Results(s *capnp.Segment) (Conmon_serveExecContainer_Results, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_serveExecContainer_Results(st), err +} + +func ReadRootConmon_serveExecContainer_Results(msg *capnp.Message) (Conmon_serveExecContainer_Results, error) { + root, err := msg.Root() + return Conmon_serveExecContainer_Results(root.Struct()), err +} + +func (s Conmon_serveExecContainer_Results) String() string { + str, _ := text.Marshal(0xdebaeed2a782ac80, capnp.Struct(s)) + return str +} + +func (s Conmon_serveExecContainer_Results) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_serveExecContainer_Results) DecodeFromPtr(p capnp.Ptr) Conmon_serveExecContainer_Results { + return Conmon_serveExecContainer_Results(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_serveExecContainer_Results) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_serveExecContainer_Results) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_serveExecContainer_Results) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_serveExecContainer_Results) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_serveExecContainer_Results) Response() (Conmon_ServeExecContainerResponse, error) { + p, err := capnp.Struct(s).Ptr(0) + return Conmon_ServeExecContainerResponse(p.Struct()), err +} + +func (s Conmon_serveExecContainer_Results) HasResponse() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_serveExecContainer_Results) SetResponse(v Conmon_ServeExecContainerResponse) error { + return capnp.Struct(s).SetPtr(0, capnp.Struct(v).ToPtr()) +} + +// NewResponse sets the response field to a newly +// allocated Conmon_ServeExecContainerResponse struct, preferring placement in s's segment. +func (s Conmon_serveExecContainer_Results) NewResponse() (Conmon_ServeExecContainerResponse, error) { + ss, err := NewConmon_ServeExecContainerResponse(capnp.Struct(s).Segment()) + if err != nil { + return Conmon_ServeExecContainerResponse{}, err + } + err = capnp.Struct(s).SetPtr(0, capnp.Struct(ss).ToPtr()) + return ss, err +} + +// Conmon_serveExecContainer_Results_List is a list of Conmon_serveExecContainer_Results. +type Conmon_serveExecContainer_Results_List = capnp.StructList[Conmon_serveExecContainer_Results] + +// NewConmon_serveExecContainer_Results creates a new list of Conmon_serveExecContainer_Results. +func NewConmon_serveExecContainer_Results_List(s *capnp.Segment, sz int32) (Conmon_serveExecContainer_Results_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz) + return capnp.StructList[Conmon_serveExecContainer_Results](l), err +} + +// Conmon_serveExecContainer_Results_Future is a wrapper for a Conmon_serveExecContainer_Results promised by a client call. +type Conmon_serveExecContainer_Results_Future struct{ *capnp.Future } + +func (f Conmon_serveExecContainer_Results_Future) Struct() (Conmon_serveExecContainer_Results, error) { + p, err := f.Future.Ptr() + return Conmon_serveExecContainer_Results(p.Struct()), err +} +func (p Conmon_serveExecContainer_Results_Future) Response() Conmon_ServeExecContainerResponse_Future { + return Conmon_ServeExecContainerResponse_Future{Future: p.Future.Field(0, nil)} +} + +const schema_ffaaf7385bc4adad = "x\xda\xc4Z}\x90\x14\xe5\x99\x7f\x9e\xee\x19z\xf6\x8b" + + "\xd9\xa6\x87\x80\xeb\xb2+_9\xd8\x84\x00\xae\x9e\x84\"" + + "\xc5.\xb0\xe1 `\xb6w@O\xb0<\x9a\x99fw" + + "`vz\xec\xeeaY\xa2\x87\x9a\xb3T\xcc\x19\xe1\xb0" + + "\x12\xa9\xa3\xca\xaf\x18!pJ\x92\xf5\x84@J\x88\xa9" + + "\x00\x91;\x97\x0b\x9e\xb1\xa2\x07\xe2&@\xa9\x11c\xea" + + "\xc0\x82\xeb\xab\xe7\xed\xe9\xeewgG2\xb3zu\x7f" + + "X\xec<\xfd\xeb\xe7}\x9f\xf7}\xbe~O;\xe3J" + + "eKhf\xcd\xf4Z\x10\xd4\x03\xe1\x11\x8eu\xba\xd7" + + "|v\xc7\xc2o\x83<\x11\x01\xc2(\x014_\x91\xde" + + "A@E\x8e\xcc\x05t\xfe\xfc\xcc\x91\xaf}o\xcb\x1f" + + "7\xf3\x80\x99\x11\x06hc\x80\xdf\xcdjZ\xf3\x84\xb8" + + "\xe4a\x1e\x90\x8a\xbcI\x80\xbb\x19\xe0\xefWE\xb7\xfd" + + "\xd3\x17V2\x80s\xa1y\xcd[\x8f\x9f\xbd\xe9_!" + + ",\x11pG\xe4MT\xf6E\xe8\xcf\xbe\xc8w\x11\xd0" + + "y\xf8K\xadj\xe5cO?\xca\xab{\xac\xf2<\xa9" + + "\xdbYI\xea~\xdd\xb0\xf1\xd6\xe8\xb3\x0f|\xbf@\x1d" + + "\x03\x1e\xad|\x07\x95\x81J\x09@9\xcd\xc0\xf7\x9f\xbb" + + "\xf9\xc5\xe5\xdf\xfe\xe3\x13\xbc\xb6\xd1U\x1f\x91\xb6\xa9U" + + "\x04x|\xe5\xd9um\x8b\xa2O\x0d\xd6\x16\"\xdc\xd2" + + "\xaa]\xa8\xe8U\x12\x88\xce\x17>9\xf3\xcc\xeb\xf1Y" + + ";A\x9d\x88C\x16m%\xdcmU\xb4\xe8\xf2\xaa\x1e" + + "@\xe7\xc6\x9e\xbd]\x1f\xcd9\xb7\xb3\xd8\x0e\xf7V}" + + "\x84\xcaq\x06>\xca60\xe9\xf9_\xf4o\x9e3}" + + "\x17\xbf\xc3sU'h\x87W\x18`\xf3\x0f\xf5\xbf:" + + "\xb4\xff\x1b\x04\x10\x02m\x80\xcd\xe3\xaa7\xa3rc5" + + "\xa9\x9aY}\x13\xa0\xd3\xb3\xea\xc8\xf3\x1b\xd5\x81\xddE" + + "l\xf9j\xf5VT\xd4j\xb2EY0c\xdf\xeb\xcd" + + "M{\x0am\x11\x087\x8dpmLgk\xf5\xf3\x80" + + "\xce\x0dO\xfe\xe4\xc5G>\xd8\xf0/\x84\x16\x0a\x8d\xb9" + + "P\xbd\x16\x95p\xcd\x18\x00\xa5\xa6\x86\xd0\xdf\xea?\xff" + + "\xdc#\x0f\xb7\xf6\x15\xea\x16\x09\xfd\x83\x9a\xc3\xa8\x1c\xac" + + "\xa1?\xf7\xd54\xd2]\x8b\xa7\xde\xad|\xa4u\xfa\x8b" + + "\xc5\x0e\xea\xf4\xc8c\xa8\\\x19I;\xb94\x92\xce\xc1" + + "\x7f.\xd7\x8b\xce\x9e=\xaf\xac\x9c\xf5\xdf\xbb\x1c:\x87" + + "k\xa2u\xd8<5\xda\x83tr\xb5\x0b\x05\xe5\xfeQ" + + "\x12\x803\xf5\xbd\x07\x9f}\xe0G\xf1\xfd\xc5\x94w\x8f" + + ":\x8c.L\xb9w\x14)?\xf6\xe2\xce\xd9\x9f\x9c\xe9" + + "\xd9_\xb8q\xb6\xdb\xbeQ'P\xe9't\xf3\xf1Q" + + "\x0f\x88\x80N\xed\xca\x7f\xff\xda{w\xfc\xfe\x97\xfc\xa5" + + "\xb5\x8ea>\xbf|\x0c\xe9\xfb\x83\xf63\xa1\xedx\xfa" + + "W<\xa0wL\xa5\x00\xa8lq\x01\xef\xfe\xcf\xda\xce" + + "\xec\xf4Wy\xc0\xde1[I\xc3!\x06XWu$" + + "V1\xd7\xfa7\x1epz\xcca\x02\\`\x80\x8b\xa3" + + "\x7f\xfe\xbd\xba9\xfb\x07\x01\xe4\xb1l\x0f\x93\xc7\x12`" + + "|\xfd\xef\xef5S\xf5\xaf\x15\xbd\x8cEc\xcf\xa3\xa2" + + "\x8f\xa5?\xb5\xb1,\xf0\xeaZ\xfbo\x88f\x16\xbeV" + + "p^\x0c]S\xf7\x14*\x93\xeb\xe8\xbc\xc6\xd7\xd1E" + + "?\xfd\xa7\xe7V\xf5m\x89\xbd>\xc4)\xfb\xeb\xd6\xa2" + + "2\xc0\x90\xa7\xeb6\x01:\x97\xef\x9fs\xcf\xb8q\xaf" + + "\xff\xb6\xa8\xbb\x8d\xbe\xf6<*3\xaf%\xf4\xb4k\xff" + + "\x00\xe8l\xffRO\xf6\x8e\xd5\xb3\xdf.@3\x1f\xae" + + "\xa8\x7f\x13\x95\xc9\xf5l\x13\xf5d\xe0=\xbb\xef\xfb\xe1" + + "\x89\x0f\xf6\xbf\xcd\x9f@[=\x0b\xee\xdb\x18\xe0\xf2\xec" + + "\xcb?\x7fbN\xf6\xbf\x0a\xd7\x0e\x13\xf2\xee\xfa\xcd\xa8" + + "\xd1p\x93\x00\xe8<{\xe7\xd3\x8f^\x9c " + + "\x7f\\\x18\xa7\xcc\xd4\x1b\xc7\xbf\x83\x8a:\x9e%\xb5\xf1" + + "\xbf\"S_\xda\xbe\xed\xbb\xaf\\\xbf\xf0c~\xa3\xcb" + + "'\xb2\xac\x93\x9aH\x1b\x1d\xfdw\xf7\x9ej:wf" + + "\x10\xe0\xa1\x89\xc7\x08\xb0\x83\x01\x0e\xe0\xae\xaa\xdb\xd7\x9e" + + "\xbd\xc8\x03\x0eMd\xa6\x9ed\x80\x8bO\xfe\xa8\xf9\x9e" + + "\xe3?\xb9T$\x1b]\x9ax\x0c\x95\xd1\x93(\x1bm" + + "\xfd\x8f\xc5\xddo_\xf9\xd9'\x05^\xc7\xbc\xe3\xc2\xc4" + + "\xa7P\xa9\x98Dg\x12\x9e\xd4\x03\xd3\x9cT\xc6\xd6\xcd" + + "\x8c\x96\x1e1=k\x1a\xb61=ad\xba\x8d\xccW" + + "\x12Z6\x93\x9d=\xdf\xfd\xa1o\xd0\x13\xf1\xdeLb" + + "\xbe\x91\xb1\xb5TF7'\xb5k\xa6\xa4u[jH" + + "\x0c\x01\x84\x10@\xae\x99\x07\xa0FDTc\x02n2" + + "\xf5;s\xbaecmp\x86\x80X\x0bX\xd2r\x09" + + "S\xd7l\xfdf\xad[\xb7\xb2ZB\xb7&u\xe8V" + + "NJ\xdb\x83\x96[\x0c\xa0V\x8b\xa8\x8e\x15\xd01u" + + "+kd,\x1d\x00\xb06(f\x9fe\xc9v\xcd\xd4" + + "\xc4R\x0c\xf4+q\x19\xab\xcd/X\xad\x83\xb4\x89\x96" + + "\xdd\x8e\xa8\xd6\xfb\x0b\xf6\xad\x06P\x7f*\xa2\xfa\xb2\x80" + + "2b\x0cIxp\x05\x80z@D\xf5\x0d\x01eA" + + "\x88\xa1\x00 \x9f$\xe4oDT?\x14P\x16\xc5\x18" + + "\x8a\x00\xf2\xfb$|O\xc4x\x04\x05\x94C\xa1\x18\x86" + + "\xe8\xd2q1@<\x84\"\xc6kI\x1e\x0e\xc70L" + + "\xb5\x06\xaf\x07\x88GH\x1e#\xf9\x88\x111\x1c\x01\xa0" + + "\xc8\x0c_K\xf2/\xa3\x80N\xb7nkI\xcd\xd6@" + + "\xfaf:\x895 `\x0d\xa0\x93\xc9\x9b\x02\xa2n\xe1" + + "H\xc0v\x111\x1a$4@\x12:\xb9Tr\xa9\x96" + + "\xcd\xa6@\xcat\xfa\xb0j\x10\xd8\xc3\xce\xab=\\\xad" + + "Yz\xbbfw\xd1\x05\x93\xac\x1a\xb01k$\x17%" + + "\xbd_\xc1\xbe\x00\xbc\x97k\x83@\xc8o\xa0\x94\xbb\xb1" + + "ts\xbd\xde\xb6A\x1f\xe4\xecQ\xb3$g\xf7\xab\xc3" + + "g\xf2\x05+kH\x19K'g\xe0V\\\x91\xf7\xf7" + + ")B\xf1\xe3\xae\x0d\x1a\xaa2\xac5u#\xabg\x96" + + "\x18\x9d\x81\xb5\x1dz\xa3\x95+9\xd8\xfc^\xaf\xc0\xe4" + + "\xf0U\x16\xed\xf0\x16%[\xa3\x86kkIo\xfa\xc7" + + "\xc4\xbf\xa9F\xfc\x8dNm\x02P'\x89\xa8\xce\x10\xd0" + + "\x8b\x98i$\x9b\"\xa2z\x83\x80Q\xbb7\xab\x17x" + + "f\x140\x9a\xd5\xec.\xdf\x95J9\xb7\xf8\x10/\xe9" + + "\xd0\xad\xc6\xac1\xf4\xde&\x04\x9e\"\xe5\xcctY\xab" + + "h\xb6\xad%\xba\x06e]\xad\x1bKpD\xbfH\x97" + + "q+\xf3;M#\x97]\xaae\xb4N\xdd\x04`\x07" + + "\xcb\xb2\x8b<\x8f\xd4\xc8\x15\x8b\x016Y\xbd\x96\xadw" + + "'\x9d\x04\x03\xaf\xb1\x00\xa0$\xe5\xad\xcc\x92\x0e\xd7u" + + "\xb0\xe4\xfb\xbeE7\xad\x94\x91a\xf9\xd1B\x96\x1f\xab" + + "}\xdb\xdb\xc8\xf6\x16\x11\xd5%\xc1e/\xa2\xa4\xf77" + + "\"\xaa\xcb(=\xa2\x9b\x1eUr\xdfv\x11\xd5\xb4\x80" + + "\x9b\xd6\xeb\xe6j\xc3\xd2\x11A@\x84OKhe\xa5" + + "\x93\xd0U,Xbt.0\xa3\xa9\xf5\xba\xa9\x86\x90" + + "\xefU\xb0)\xba\xac7\xab\xf3\xf64\x15\xb1\x87d\x0b" + + "DT\xdb9{\x96\xce\x0b\x8c\xf4<\xdaW\\\xc4\xa3" + + "7uk\x1b\xe2\xa9\x8d:V\x80\x80\x15%{\xb8}" + + "k*\x934z\xe8M\xf7\x02l\xe6\x141\x7f\xc3w" + + "\xd7\x01\xa8\x1bDT\xff!\xd8\xf0\xbd\xd7\x03\xa8w\x89" + + "\xa8>\xc8m\xf8\xfe\xd9\x00\xea=\"\xaa\xdf\xa1\xfa\x84" + + "n}z\x88\xae\xeaA\x11\xd5mT\x9e\x04V\x9e\xe4" + + "-tU\x8f\x8a\xa8\xee\x16PL\xf9\xe9\xbd\xb1'\x95" + + "\xb4\xbbP\x02\x01%\xc0\xb9]z\xaa\xb3\xcb\xf6~~" + + "\x1eWx\xd5\x93\xb05\xd3\xfez2n$\xd6\xe9v" + + "\x87\x9f\xfd\x0a\xe2\xbc)\x08\xc4\xe2\xe9D\xfc\xb4%D" + + "#\xa3\xde\x8e\x18\x90Hy\xef\xc6\xa0U\x95\xf7\xde\x17" + + "0)y\xef\xfe\xa0\xc3\x95\xfb:8\"\xdbg\x06\x8d" + + "\xbe\xdcw8h\xbc\xe4}\xc7\x02\xc2 \x1f:\x11$" + + "\x07\xf9\xa8\xc9\xf1\xdb\xa3\x1b9\xbart3\xc7\xe2\x8f" + + "o\x0dH\xa8\xdc\xbf\x8b\xebBO\xfe\x98\x9bD\xfc\xf6" + + "0Ga\xde\xea\xe0\x86\x0ao\x1d\x0b\x8a\x93<\xb0\x95" + + "\xa3\x91\xe7vq\x84\xf5\xfd\x1fs\xad\xeb\x85\xcdA9" + + "\x95\xff|\x82\x1b\x00\\y\xd3\xf1\xf2\x02\xccu\x1d\xd3" + + "\x17\x88\xde\xf5\xb8e5\xc8\xce\x1e\x90\xc5cj\xbd\x0e" + + "h:^\xc6\x83F\x96\xf3\x1c\xef\x9dp\x90\xd2]e" + + "m\x85\xfd\xaf\x17\x0f\xe0x\x8f\x04\xbe\x10\xb8I\xce\xf1" + + "\x92\x1e4\xbak\xfb\xbf\xe7\xbaz\x1d\xaf\x10bg\xa0" + + "\x90\x97y\x8a\xbcXD/\x18\xa3L_\xa18_\x80" + + "\x1c\xaf\xa5\x10\x07\xf5\x97\x96\x0d^\xf9\xc4\x00#\x0c\xea" + + ";\x98c;\x01\x8c\xdbB>\x080\x1f\x05\xde\x16\x0a" + + "\xc4\xde\x16\x96\xe9\x1bl\xfa\x0f\x97j\xd9\xb6\x8cm\xf6" + + "\x028^\xcd\x14\x0a\xcf\x11\xed\xe2\xcfhm\xd1\xd2\xd5" + + "Ib\x18\xc0g\xf7\xe81FE\xc6y (a\x94" + + "0 _\xe8Qx\xf9\xd2} \xc8\x17$\x14\xfcy" + + "\x1cz\xfcJ\x1e\xd8\x0a\x82|ZB\xd1\x1f\x15\xa17" + + "~\x90O\xd2{\xc7%\x0c\xf9\xcc\x13\xbd\x89\x97|h" + + ";\x08\xf2A\x09\xc3\xfe0\x02=\x82+\xef\xdd\x0f\x82" + + "\xbcG\xc2\x11\xfe\xf4\x0e\xbd9\x9f\xfc\xe4f\x10\xe4\x1d" + + "\x12J\xfe\x08\x02=2(o1A\x90\x1f\x920\xe2" + + "\x8f\xe9\xd0#\xe1\xf2\xdd\xb4^\xafDE\x8b\xdc\xbb\x05" + + "\x9dD\xdeG1\x7fJ\xd0\x82\x8eG\xcf\xd0;;4" + + "[\xd0\xf1\x9a\x07\x1ei\xfa\xce\x95\x87\x8a:A\xadA" + + "\x8e4\xdf\xc8\xccu_\xf1\xd7\xbbYC\xcfO\x80\xf4" + + "X\xf9k\x87Fv\xefL\x85{\x81\x98\xe05\xf3u" + + "\xbe\x8c\x14\x1b\x14\x9b\"=\xe8\x14\xe1s\xcc\xed\x85i" + + "\x82k4Z\xbc\xa5\x95\xbdX\x07\x10\xdfM\x1c\xe8%" + + "\x0c\xb8\x98\xd2\x87+\x00\xe2?%\xf9\xcb( \xbal" + + "L9\xc8(\xd3\x01\x12\x1f\xc1\xa0\xe0)\xbfd\x14\xeb" + + "e\x92\xbf\x8aA\xcdS\x8eb\x07@\xfc\x08\xc9\xdfe" + + "\x94Lt)\xd9i\\\x0b\x10?E\xf2\xcb\x8c\x92\x85" + + "\\Jv\x89-{\x91Q5A@Y\x0a\xc7\x90\xf8" + + "\xbc,\x90\xbcV \xaaF\xf2\xc8\x88\x18F\x00\x94\xa9" + + "L>\x85\xe4\x0bH^!\xc5\xb0\x02@i\x15V\x03" + + "\xc4[H~;\xc9+#1\xac\x04Pnc\xf2\xbf" + + "%y\x92\xe4U\x151\xac\x02P4\x81\xecZE\xf2" + + "\xbbH^]\x19\xc3j\x00\xa5W\x98\x07\x10\xb7I\xfe" + + "(\xc9k0\x865\x00\xca?\x0a&@\xfc;$\xff" + + ">\xc9GV\xc5p$\x80\xf2\x18\x93o#\xf9\x0b$" + + "\x8fV\xc70\x0a\xa0\xecaz\x9e#\xf9+\xc2\xa0\xf2" + + "\xef\xac\xcee\x92i\xbd]\x03\x91+\xac\xb6nv\xa7" + + "2Z\x9a\x9c \xdf\xcd5Zv2\x95\xf1{;}" + + "C\xcaf\xb4\x11\x870J\xc3\xe8n\xa3\xa7\x10\xd5\xec" + + "\xae!O\xd3^\x95\x10M\x8e`q\xb3%\x86J\xa4" + + "u-\x93\xcb\xce\x07\xb1;9\x84\xce\xa6\x8d\xd5Z\xba" + + "\xd5\x04q(\x9bM\x18\xdd\xddZ&\xd9\x0a\x929\xf4" + + "\xe1\xf0\x9b\x99Mzf\xfd-\x1a\xbf\xe1\xc2\x88H\x0c" + + ".x\x18\x0d\xfa\x07\xb7mt\xb4d2e\xa7\x8c\x0c" + + "4j\xe9\xaf'}U\x15\xee\xe66\xa5um\xddP" + + "\xf1\xb0\xb8L\x87n\xe5\xd2b\xa94\xd3oS\x0a\x08" + + "\x8dtU&\xcfu\xb0\x05$\xca\x02\xf8\xcb,\xcao" + + "z\xca`Q\xf9L]:U\xf3\xbb\xbe2f\x06\x16" + + "\x9f.=\x83\xfe\xf2R~\xdbU\xf6`l\xb8\xd7\xe6" + + "w\xa4e\xacX\x8cZ\xbb\xddF\xc1xlq~<" + + "\xf6\x1a7\x1e;N\x94\xe4\x88\x88\xeao\xb8\xf1X?" + + "q\xf0WET\xcf\x0a\x88\xf9\xe9\xd8\x00\xc9N\x89\xa8" + + "\xbeG\x99\x18]\xf6q\x8e\xc8\xcb\xbb\xf99ZX`" + + "iX~\x9f\xc8\xcbY\x11\xd5\x8f)\x07\x8b,\x07\xcb" + + "\x17f\xbb\xc35\xf5b\x89\xd5\x88\xcbfRbH\xba" + + "\x90l\xbb\xb7x\x0e\x9bk\xd9I#g\xf3?u\xd3" + + "\xf43\\\x99\xe3\x96;sR\xfe\x1c9\xdaY\x17\xd0" + + "N\xb98\x8f\x16\x86\xf2h>;\xff\x1fSh\xd6\x8e" + + "F\xa9\xf9`\xf4\x93m\xe5\xc6\x09l&1\x8d\xfe\x11" + + "\xe4\xc9\xf4\x8f(\x8fk\x02\xc0\x90" + + "\x99\xa9`l\xc3\xff\xd0\xe3q\x19\xe2\xd2\x10\xaf&\xf1" + + "X\x0c\xb2\x972\x1a'x\xdf\x7f\xea\x19\x99\x11\\2" + + "s\x0d\xce\x06\x88\xc7H~\x1d\x06\xe1\xa0\x8cc\xea\xeb" + + "I>\x05\x83\x88P&3\xfcu\xdew$yD\xd8" + + "%3S\x91\xc8\xc6\x14\x92\xdf@ri\x84Kff" + + "2\xf23\x83\xe4sH\x1e\x91\\2\xf3U\xa6\x7f\x16" + + "\xc9\x17\x90\xbc\"\x92'3\x8ct\xb5\x90|\x09\x0a\xe8" + + "dM#\xa1[\xd6\"@?gy,\xda\xaf\xc3\xb6" + + "\xd6\xe9\xfd=\x97z\xf2\x94\xcd\x11\x8eT:\xb9@\xb3" + + "\x01u\x1fbkf\xa7\x1e@\xcc\x9ce\xd3Q\x83\xc4" + + "\xe9t\x12\x9a\xd9i\xdc\xa2\x9b\x10\xb5\x86\x88\x97\x99:" + + "\xa7oP\xb4z\x11<\xcc\x0a\x15\xd4\xf5\xeb|\xdf\xed" + + "\xaf\xcbw=o\x04\x05\xea\xe4\x8a\xfc\x87\xc2S\\\x81" + + "z\x8b\x9c\xfc\x8d|\x83#\xb6\xb8\xb9\xee\x02E\xdb\x87" + + "\"\xaa\x97\xb9\xe9\xec%\xcau\x17E\x8c\x87x\x9e\x8a" + + "t\xf4\x1d\xbe\x87x4\xf5\x1a\xe6Q\xccCf G" + + "S\xa7!\xd1\xbf/\x93|\x16\x0eN\x8f\xe4\xf1F\xce" + + "\x8e\x83\xa8'\xbca\xf5\xa6<[*\xe4IE\xd8\xdf" + + "\xff3w\x1aN;]2M\xf0G\xc0\xc3\xa6\x09n" + + "\xf2. >\x9f\x9eS\xfd\xb1l\x19\x0b\x0e\xfd\xff\x04" + + ":t+Zz\xbd\xf7\xc7\xd4e\xd1\x85A\xdf)\xb8" + + "\xe9|I\xc9\xd2\x1bT\xb29\xa5d\x9b\xbd\x05\x1f\x14" + + "'\x04\x1f\x14\xfd\x86a\xda\xf5\xc1\x17Ei\x9d\xde\xeb" + + "\x7f\xa5X\xaf\xa5s~|\xffo\x00\x00\x00\xff\xff2" + + "\xa3T>" func RegisterSchema(reg *schemas.Registry) { reg.Register(&schemas.Schema{ @@ -4793,10 +5286,12 @@ func RegisterSchema(reg *schemas.Registry) { 0x8aef91973dc8a4f5, 0x8b4c03a0662a38dc, 0x8b5b1693940f607e, + 0x90a3950a51412b8b, 0x9887a60f577a1ecb, 0xa0ef8355b64ee985, 0xa20f49456be85b99, 0xa93853d6a4e3fa16, + 0xa9e93cf268b17735, 0xaa2f3c8ad1c3af24, 0xaa4bbac12765a78a, 0xace5517aafc86077, @@ -4812,10 +5307,12 @@ func RegisterSchema(reg *schemas.Registry) { 0xcc2f70676afee4e7, 0xce733f0914c80b6b, 0xceba3c1a97be15f8, + 0xd01c697281e61c21, 0xd0476e0f34d1411a, 0xd61491b560a8f3a3, 0xd9d61d1d803c85fc, 0xde3a625e70772b9a, + 0xdebaeed2a782ac80, 0xdf703ca0befc3afc, 0xe00e522611477055, 0xe313695ea9477b30, diff --git a/pkg/client/client.go b/pkg/client/client.go index 0927d423ec..fe463cc606 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -1274,3 +1274,95 @@ func mappingsToSlice(mappings []idtools.IDMap) (res []string) { return res } + +// ExecSyncConfig is the configuration for calling the ServeExecContainer method. +type ServeExecContainerConfig struct { + // ID is the container identifier. + ID string + + // Cmd is the command to be run. + Cmd []string + + // Tty indicates if a tty should be used or not. + Tty bool + + // Stdin indicates if stdin should be available or not. + Stdin bool + + // Stdout indicates if stdout should be available or not. + Stdout bool + + // Stderr indicates if stderr should be available or not. + Stderr bool +} + +// ServeExecContainerResult is the result for calling the ServeExecContainer method. +type ServeExecContainerResult struct { + // URL specifies the returned URL. + URL string +} + +// ExecSyncContainer can be used to execute a command within a running +// container. +func (c *ConmonClient) ServeExecContainer( + ctx context.Context, + cfg *ServeExecContainerConfig, +) (*ServeExecContainerResult, error) { + ctx, span := c.startSpan(ctx, "ServeExecContainer") + if span != nil { + defer span.End() + } + + conn, err := c.newRPCConn() + if err != nil { + return nil, fmt.Errorf("create RPC connection: %w", err) + } + defer conn.Close() + + client := proto.Conmon(conn.Bootstrap(ctx)) + future, free := client.ServeExecContainer(ctx, func(p proto.Conmon_serveExecContainer_Params) error { + req, err := p.NewRequest() + if err != nil { + return fmt.Errorf("create request: %w", err) + } + if err := c.setMetadata(ctx, req); err != nil { + return err + } + if err := req.SetId(cfg.ID); err != nil { + return fmt.Errorf("set ID: %w", err) + } + + if err := stringSliceToTextList(cfg.Cmd, req.NewCmd); err != nil { + return fmt.Errorf("convert command to text list: %w", err) + } + + req.SetTty(cfg.Tty) + req.SetStdin(cfg.Stdin) + req.SetStdout(cfg.Stdout) + req.SetStderr(cfg.Stderr) + + return nil + }) + defer free() + + result, err := future.Struct() + if err != nil { + return nil, fmt.Errorf("create result: %w", err) + } + + resp, err := result.Response() + if err != nil { + return nil, fmt.Errorf("set response: %w", err) + } + + url, err := resp.Url() + if err != nil { + return nil, fmt.Errorf("get url: %w", err) + } + + serveExecContainerResult := &ServeExecContainerResult{ + URL: url, + } + + return serveExecContainerResult, nil +}