Skip to main content

ContainerIO

Struct ContainerIO 

Source
pub(crate) struct ContainerIO {
    terminal: Option<Terminal>,
    logger: Arc<Mutex<ContainerLog>>,
    attach: SharedContainerAttach,
    stdout: StdioChannel,
    stderr: StdioChannel,
    consumed: Arc<AtomicBool>,
    collector: Mutex<Option<StdioCollector>>,
}
Expand description

The stdio of a container or exec, a terminal or pipes, and the log drivers and attach endpoints its output goes to.

Fields§

§terminal: Option<Terminal>

None for a process with pipes.

§logger: Arc<Mutex<ContainerLog>>§attach: SharedContainerAttach§stdout: StdioChannel

The stdio channels, see StdioSender. A terminal merges stderr into stdout, its stderr channel ends right away.

§stderr: StdioChannel§consumed: Arc<AtomicBool>

Whether a consumer reads the stdio channels, see StdioSender.

§collector: Mutex<Option<StdioCollector>>

Collects the output of an exec while its runtime runs, see ContainerIO::collect_stdio. Taken by the consumer of the output, which shares the IO with others already.

Implementations§

Source§

impl ContainerIO

Source

pub(super) const IDLE_FLUSH: Duration

How long a line without its ending waits before it is written as a partial one, so that prompts and progress output show up in the logs.

Source

pub(crate) fn connect_streams( &mut self, stdin: Option<ChildStdin>, stdout: Option<ChildStdout>, stderr: Option<ChildStderr>, token: CancellationToken, )

Read the pipes of the runtime, which the process it starts shares.

Source

pub(crate) async fn connect_terminal( &mut self, stdin: bool, token: CancellationToken, ) -> Result<()>

Wait until the runtime connected the terminal and read it. A wait which gets dropped leaves the connection for the next one.

Source

pub(super) fn spawn_read_loop<T>( &mut self, reader: T, pipe: Pipe, output: Arc<AttachOutput>, )
where T: AsyncRead + Unpin + Send + 'static,

Spawn the ContainerIO::read_loop of a pipe, which takes the sender of its stdio channel.

Source

fn spawn_stdin_loop<T>(&self, writer: Option<T>, token: CancellationToken)
where T: AsyncWrite + Unpin + Send + 'static,

Spawn the ContainerIO::read_loop_stdin of the process. Without a stdin, attach clients must not wait for one which nothing ever reads.

Source

pub(crate) async fn read_loop<T>( reader: T, pipe: Pipe, logger: Arc<Mutex<ContainerLog>>, message_tx: Option<StdioSender>, attach: SharedContainerAttach, attach_output: Arc<AttachOutput>, ) -> Result<()>
where T: AsyncRead + Unpin,

Read the pipe until it ends and let the log drivers write what they still buffer, however the loop ended.

Source

async fn read_pipe<T>( reader: T, pipe: Pipe, logger: &Arc<Mutex<ContainerLog>>, log_has_drivers: bool, message_tx: Option<StdioSender>, attach: &SharedContainerAttach, ) -> Result<()>
where T: AsyncRead + Unpin,

Source

async fn read_chunk<T>(reader: &mut T) -> Result<Bytes>
where T: AsyncRead + Unpin,

Read a chunk of up to READ_BUFFER_SIZE into the scratch buffer of the thread, see with_scratch, and copy it out. Empty once the output ended.

Source

async fn closed(message_tx: Option<&StdioSender>)

Complete once the stdio channel got closed, never without one.

Source

async fn forward(message_tx: &mut Option<StdioSender>, message: Message)

Forward a message to the stdio channel, see StdioSender. If the channel got closed or all receivers are gone (see ContainerIO::drop_stdio), the sender is dropped as well so that the channel buffer gets freed and no further sends are attempted.

Source

pub(crate) async fn read_loop_stdin( writer: impl AsyncWrite + Unpin, attach: SharedContainerAttach, token: CancellationToken, ) -> Result<()>

Write the stdin of the attach endpoints to writer until they closed it or the process exited, which cancels token.

Source

async fn forward_stdin( writer: impl AsyncWrite + Unpin, attach: &SharedContainerAttach, ) -> Result<()>

Source

async fn handle_stdin_data( data: &[u8], writer: impl AsyncWrite + Unpin, ) -> Result<bool>

Write attach input to the stdin of the process, false once that got closed, which ends the stdin like its EOF. A pipe reports EPIPE once the process exited or closed its stdin. A terminal reports EIO only once nothing has it open, see connect_terminal, otherwise its writes block once its buffer is full, until the exit ends the stdin, see read_loop_stdin.

Source§

impl ContainerIO

Source

pub(crate) fn stdio(&self) -> Result<(Receiver<Message>, Receiver<Message>)>

Retrieve clones of the stdout and stderr channels.

Fails if the channels have been dropped via ContainerIO::drop_stdio.

Source

fn receivers(&self) -> Result<(&Receiver<Message>, &Receiver<Message>)>

The stdout and stderr receivers, see ContainerIO::stdio.

Source

pub(crate) fn drop_stdio(&mut self)

Drop the stdout and stderr channels.

The channels buffer the last chunks per pipe for consumers like exec_sync, which may start reading after the process already produced output, and for reporting the runtime’s stderr if a create fails. Once a container is created nothing consumes them anymore, attach sessions use the attach broadcast, so they get dropped, see StdioChannel::close.

Source

pub(crate) fn collect_stdio( &self, stdout_enabled: bool, stderr_enabled: bool, ) -> Result<()>

Read the output of an exec from now on, until it gets taken with ContainerIO::take_early_stdio once its runtime finished. The process may write a lot before, which the channels alone would drop, see StdioSender. A runtime without a terminal shares the pipes, so the reads must not wait for anything: they apply backpressure, but take everything up to ContainerIO::MAX_STDIO_STREAM_SIZE per pipe and drop what follows.

The output of a pipe which is not of interest gets read and dropped.

Source

pub(super) async fn collect( receiver: &Receiver<Message>, stop: &CancellationToken, enabled: bool, ) -> EarlyStream

Collect the output of a channel until stop, the remaining messages stay queued for the consumer which comes next. Beyond the size limit the output gets read and dropped.

Source

pub(crate) async fn take_early_stdio(&self) -> EarlyStdio

The output collected since ContainerIO::collect_stdio, empty without that.

Source

fn consume_stdio(&self)

Apply backpressure to the read loops from now on, see StdioSender.

Source

pub(crate) async fn runtime_error(&self, e: Error) -> Error

Attach the stderr output of a runtime which failed to its error. With a terminal, the error carries it already. The read loops get stopped afterwards, a process which the runtime left behind, like a daemon of the process it started, may keep the pipes open, see SharedContainerAttach::stop_output.

Source

pub(crate) async fn read_all( &self, exited: &CancellationToken, ) -> Result<(Vec<u8>, Vec<u8>)>

Read the output until it ended. Once exited got cancelled, the output still in flight is taken as long as the Drain does. A background process which holds the pipes open must not keep this waiting. The channels get closed afterwards, so that the read loops discard what follows. There is no deadline of its own: the watcher of an exec cancels exited also when it kills the process at its timeout, and a deadline which raced that one would end the output of a process which exited right at it.

Source

async fn read_all_with_early( &self, exited: &CancellationToken, early: EarlyStdio, ) -> Result<(Vec<u8>, Vec<u8>)>

Read the output after the one collected before, see ContainerIO::read_all.

Source

pub(super) async fn read_stream( exited: &CancellationToken, receiver: &Receiver<Message>, early: EarlyStream, ) -> Vec<u8> ⓘ

Read a stream, after the early output collected before.

Source

async fn next_message( receiver: &Receiver<Message>, drain: Option<&mut Drain>, ) -> Option<Message>

The next message, bounded by the drain once the process exited. None once the output ended or the drain gave up, a closed channel ends the output as well.

Source§

impl ContainerIO

Source

pub(crate) fn terminal(&self) -> Option<&Terminal>

The terminal of the process, none with pipes.

Source

pub(crate) fn logger(&self) -> &Arc<Mutex<ContainerLog>> ⓘ

The log drivers which get the output.

Source

pub(crate) fn attach(&self) -> &SharedContainerAttach

The attach endpoints of the process.

Source

pub(crate) fn resize(&self, width: u16, height: u16) -> Result<()>

Resize the terminal. Errors in case of no terminal containers.

Source

pub(crate) fn try_resize(&self, width: u16, height: u16) -> Result<bool>

Resize the terminal if the container has one and return whether it does. One which the runtime did not connect yet gets the size once it does, see TerminalResizer::resize.

Source

pub(crate) fn terminal_eof(&self) -> Option<u8>

The end of file character of the terminal, none without one.

Source§

impl ContainerIO

Source

pub(crate) const MAX_STDIO_STREAM_SIZE: usize

The most output of a pipe an exec collects while its runtime runs, see ContainerIO::collect_stdio, and the most an exec_sync reads of each pipe.

Source

pub(crate) fn new( terminal: bool, logger: Arc<Mutex<ContainerLog>>, ) -> Result<Self>

Create a new container IO instance.

Trait Implementations§

Source§

impl Debug for ContainerIO

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FutureExt for T

§

fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
§

fn with_current_context(self) -> WithContext<Self> ⓘ

Attaches the current Context to this type, returning a WithContext wrapper. Read more
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> IntoRequest<T> for T

§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
§

impl<L> LayerExt<L> for L

§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in [Layered].
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more