diff --git a/go.mod b/go.mod index beb56e6f..45325b15 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/containerd/log v0.1.1-0.20260403072107-cb1839ebf76b github.com/containerd/otelttrpc v0.1.0 github.com/containerd/plugin v1.1.0 - github.com/containerd/shimtest v0.3.0 + github.com/containerd/shimtest v0.3.3 github.com/containerd/ttrpc v1.2.9 github.com/containerd/typeurl/v2 v2.3.0 github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c diff --git a/go.sum b/go.sum index 6207b679..1e645818 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ github.com/containerd/platforms v1.0.0-rc.4 h1:M42JrUT4zfZTqtkUwkr0GzmUWbfyO5VO0 github.com/containerd/platforms v1.0.0-rc.4/go.mod h1:lKlMXyLybmBedS/JJm11uDofzI8L2v0J2ZbYvNsbq1A= github.com/containerd/plugin v1.1.0 h1:O+7lczNJVMy8rz0YNx3xGB8tTf5qY4i5abF041Ew19U= github.com/containerd/plugin v1.1.0/go.mod h1:qBTum+A8lJ6lO44A19Eo7y1OlcLj4OWFH1DA/vnHmcc= -github.com/containerd/shimtest v0.3.0 h1:oTtRnAEA20cqqxU68Jpg6fajUVXtUYI38Q1Z/shv70k= -github.com/containerd/shimtest v0.3.0/go.mod h1:v9b7phlmKrfn9zKHqhDyoe0kv24mxDEYyJlXFcFhjnI= +github.com/containerd/shimtest v0.3.3 h1:n0bG1i5baAjrtFWtPySjIiDICq7Gmh50hhjvVkYUktU= +github.com/containerd/shimtest v0.3.3/go.mod h1:vT0DHiGsMJ6Hi56uGZLWS3o8gzRd0wSCC17Wen3XjP4= github.com/containerd/ttrpc v1.2.9 h1:ha0ak962T0s3CA/RoZ6S6xiWZQF24GrBaEpiGX1uihg= github.com/containerd/ttrpc v1.2.9/go.mod h1:jjtQRwXm4DL3KsHKW8vDiUOV6wO0hi6IPhmJhxU7aEs= github.com/containerd/typeurl/v2 v2.3.0 h1:HZHPhRWo5XMy3QGQoPrUzbW/2ckwjfweHmOwlkIrPAQ= diff --git a/internal/shim/task/io.go b/internal/shim/task/io.go index 49807eb9..1034bece 100644 --- a/internal/shim/task/io.go +++ b/internal/shim/task/io.go @@ -32,6 +32,7 @@ import ( "github.com/containerd/containerd/v2/pkg/stdio" "github.com/containerd/errdefs" + "github.com/containerd/log" ) type streamCreator interface { @@ -105,11 +106,25 @@ func (s *service) forwardIO(ctx context.Context, ss streamCreator, idPrefix stri } }() ioDone := make(chan struct{}) - stdinEOF, err := copyStreams(ctx, streams, sio.Stdin, sio.Stdout, sio.Stderr, ioDone) + stdinEOF, stdinDone, err := copyStreams(ctx, streams, sio.Stdin, sio.Stdout, sio.Stderr, ioDone) if err != nil { return stdio.Stdio{}, nil, nil, nil, err } return pio, func(ctx context.Context) error { + // Release our stdin FIFO write reference (if any) unconditionally, + // as a safety net for callers that tear down the process without + // ever issuing CloseIO (e.g. Kill+Delete). This is idempotent: it + // is a no-op if CloseIO already released it. Dropping the + // reference here only allows the host-side stdin copy to reach a + // real EOF once the external client has also closed its own + // write end; it does not force-close anything the client still + // holds open. + if stdinEOF != nil { + if err := stdinEOF(); err != nil { + log.G(ctx).WithError(err).Warn("error releasing stdin during io shutdown") + } + } + // ioDone is expected to already be closed by the time ioShutdown // is called: the host Wait handler blocks until ioDone fires before // returning to the caller, ensuring all buffered bytes have been @@ -127,6 +142,21 @@ func (s *service) forwardIO(ctx context.Context, ss streamCreator, idPrefix stri case <-ctx.Done(): err = ctx.Err() } + // Wait for the stdin copy goroutine to finish draining and send + // its in-band CloseWrite before we close the underlying stream + // connection out from under it. Bounded by the same deadline as + // ioDone above; if the external client never closes its own FIFO + // write end, this times out and we force-close everything below, + // same as the ioDone safety net. + if stdinDone != nil { + select { + case <-stdinDone: + case <-ctx.Done(): + if err == nil { + err = ctx.Err() + } + } + } for i, c := range streams { if c != nil && (i != 2 || c != streams[1]) { c.Close() diff --git a/internal/shim/task/io_copystreams.go b/internal/shim/task/io_copystreams.go deleted file mode 100644 index 5f798017..00000000 --- a/internal/shim/task/io_copystreams.go +++ /dev/null @@ -1,74 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package task - -import ( - "context" - "io" - - "github.com/containerd/log" -) - -// copyStdinUntilClose reads from f and writes raw bytes to sc until closeCh -// is closed (CloseIO) or f delivers EOF. On either exit it calls -// sc.CloseWrite() to send OP_SHUTDOWN(SEND) in-order on the vsock stdin -// stream, guaranteeing the guest sees EOF after all data already written — -// not via an out-of-band RPC that could race in-flight bytes. -func copyStdinUntilClose(ctx context.Context, sc interface { - io.Writer - CloseWrite() error -}, f io.Reader, buf []byte, closeCh <-chan struct{}) { - type readResult struct { - n int - err error - } - readCh := make(chan readResult, 1) - for { - go func() { - n, err := f.Read(buf) - readCh <- readResult{n, err} - }() - select { - case <-closeCh: - // CloseIO fired: drain the pending read then send in-band EOF. - res := <-readCh - if res.n > 0 { - if _, err := sc.Write(buf[:res.n]); err != nil { - log.G(ctx).WithError(err).Warn("error writing stdin on CloseIO") - } - } - if err := sc.CloseWrite(); err != nil { - log.G(ctx).WithError(err).Warn("error sending stdin EOF via CloseWrite") - } - return - case res := <-readCh: - if res.n > 0 { - if _, err := sc.Write(buf[:res.n]); err != nil { - log.G(ctx).WithError(err).Warn("error writing stdin") - return - } - } - if res.err != nil { - // Pipe/named-pipe EOF: client closed its write end. - if err := sc.CloseWrite(); err != nil { - log.G(ctx).WithError(err).Warn("error sending stdin EOF on pipe close") - } - return - } - } - } -} diff --git a/internal/shim/task/io_copystreams_unix.go b/internal/shim/task/io_copystreams_unix.go index 12d2a287..9afac513 100644 --- a/internal/shim/task/io_copystreams_unix.go +++ b/internal/shim/task/io_copystreams_unix.go @@ -41,10 +41,23 @@ type stdinStreamWriteCloser interface { CloseWrite() error } -// copyStreams returns a stdinEOF function that, when called (by CloseIO), -// signals the stdin goroutine to stop reading the FIFO and send the -// OP_SHUTDOWN(SEND) in-band EOF to the guest. It is nil when stdin is empty. -func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdout, stderr string, done chan struct{}) (stdinEOF func() error, err error) { +// copyStreams returns a stdinEOF function and a stdinDone channel for the +// stdin FIFO (both nil when stdin is empty). +// +// stdinEOF, when called (by CloseIO or container teardown), drops the +// host's own O_WRONLY reference on the stdin FIFO -- mirroring the +// reference containerd runc shim's stdin FIFO handling. Holding that +// reference is what lets the external client close its own FIFO write end +// to detach without delivering EOF to the process: the FIFO can only reach +// a real EOF once every writer, including this one, is closed. Dropping it +// does not force anything; the copy goroutine still fully drains whatever +// is already buffered in the FIFO (and whatever the client still writes, +// if it hasn't closed its own end yet) before the guest sees EOF. +// +// stdinDone is closed once the copy goroutine has drained the FIFO to a +// real EOF and delivered the in-band CloseWrite, so callers can wait for +// it before tearing down the underlying stream connection. +func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdout, stderr string, done chan struct{}) (stdinEOF func() error, stdinDone <-chan struct{}, err error) { var cwg sync.WaitGroup var copying atomic.Int32 copying.Store(2) @@ -103,7 +116,7 @@ func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdo } ok, err := fifo.IsFifo(i.name) if err != nil { - return nil, err + return nil, nil, err } var ( fw io.WriteCloser @@ -111,10 +124,10 @@ func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdo ) if ok { if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil { - return nil, fmt.Errorf("containerd-shim: opening w/o fifo %q failed: %w", i.name, err) + return nil, nil, fmt.Errorf("containerd-shim: opening w/o fifo %q failed: %w", i.name, err) } if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil { - return nil, fmt.Errorf("containerd-shim: opening r/o fifo %q failed: %w", i.name, err) + return nil, nil, fmt.Errorf("containerd-shim: opening r/o fifo %q failed: %w", i.name, err) } } else { if sameFile != nil { @@ -123,7 +136,7 @@ func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdo continue } if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil { - return nil, fmt.Errorf("containerd-shim: opening file %q failed: %w", i.name, err) + return nil, nil, fmt.Errorf("containerd-shim: opening file %q failed: %w", i.name, err) } if stdout == stderr { sameFile = newCountingWriteCloser(fw, 1) @@ -133,36 +146,63 @@ func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdo } if stdin != "" { // Assert early: the stdin vsock stream must implement CloseWrite so - // we can send OP_SHUTDOWN(SEND) in-order when CloseIO fires, rather - // than forwarding an out-of-band RPC that races in-flight bytes. + // we can send OP_SHUTDOWN(SEND) in-order once the FIFO reaches a + // real EOF, rather than forwarding an out-of-band RPC that races + // in-flight bytes. sc, ok := streams[0].(stdinStreamWriteCloser) if !ok { - return nil, fmt.Errorf("stdin stream connection does not implement CloseWrite; vsock conn required") + return nil, nil, fmt.Errorf("stdin stream connection does not implement CloseWrite; vsock conn required") + } + + // Hold our own O_WRONLY reference on the stdin FIFO, mirroring the + // reference containerd runc shim's stdin handling (it opens the + // FIFO write end itself to unblock its own O_RDONLY open and to + // decouple client detach from process EOF). As long as this + // reference is open, the FIFO cannot reach EOF even if the + // external client closes its own write end -- that just means + // detach. EOF is only delivered once this reference is dropped by + // stdinEOF below (CloseIO or container teardown). + fw, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return nil, nil, fmt.Errorf("containerd-shim: opening w/o stdin fifo %q failed: %w", stdin, err) } f, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0) if err != nil { - return nil, fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err) + fw.Close() + return nil, nil, fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err) } - // closeCh is closed by the stdinEOF function (triggered by CloseIO). - closeCh := make(chan struct{}) + stdinDoneCh := make(chan struct{}) + stdinDone = stdinDoneCh cwg.Add(1) go func() { cwg.Done() + defer close(stdinDoneCh) p := bufPool.Get().(*[]byte) defer bufPool.Put(p) - copyStdinUntilClose(ctx, sc, f, *p, closeCh) + // Drain to a real EOF: io.CopyBuffer only returns once every + // writer of the FIFO -- including our own reference above -- + // has closed, guaranteeing every byte buffered before EOF has + // already been forwarded to the guest via sc.Write. + if _, err := io.CopyBuffer(sc, f, *p); err != nil { + log.G(ctx).WithError(err).Warn("error copying stdin") + } + // All buffered bytes are now on the wire; deliver EOF in-band. + if err := sc.CloseWrite(); err != nil { + log.G(ctx).WithError(err).Warn("error sending stdin EOF via CloseWrite") + } // Do NOT Close sc here; deferred to ioShutdown/forwardIO cleanup // so the transport outlives the in-band EOF and the host can // close its end cleanly after the guest drains. f.Close() }() stdinEOF = func() error { - // Signal the goroutine to stop reading the FIFO and send - // OP_SHUTDOWN(SEND) in-order on the stdin stream. - close(closeCh) - return nil + // Drop our write reference. Idempotent: fifo.Close is safe to + // call more than once (e.g. once from an explicit CloseIO + // call and again from container teardown as a safety net for + // callers that never issue CloseIO). + return fw.Close() } } cwg.Wait() - return stdinEOF, nil + return stdinEOF, stdinDone, nil } diff --git a/internal/shim/task/io_copystreams_windows.go b/internal/shim/task/io_copystreams_windows.go index cc5cc828..09642b6e 100644 --- a/internal/shim/task/io_copystreams_windows.go +++ b/internal/shim/task/io_copystreams_windows.go @@ -20,6 +20,7 @@ package task import ( "context" + "errors" "fmt" "io" "os" @@ -38,7 +39,63 @@ type stdinStreamWriteCloser interface { CloseWrite() error } -func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdout, stderr string, done chan struct{}) (stdinEOF func() error, err error) { +// writeErrRecorder wraps the guest-facing stdin stream so the redial loop +// below can tell the two failure modes of io.CopyBuffer apart. A read-side +// error (including the ordinary nil-error EOF) means the *client* +// disconnected, which is a detach candidate and should be followed by a +// reconnect. A write-side error means the stream to the guest is broken, so +// no future client could ever deliver bytes and reconnecting would spin +// forever without closing stdinDone. +// +// It is only ever written by copyStreams' single stdin goroutine, so err +// needs no synchronization. Embedding io.Writer (rather than the full +// stdinStreamWriteCloser) also hides any ReaderFrom the underlying stream +// may implement, keeping io.CopyBuffer on the path that routes every byte +// through Write and therefore through this recorder. +type writeErrRecorder struct { + io.Writer + err error +} + +func (w *writeErrRecorder) Write(p []byte) (int, error) { + n, err := w.Writer.Write(p) + if err != nil { + w.err = err + } + return n, err +} + +// copyStreams returns a stdinEOF function and a stdinDone channel for the +// stdin pipe (both nil when stdin is empty). +// +// For a named pipe, stdinEOF (invoked by CloseIO or container teardown) +// signals the copy goroutine that the next client disconnect is real EOF +// rather than a detach. Unlike a POSIX FIFO, a Windows named pipe +// connection has no notion of holding a second, independent writer +// reference to keep the "conversation" from ending when the client +// disconnects. Instead, this mirrors the same client-detach/re-attach +// contract using reconnection: go-winio's ListenPipe (matching +// containerd's own stdio server model, where the caller is the named-pipe +// server and the shim is the client) creates a fresh pipe instance for +// every Accept, so a new client can connect to the same pipe path after a +// previous one disconnects. When the current connection ends without +// stdinEOF having been called, the goroutine treats it as a detach and +// dials the same pipe path again, waiting (with no timeout, only +// cancelled by stdinEOF or container teardown) for a new client to +// reconnect before relaying any more bytes -- exactly as the POSIX side +// waits for the FIFO to reach a real EOF only after CloseIO releases its +// write reference. Only when stdinEOF has been called does the next +// disconnect (or the current one, if it already happened) deliver EOF to +// the guest via CloseWrite. +// +// Reconnecting is only correct when the copy ended because the client +// went away. If it ended because writing to the guest-facing stream +// failed, the loop stops instead -- see writeErrRecorder. +// +// A plain file (the non-named-pipe fallback) has no reconnect concept, so +// it is read once to EOF and always delivers EOF immediately; stdinEOF is +// a no-op in that case. +func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdout, stderr string, done chan struct{}) (stdinEOF func() error, stdinDone <-chan struct{}, err error) { var cwg sync.WaitGroup var copying atomic.Int32 copying.Store(2) @@ -106,7 +163,7 @@ func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdo if isNamedPipe(i.name) { fw, err = winio.DialPipe(i.name, &pipeDialTimeout) if err != nil { - return nil, fmt.Errorf("containerd-shim: connecting to named pipe %q failed: %w", i.name, err) + return nil, nil, fmt.Errorf("containerd-shim: connecting to named pipe %q failed: %w", i.name, err) } } else { if sameFile != nil { @@ -115,7 +172,7 @@ func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdo continue } if fw, err = os.OpenFile(i.name, os.O_WRONLY|os.O_APPEND, 0); err != nil { - return nil, fmt.Errorf("containerd-shim: opening file %q failed: %w", i.name, err) + return nil, nil, fmt.Errorf("containerd-shim: opening file %q failed: %w", i.name, err) } if stdout == stderr { sameFile = newCountingWriteCloser(fw, 1) @@ -126,38 +183,117 @@ func copyStreams(ctx context.Context, streams [3]io.ReadWriteCloser, stdin, stdo if stdin != "" { sc, ok := streams[0].(stdinStreamWriteCloser) if !ok { - return nil, fmt.Errorf("stdin stream connection does not implement CloseWrite; vsock conn required") + return nil, nil, fmt.Errorf("stdin stream connection does not implement CloseWrite; vsock conn required") } + + namedPipe := isNamedPipe(stdin) + + // Establish the first connection synchronously, bounded by + // pipeDialTimeout, preserving the existing Exec()/Create() + // contract: if no client attaches to stdin promptly, the RPC + // fails fast rather than hanging. var f io.ReadCloser - if isNamedPipe(stdin) { + if namedPipe { conn, err := winio.DialPipe(stdin, &pipeDialTimeout) if err != nil { - return nil, fmt.Errorf("containerd-shim: connecting to named pipe %q for stdin failed: %w", stdin, err) + return nil, nil, fmt.Errorf("containerd-shim: connecting to named pipe %q for stdin failed: %w", stdin, err) } f = conn } else { var err error f, err = os.Open(stdin) if err != nil { - return nil, fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err) + return nil, nil, fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err) } } - closeCh := make(chan struct{}) + + // closeRequested is closed by stdinEOF (CloseIO or container + // teardown) to signal that the next client disconnect -- or the + // current one, if it has already happened -- must deliver EOF to + // the guest instead of waiting for a new client to reconnect. + closeRequested := make(chan struct{}) + var closeOnce sync.Once + stdinEOF = func() error { + closeOnce.Do(func() { close(closeRequested) }) + return nil + } + + stdinDoneCh := make(chan struct{}) + stdinDone = stdinDoneCh cwg.Add(1) go func() { cwg.Done() + defer close(stdinDoneCh) p := bufPool.Get().(*[]byte) defer bufPool.Put(p) - copyStdinUntilClose(ctx, sc, f, *p, closeCh) - f.Close() + w := &writeErrRecorder{Writer: sc} + + readLoop: + for { + // Drain to a real EOF: the peer closing its write end is + // what unblocks this read, so every byte buffered before + // EOF is forwarded before we either reconnect or deliver + // the in-band CloseWrite below. + if _, err := io.CopyBuffer(w, f, *p); err != nil { + log.G(ctx).WithError(err).Warn("error copying stdin") + } + f.Close() + + // A write failure means the guest-facing stream is gone, + // not that the client detached. Reconnecting would block + // on a client that can never be serviced, leaving + // stdinDone open and stalling ioShutdown for its full + // timeout, so stop the loop instead. + if w.err != nil { + log.G(ctx).WithError(w.err).Warn("stdin stream to guest failed; not waiting for client re-attach") + break readLoop + } + + if !namedPipe { + break readLoop + } + select { + case <-closeRequested: + break readLoop + default: + } + + // The client disconnected without stdinEOF having been + // called: treat this as a detach and wait for a new + // client to reconnect on the same pipe path. This wait is + // deliberately not time-bounded -- a detach may + // legitimately last a long time -- and is rooted in + // context.Background() rather than ctx, since ctx is the + // Exec()/Create() RPC's context and is typically cancelled + // as soon as that RPC returns. It is only cancelled by + // stdinEOF (CloseIO, or container teardown calling + // stdinEOF as a safety net). + dialCtx, cancel := context.WithCancel(context.Background()) + go func() { + select { + case <-closeRequested: + cancel() + case <-dialCtx.Done(): + } + }() + conn, err := winio.DialPipeContext(dialCtx, stdin) + cancel() + if err != nil { + if !errors.Is(err, context.Canceled) { + log.G(ctx).WithError(err).Warn("error reconnecting to stdin pipe after detach") + } + break readLoop + } + f = conn + } + + if err := sc.CloseWrite(); err != nil { + log.G(ctx).WithError(err).Warn("error sending stdin EOF via CloseWrite") + } }() - stdinEOF = func() error { - close(closeCh) - return nil - } } cwg.Wait() - return stdinEOF, nil + return stdinEOF, stdinDone, nil } // isNamedPipe checks if a path looks like a Windows named pipe (\\.\pipe\...). diff --git a/internal/shim/task/io_copystreams_windows_test.go b/internal/shim/task/io_copystreams_windows_test.go new file mode 100644 index 00000000..b957f0b6 --- /dev/null +++ b/internal/shim/task/io_copystreams_windows_test.go @@ -0,0 +1,231 @@ +//go:build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package task + +import ( + "context" + "fmt" + "io" + "strconv" + "sync" + "testing" + "time" + + winio "github.com/Microsoft/go-winio" + "github.com/stretchr/testify/require" +) + +// fakeStdinStream is a minimal in-memory stdinStreamWriteCloser used to +// observe what copyStreams' stdin goroutine relays to the "guest" side +// (Write) and whether/when it delivers EOF (CloseWrite), without needing a +// real vsock connection or VM. It never returns anything to Read: the +// stdin direction only writes into it. +type fakeStdinStream struct { + mu sync.Mutex + buf []byte + writeClosed bool +} + +func newFakeStdinStream() *fakeStdinStream { + return &fakeStdinStream{} +} + +func (f *fakeStdinStream) Read([]byte) (int, error) { return 0, io.EOF } + +func (f *fakeStdinStream) Write(p []byte) (int, error) { + f.mu.Lock() + defer f.mu.Unlock() + f.buf = append(f.buf, p...) + return len(p), nil +} + +func (f *fakeStdinStream) Close() error { return nil } + +func (f *fakeStdinStream) CloseWrite() error { + f.mu.Lock() + defer f.mu.Unlock() + f.writeClosed = true + return nil +} + +// snapshot returns the bytes relayed so far and whether CloseWrite (EOF) +// has been delivered. +func (f *fakeStdinStream) snapshot() (data string, eofDelivered bool) { + f.mu.Lock() + defer f.mu.Unlock() + return string(f.buf), f.writeClosed +} + +// testPipeName returns a unique named-pipe path for this test process. +func testPipeName(t *testing.T) string { + t.Helper() + return `\\.\pipe\nerdbox-copystreams-test-` + strconv.FormatInt(time.Now().UnixNano(), 36) +} + +// TestCopyStreamsStdinDetachReattach exercises the Windows stdin redial +// logic in copyStreams (io_copystreams_windows.go) directly, without any +// VM/libkrun/shim process involved. It validates the core contract added +// to support stdin detach/re-attach on Windows: +// +// 1. A client can write to the exec's stdin and disconnect ("detach") +// without stdinEOF (CloseIO) having been called, and the guest-facing +// stream must NOT see EOF (CloseWrite) during that detach window. +// 2. A new client can then connect to the very same named-pipe path +// ("re-attach") and its data must also be relayed. +// 3. Only after stdinEOF is called does the next disconnect deliver EOF +// (CloseWrite) to the guest-facing stream. +// +// This is the Windows analogue of the shimtest conformance test +// StdinDetachReattach (vendor/github.com/containerd/shimtest/ +// exec_suite.go), but runs as a plain `go test` with no VM required, so it +// also runs automatically in CI's existing windows-latest unit-test job +// (see .github/workflows/ci.yml, task test:unit). +func TestCopyStreamsStdinDetachReattach(t *testing.T) { + pipePath := testPipeName(t) + l, err := winio.ListenPipe(pipePath, &winio.PipeConfig{ + InputBufferSize: 4096, + OutputBufferSize: 4096, + }) + require.NoError(t, err, "ListenPipe") + defer l.Close() + + // acceptWriteClose accepts exactly one client connection, writes data + // to it, and closes -- run in a goroutine so the caller can overlap it + // with copyStreams' dial/redial attempts, exactly as a real client + // would. + acceptWriteClose := func(data string) <-chan error { + done := make(chan error, 1) + go func() { + conn, err := l.Accept() + if err != nil { + done <- fmt.Errorf("accept: %w", err) + return + } + defer conn.Close() + if _, err := conn.Write([]byte(data)); err != nil { + done <- fmt.Errorf("write: %w", err) + return + } + done <- nil + }() + return done + } + + // The first writer must already be trying to connect before + // copyStreams dials, mirroring the ordering shimtest's exec tests use + // (open the stdin writer before calling Exec): copyStreams' first + // dial is synchronous and bounded by pipeDialTimeout. + w1Done := acceptWriteClose("first") + + sc := newFakeStdinStream() + streams := [3]io.ReadWriteCloser{sc, nil, nil} + ioDone := make(chan struct{}) + + stdinEOF, stdinDone, err := copyStreams(context.Background(), streams, pipePath, "", "", ioDone) + require.NoError(t, err, "copyStreams") + require.NotNil(t, stdinEOF, "expected non-nil stdinEOF") + require.NotNil(t, stdinDone, "expected non-nil stdinDone") + + require.NoError(t, <-w1Done, "first writer") + + // Give the copy goroutine a moment to notice the first writer's + // disconnect and start waiting to reconnect (the "detach" period). + time.Sleep(300 * time.Millisecond) + + // Confirm no premature EOF was delivered to the guest during the + // detach window: the shim must not deliver EOF just because a client + // disconnected without calling CloseIO. + if _, eof := sc.snapshot(); eof { + t.Fatal("stdin EOF (CloseWrite) delivered during detach, before stdinEOF/CloseIO was called") + } + + // A second writer "re-attaches" on the very same pipe path. + w2Done := acceptWriteClose("second") + require.NoError(t, <-w2Done, "second writer") + + // Give the copy goroutine a moment to relay the second write. + time.Sleep(300 * time.Millisecond) + + data, eof := sc.snapshot() + require.False(t, eof, "EOF must not be delivered before stdinEOF is called") + require.Equal(t, "firstsecond", data, "expected data from both the pre-detach and post-reattach writers to have been relayed before stdinEOF") + + // Now signal real EOF, as CloseIO would. + require.NoError(t, stdinEOF()) + + select { + case <-stdinDone: + case <-time.After(5 * time.Second): + t.Fatal("timed out waiting for stdinDone after stdinEOF") + } + + data, eof = sc.snapshot() + require.True(t, eof, "expected CloseWrite to have been called after stdinEOF") + require.Equal(t, "firstsecond", data, "expected data from both the pre-detach and post-reattach writers") +} + +// TestCopyStreamsStdinCloseWithoutDetach verifies the simple case (no +// detach involved): a single client writes and disconnects, then stdinEOF +// is called; the guest-facing stream must have received the data and EOF. +// This guards against a regression where the redial loop introduced for +// detach/re-attach support accidentally breaks the common case. +func TestCopyStreamsStdinCloseWithoutDetach(t *testing.T) { + pipePath := testPipeName(t) + l, err := winio.ListenPipe(pipePath, &winio.PipeConfig{ + InputBufferSize: 4096, + OutputBufferSize: 4096, + }) + require.NoError(t, err, "ListenPipe") + defer l.Close() + + writeDone := make(chan error, 1) + go func() { + conn, err := l.Accept() + if err != nil { + writeDone <- fmt.Errorf("accept: %w", err) + return + } + defer conn.Close() + _, err = conn.Write([]byte("hello")) + writeDone <- err + }() + + sc := newFakeStdinStream() + streams := [3]io.ReadWriteCloser{sc, nil, nil} + ioDone := make(chan struct{}) + + stdinEOF, stdinDone, err := copyStreams(context.Background(), streams, pipePath, "", "", ioDone) + require.NoError(t, err, "copyStreams") + require.NoError(t, <-writeDone, "writer") + + // The client already closed its connection above (defer conn.Close()); + // signal CloseIO promptly, matching the documented + // write-then-close-then-CloseIO client protocol. + require.NoError(t, stdinEOF()) + + select { + case <-stdinDone: + case <-time.After(5 * time.Second): + t.Fatal("timed out waiting for stdinDone") + } + + data, eof := sc.snapshot() + require.True(t, eof, "expected CloseWrite to have been called") + require.Equal(t, "hello", data) +} diff --git a/internal/shim/task/service.go b/internal/shim/task/service.go index d3c81998..522a67d5 100644 --- a/internal/shim/task/service.go +++ b/internal/shim/task/service.go @@ -152,10 +152,15 @@ type container struct { // ioDone is closed when the host-side copy goroutines for the init // process have fully drained output to the destination FIFO. ioDone <-chan struct{} - // stdinEOF, when non-nil, signals the host stdin goroutine to stop - // reading the FIFO and send OP_SHUTDOWN(SEND) in-order on the stdin - // stream. Called by CloseIO instead of forwarding the RPC out-of-band, - // guaranteeing the EOF arrives after all in-flight stdin bytes. + // stdinEOF, when non-nil, releases the host's own write reference on + // the process' stdin (the O_WRONLY FIFO handle on Unix; the + // reconnect-on-detach loop on Windows). It does not stop or truncate + // the copy: the host stdin goroutine keeps draining until stdin + // reaches a real EOF, and only then sends OP_SHUTDOWN(SEND) in-order + // on the stdin stream. Called by CloseIO instead of forwarding the RPC + // out-of-band, guaranteeing the EOF arrives after all in-flight stdin + // bytes, and by container teardown as a safety net for callers that + // never issue CloseIO. stdinEOF func() error // forwarder is the UNIX socket forwarder for this specific container. @@ -217,11 +222,19 @@ func (s *service) RegisterTTRPC(server *ttrpc.Server) error { } func (s *service) shutdown(ctx context.Context) error { + // Detach all containers from tracking under the lock, then shut them down + // outside of it. Each container shutdown can block until its host-side + // copy goroutines drain and stdin reaches a real EOF (up to a 30 s ceiling + // per process), so holding s.mu across them would stall every concurrent + // RPC. Clearing the map first means no other RPC can reach a container we + // are tearing down. s.mu.Lock() - defer s.mu.Unlock() - var errs []error + containers := s.containers + s.containers = make(map[string]*container) + s.mu.Unlock() - for id, c := range s.containers { + var errs []error + for id, c := range containers { if err := c.shutdown(ctx); err != nil { errs = append(errs, fmt.Errorf("container %q shutdown: %w", id, err)) } @@ -575,7 +588,41 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI. return nil, errgrpc.ToGRPC(err) } tc := taskAPI.NewTTRPCTaskClient(vmc) - return tc.Start(ctx, r) + resp, err := tc.Start(ctx, r) + if err != nil && r.ExecID != "" { + // On exec start failure the VM side did not launch the process, so it + // will not close the exec's vsock streams on its own. The host-side + // copy goroutines (stdout/stderr) are therefore blocked indefinitely, + // which means the ioShutdown triggered by a subsequent Delete call + // would block for its full 30 s timeout before closing the streams. + // + // To prevent that, remove the exec's IO shutdown from the container's + // tracking and initiate it asynchronously here with a short timeout. + // After the timeout ioShutdown closes the vsock connections, the copy + // goroutines see a read error and exit, and the subsequent Delete call + // finds no pending ioShutdown and returns promptly. + s.mu.Lock() + var execShutdown func(context.Context) error + if c, ok := s.containers[r.ID]; ok { + if f, ok := c.execShutdowns[r.ExecID]; ok { + execShutdown = f + delete(c.execShutdowns, r.ExecID) + delete(c.execIODone, r.ExecID) + delete(c.execStdinEOF, r.ExecID) + } + } + s.mu.Unlock() + if execShutdown != nil { + go func() { + shutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if serr := execShutdown(shutCtx); serr != nil && !errors.Is(serr, context.DeadlineExceeded) { + log.G(ctx).WithError(serr).WithField("exec", r.ExecID).Error("failed to shutdown exec io after start failure") + } + }() + } + } + return resp, err } // Delete the initial process and container @@ -589,26 +636,38 @@ func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAP tc := taskAPI.NewTTRPCTaskClient(vmc) resp, err := tc.Delete(ctx, r) if err == nil { + // Detach the IO shutdown from the service's tracking under the lock, + // then run it *outside* the lock. ioShutdown can block until the + // host-side copy goroutines drain and the stdin FIFO reaches a real + // EOF (up to its 30 s ceiling), so holding s.mu across it would stall + // every other RPC -- including the CloseIO that releases stdin. + // Removing the entry first means no concurrent RPC can observe or + // re-run the shutdown we are about to perform. s.mu.Lock() + var shutdown func(context.Context) error if c, ok := s.containers[r.ID]; ok { if r.ExecID != "" { if ioShutdown, ok := c.execShutdowns[r.ExecID]; ok { - if err := ioShutdown(ctx); err != nil { - log.G(ctx).WithError(err).WithField("exec_id", r.ExecID).Error("failed to shutdown exec io after delete") - } + shutdown = ioShutdown delete(c.execShutdowns, r.ExecID) delete(c.execIODone, r.ExecID) delete(c.execStdinEOF, r.ExecID) } } else { - if err := c.shutdown(ctx); err != nil { - log.G(ctx).WithError(err).Error("failed to shutdown container after delete") - } + shutdown = c.shutdown delete(s.containers, r.ID) } } s.mu.Unlock() + if shutdown != nil { + if err := shutdown(ctx); err != nil { + log.G(ctx).WithError(err).WithFields(log.Fields{ + "container_id": r.ID, + "exec_id": r.ExecID, + }).Error("failed to shutdown io after delete") + } + } } return resp, err } @@ -767,10 +826,16 @@ func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptyp log.G(ctx).WithFields(log.Fields{"container_id": r.ID, "exec_id": r.ExecID, "stdin": r.Stdin}).Info("close io") if r.Stdin { // Deliver stdin EOF in-band on the stream connection rather than - // forwarding the RPC out-of-band. The in-band CloseWrite sends - // OP_SHUTDOWN(SEND) ordered after all data already written to the - // stream, preventing truncation caused by an out-of-band RPC on a - // separate vsock connection racing in-flight stdin bytes. + // forwarding the RPC out-of-band. stdinEOF drops the host's own + // write reference on the stdin FIFO (mirroring the reference + // containerd runc shim), which lets the host's stdin copy + // goroutine drain to a real FIFO EOF and then send an in-band + // CloseWrite (OP_SHUTDOWN(SEND)) ordered after all buffered data. + // This avoids the truncation an out-of-band RPC on a separate + // vsock connection could cause by racing in-flight stdin bytes, + // and it preserves the client-detach/re-attach semantics the FIFO + // write reference is meant to provide: closing the client's own + // FIFO write end alone (without CloseIO) does not deliver EOF. s.mu.Lock() var stdinEOF func() error if c, ok := s.containers[r.ID]; ok { diff --git a/vendor/github.com/containerd/containerd/api/runtime/task/v2/doc.go b/vendor/github.com/containerd/containerd/api/runtime/task/v2/doc.go new file mode 100644 index 00000000..f933dd8d --- /dev/null +++ b/vendor/github.com/containerd/containerd/api/runtime/task/v2/doc.go @@ -0,0 +1,17 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package task diff --git a/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim.pb.go b/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim.pb.go new file mode 100644 index 00000000..e62f4e70 --- /dev/null +++ b/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim.pb.go @@ -0,0 +1,2331 @@ +// +//Copyright The containerd Authors. +// +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc (unknown) +// source: runtime/task/v2/shim.proto + +package task + +import ( + types "github.com/containerd/containerd/api/types" + task "github.com/containerd/containerd/api/types/task" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" + emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CreateTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` + Rootfs []*types.Mount `protobuf:"bytes,3,rep,name=rootfs,proto3" json:"rootfs,omitempty"` + Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` + Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` + Checkpoint string `protobuf:"bytes,8,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` + ParentCheckpoint string `protobuf:"bytes,9,opt,name=parent_checkpoint,json=parentCheckpoint,proto3" json:"parent_checkpoint,omitempty"` + Options *anypb.Any `protobuf:"bytes,10,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *CreateTaskRequest) Reset() { + *x = CreateTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTaskRequest) ProtoMessage() {} + +func (x *CreateTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateTaskRequest.ProtoReflect.Descriptor instead. +func (*CreateTaskRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{0} +} + +func (x *CreateTaskRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *CreateTaskRequest) GetBundle() string { + if x != nil { + return x.Bundle + } + return "" +} + +func (x *CreateTaskRequest) GetRootfs() []*types.Mount { + if x != nil { + return x.Rootfs + } + return nil +} + +func (x *CreateTaskRequest) GetTerminal() bool { + if x != nil { + return x.Terminal + } + return false +} + +func (x *CreateTaskRequest) GetStdin() string { + if x != nil { + return x.Stdin + } + return "" +} + +func (x *CreateTaskRequest) GetStdout() string { + if x != nil { + return x.Stdout + } + return "" +} + +func (x *CreateTaskRequest) GetStderr() string { + if x != nil { + return x.Stderr + } + return "" +} + +func (x *CreateTaskRequest) GetCheckpoint() string { + if x != nil { + return x.Checkpoint + } + return "" +} + +func (x *CreateTaskRequest) GetParentCheckpoint() string { + if x != nil { + return x.ParentCheckpoint + } + return "" +} + +func (x *CreateTaskRequest) GetOptions() *anypb.Any { + if x != nil { + return x.Options + } + return nil +} + +type CreateTaskResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` +} + +func (x *CreateTaskResponse) Reset() { + *x = CreateTaskResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateTaskResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTaskResponse) ProtoMessage() {} + +func (x *CreateTaskResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateTaskResponse.ProtoReflect.Descriptor instead. +func (*CreateTaskResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateTaskResponse) GetPid() uint32 { + if x != nil { + return x.Pid + } + return 0 +} + +type DeleteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` +} + +func (x *DeleteRequest) Reset() { + *x = DeleteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRequest) ProtoMessage() {} + +func (x *DeleteRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead. +func (*DeleteRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{2} +} + +func (x *DeleteRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *DeleteRequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +type DeleteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + ExitStatus uint32 `protobuf:"varint,2,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=exited_at,json=exitedAt,proto3" json:"exited_at,omitempty"` +} + +func (x *DeleteResponse) Reset() { + *x = DeleteResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteResponse) ProtoMessage() {} + +func (x *DeleteResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead. +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{3} +} + +func (x *DeleteResponse) GetPid() uint32 { + if x != nil { + return x.Pid + } + return 0 +} + +func (x *DeleteResponse) GetExitStatus() uint32 { + if x != nil { + return x.ExitStatus + } + return 0 +} + +func (x *DeleteResponse) GetExitedAt() *timestamppb.Timestamp { + if x != nil { + return x.ExitedAt + } + return nil +} + +type ExecProcessRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Terminal bool `protobuf:"varint,3,opt,name=terminal,proto3" json:"terminal,omitempty"` + Stdin string `protobuf:"bytes,4,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,5,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,6,opt,name=stderr,proto3" json:"stderr,omitempty"` + Spec *anypb.Any `protobuf:"bytes,7,opt,name=spec,proto3" json:"spec,omitempty"` +} + +func (x *ExecProcessRequest) Reset() { + *x = ExecProcessRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExecProcessRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecProcessRequest) ProtoMessage() {} + +func (x *ExecProcessRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecProcessRequest.ProtoReflect.Descriptor instead. +func (*ExecProcessRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{4} +} + +func (x *ExecProcessRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *ExecProcessRequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +func (x *ExecProcessRequest) GetTerminal() bool { + if x != nil { + return x.Terminal + } + return false +} + +func (x *ExecProcessRequest) GetStdin() string { + if x != nil { + return x.Stdin + } + return "" +} + +func (x *ExecProcessRequest) GetStdout() string { + if x != nil { + return x.Stdout + } + return "" +} + +func (x *ExecProcessRequest) GetStderr() string { + if x != nil { + return x.Stderr + } + return "" +} + +func (x *ExecProcessRequest) GetSpec() *anypb.Any { + if x != nil { + return x.Spec + } + return nil +} + +type ExecProcessResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ExecProcessResponse) Reset() { + *x = ExecProcessResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExecProcessResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecProcessResponse) ProtoMessage() {} + +func (x *ExecProcessResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecProcessResponse.ProtoReflect.Descriptor instead. +func (*ExecProcessResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{5} +} + +type ResizePtyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Width uint32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` + Height uint32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` +} + +func (x *ResizePtyRequest) Reset() { + *x = ResizePtyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResizePtyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResizePtyRequest) ProtoMessage() {} + +func (x *ResizePtyRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResizePtyRequest.ProtoReflect.Descriptor instead. +func (*ResizePtyRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{6} +} + +func (x *ResizePtyRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *ResizePtyRequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +func (x *ResizePtyRequest) GetWidth() uint32 { + if x != nil { + return x.Width + } + return 0 +} + +func (x *ResizePtyRequest) GetHeight() uint32 { + if x != nil { + return x.Height + } + return 0 +} + +type StateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` +} + +func (x *StateRequest) Reset() { + *x = StateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateRequest) ProtoMessage() {} + +func (x *StateRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateRequest.ProtoReflect.Descriptor instead. +func (*StateRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{7} +} + +func (x *StateRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *StateRequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +type StateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` + Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` + Status task.Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` + Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` + Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"` + ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,proto3" json:"exited_at,omitempty"` + ExecID string `protobuf:"bytes,11,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` +} + +func (x *StateResponse) Reset() { + *x = StateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateResponse) ProtoMessage() {} + +func (x *StateResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateResponse.ProtoReflect.Descriptor instead. +func (*StateResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{8} +} + +func (x *StateResponse) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *StateResponse) GetBundle() string { + if x != nil { + return x.Bundle + } + return "" +} + +func (x *StateResponse) GetPid() uint32 { + if x != nil { + return x.Pid + } + return 0 +} + +func (x *StateResponse) GetStatus() task.Status { + if x != nil { + return x.Status + } + return task.Status(0) +} + +func (x *StateResponse) GetStdin() string { + if x != nil { + return x.Stdin + } + return "" +} + +func (x *StateResponse) GetStdout() string { + if x != nil { + return x.Stdout + } + return "" +} + +func (x *StateResponse) GetStderr() string { + if x != nil { + return x.Stderr + } + return "" +} + +func (x *StateResponse) GetTerminal() bool { + if x != nil { + return x.Terminal + } + return false +} + +func (x *StateResponse) GetExitStatus() uint32 { + if x != nil { + return x.ExitStatus + } + return 0 +} + +func (x *StateResponse) GetExitedAt() *timestamppb.Timestamp { + if x != nil { + return x.ExitedAt + } + return nil +} + +func (x *StateResponse) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +type KillRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Signal uint32 `protobuf:"varint,3,opt,name=signal,proto3" json:"signal,omitempty"` + All bool `protobuf:"varint,4,opt,name=all,proto3" json:"all,omitempty"` +} + +func (x *KillRequest) Reset() { + *x = KillRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *KillRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KillRequest) ProtoMessage() {} + +func (x *KillRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KillRequest.ProtoReflect.Descriptor instead. +func (*KillRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{9} +} + +func (x *KillRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *KillRequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +func (x *KillRequest) GetSignal() uint32 { + if x != nil { + return x.Signal + } + return 0 +} + +func (x *KillRequest) GetAll() bool { + if x != nil { + return x.All + } + return false +} + +type CloseIORequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Stdin bool `protobuf:"varint,3,opt,name=stdin,proto3" json:"stdin,omitempty"` +} + +func (x *CloseIORequest) Reset() { + *x = CloseIORequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CloseIORequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloseIORequest) ProtoMessage() {} + +func (x *CloseIORequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CloseIORequest.ProtoReflect.Descriptor instead. +func (*CloseIORequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{10} +} + +func (x *CloseIORequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *CloseIORequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +func (x *CloseIORequest) GetStdin() bool { + if x != nil { + return x.Stdin + } + return false +} + +type PidsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *PidsRequest) Reset() { + *x = PidsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PidsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PidsRequest) ProtoMessage() {} + +func (x *PidsRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PidsRequest.ProtoReflect.Descriptor instead. +func (*PidsRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{11} +} + +func (x *PidsRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +type PidsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Processes []*task.ProcessInfo `protobuf:"bytes,1,rep,name=processes,proto3" json:"processes,omitempty"` +} + +func (x *PidsResponse) Reset() { + *x = PidsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PidsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PidsResponse) ProtoMessage() {} + +func (x *PidsResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PidsResponse.ProtoReflect.Descriptor instead. +func (*PidsResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{12} +} + +func (x *PidsResponse) GetProcesses() []*task.ProcessInfo { + if x != nil { + return x.Processes + } + return nil +} + +type CheckpointTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + Options *anypb.Any `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *CheckpointTaskRequest) Reset() { + *x = CheckpointTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckpointTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckpointTaskRequest) ProtoMessage() {} + +func (x *CheckpointTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckpointTaskRequest.ProtoReflect.Descriptor instead. +func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{13} +} + +func (x *CheckpointTaskRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *CheckpointTaskRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *CheckpointTaskRequest) GetOptions() *anypb.Any { + if x != nil { + return x.Options + } + return nil +} + +type UpdateTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Resources *anypb.Any `protobuf:"bytes,2,opt,name=resources,proto3" json:"resources,omitempty"` + Annotations map[string]string `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *UpdateTaskRequest) Reset() { + *x = UpdateTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateTaskRequest) ProtoMessage() {} + +func (x *UpdateTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateTaskRequest.ProtoReflect.Descriptor instead. +func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{14} +} + +func (x *UpdateTaskRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *UpdateTaskRequest) GetResources() *anypb.Any { + if x != nil { + return x.Resources + } + return nil +} + +func (x *UpdateTaskRequest) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +type StartRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` +} + +func (x *StartRequest) Reset() { + *x = StartRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartRequest) ProtoMessage() {} + +func (x *StartRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartRequest.ProtoReflect.Descriptor instead. +func (*StartRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{15} +} + +func (x *StartRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *StartRequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +type StartResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` +} + +func (x *StartResponse) Reset() { + *x = StartResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartResponse) ProtoMessage() {} + +func (x *StartResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartResponse.ProtoReflect.Descriptor instead. +func (*StartResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{16} +} + +func (x *StartResponse) GetPid() uint32 { + if x != nil { + return x.Pid + } + return 0 +} + +type WaitRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` +} + +func (x *WaitRequest) Reset() { + *x = WaitRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WaitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WaitRequest) ProtoMessage() {} + +func (x *WaitRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WaitRequest.ProtoReflect.Descriptor instead. +func (*WaitRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{17} +} + +func (x *WaitRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *WaitRequest) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +type WaitResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ExitStatus uint32 `protobuf:"varint,1,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=exited_at,json=exitedAt,proto3" json:"exited_at,omitempty"` +} + +func (x *WaitResponse) Reset() { + *x = WaitResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WaitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WaitResponse) ProtoMessage() {} + +func (x *WaitResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WaitResponse.ProtoReflect.Descriptor instead. +func (*WaitResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{18} +} + +func (x *WaitResponse) GetExitStatus() uint32 { + if x != nil { + return x.ExitStatus + } + return 0 +} + +func (x *WaitResponse) GetExitedAt() *timestamppb.Timestamp { + if x != nil { + return x.ExitedAt + } + return nil +} + +type StatsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *StatsRequest) Reset() { + *x = StatsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatsRequest) ProtoMessage() {} + +func (x *StatsRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatsRequest.ProtoReflect.Descriptor instead. +func (*StatsRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{19} +} + +func (x *StatsRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +type StatsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stats *anypb.Any `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats,omitempty"` +} + +func (x *StatsResponse) Reset() { + *x = StatsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatsResponse) ProtoMessage() {} + +func (x *StatsResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatsResponse.ProtoReflect.Descriptor instead. +func (*StatsResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{20} +} + +func (x *StatsResponse) GetStats() *anypb.Any { + if x != nil { + return x.Stats + } + return nil +} + +type ConnectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ConnectRequest) Reset() { + *x = ConnectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConnectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConnectRequest) ProtoMessage() {} + +func (x *ConnectRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConnectRequest.ProtoReflect.Descriptor instead. +func (*ConnectRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{21} +} + +func (x *ConnectRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +type ConnectResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ShimPid uint32 `protobuf:"varint,1,opt,name=shim_pid,json=shimPid,proto3" json:"shim_pid,omitempty"` + TaskPid uint32 `protobuf:"varint,2,opt,name=task_pid,json=taskPid,proto3" json:"task_pid,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` +} + +func (x *ConnectResponse) Reset() { + *x = ConnectResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConnectResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConnectResponse) ProtoMessage() {} + +func (x *ConnectResponse) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConnectResponse.ProtoReflect.Descriptor instead. +func (*ConnectResponse) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{22} +} + +func (x *ConnectResponse) GetShimPid() uint32 { + if x != nil { + return x.ShimPid + } + return 0 +} + +func (x *ConnectResponse) GetTaskPid() uint32 { + if x != nil { + return x.TaskPid + } + return 0 +} + +func (x *ConnectResponse) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +type ShutdownRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Now bool `protobuf:"varint,2,opt,name=now,proto3" json:"now,omitempty"` +} + +func (x *ShutdownRequest) Reset() { + *x = ShutdownRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ShutdownRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShutdownRequest) ProtoMessage() {} + +func (x *ShutdownRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShutdownRequest.ProtoReflect.Descriptor instead. +func (*ShutdownRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{23} +} + +func (x *ShutdownRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *ShutdownRequest) GetNow() bool { + if x != nil { + return x.Now + } + return false +} + +type PauseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *PauseRequest) Reset() { + *x = PauseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PauseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PauseRequest) ProtoMessage() {} + +func (x *PauseRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PauseRequest.ProtoReflect.Descriptor instead. +func (*PauseRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{24} +} + +func (x *PauseRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +type ResumeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ResumeRequest) Reset() { + *x = ResumeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runtime_task_v2_shim_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResumeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResumeRequest) ProtoMessage() {} + +func (x *ResumeRequest) ProtoReflect() protoreflect.Message { + mi := &file_runtime_task_v2_shim_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResumeRequest.ProtoReflect.Descriptor instead. +func (*ResumeRequest) Descriptor() ([]byte, []int) { + return file_runtime_task_v2_shim_proto_rawDescGZIP(), []int{25} +} + +func (x *ResumeRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +var File_runtime_task_v2_shim_proto protoreflect.FileDescriptor + +var file_runtime_task_v2_shim_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x74, 0x61, 0x73, 0x6b, 0x2f, 0x76, + 0x32, 0x2f, 0x73, 0x68, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, + 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, + 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x73, 0x6b, 0x2f, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0xcb, 0x02, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x74, + 0x66, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, + 0x74, 0x64, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, + 0x64, 0x65, 0x72, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x10, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x26, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x38, 0x0a, 0x0d, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, + 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, + 0x63, 0x49, 0x64, 0x22, 0x7c, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x69, 0x74, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, + 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x22, 0xc9, 0x01, 0x0a, 0x12, 0x45, 0x78, 0x65, 0x63, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x14, 0x0a, + 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, + 0x64, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x64, + 0x65, 0x72, 0x72, 0x12, 0x28, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x15, 0x0a, + 0x13, 0x45, 0x78, 0x65, 0x63, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x69, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x50, 0x74, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, + 0x37, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x22, 0xd3, 0x02, 0x0a, 0x0d, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, + 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x03, 0x70, 0x69, 0x64, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x64, + 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, + 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, + 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x65, + 0x78, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0a, 0x65, 0x78, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x09, + 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 0x69, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x22, 0x60, + 0x0a, 0x0b, 0x4b, 0x69, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, + 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x12, 0x10, + 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x6c, 0x6c, + 0x22, 0x4f, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x49, 0x4f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, + 0x74, 0x64, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, + 0x6e, 0x22, 0x1d, 0x0a, 0x0b, 0x50, 0x69, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x22, 0x4e, 0x0a, 0x0c, 0x50, 0x69, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x3e, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, + 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x22, 0x6b, 0x0a, 0x15, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, + 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf1, 0x01, + 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x32, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, + 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x37, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x22, 0x21, 0x0a, 0x0d, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x36, 0x0a, + 0x0b, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, + 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, + 0x78, 0x65, 0x63, 0x49, 0x64, 0x22, 0x68, 0x0a, 0x0c, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x69, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, + 0x1e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x3b, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2a, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x20, 0x0a, 0x0e, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x61, + 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x68, 0x69, 0x6d, 0x50, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x74, 0x61, 0x73, 0x6b, 0x50, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0x33, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x03, 0x6e, 0x6f, 0x77, 0x22, 0x1e, 0x0a, 0x0c, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1f, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0x8a, 0x0a, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x4c, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, + 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, + 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, + 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, + 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, + 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x50, 0x69, 0x64, 0x73, 0x12, 0x1f, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, + 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x69, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, + 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x69, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x41, 0x0a, 0x05, 0x50, 0x61, 0x75, 0x73, 0x65, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, + 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x21, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, + 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4f, 0x0a, 0x0a, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, 0x04, 0x4b, 0x69, + 0x6c, 0x6c, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4b, 0x69, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x46, 0x0a, 0x04, 0x45, + 0x78, 0x65, 0x63, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x50, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x50, 0x74, 0x79, + 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, + 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x50, 0x74, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x45, + 0x0a, 0x07, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x49, 0x4f, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, + 0x6c, 0x6f, 0x73, 0x65, 0x49, 0x4f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x47, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, + 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x49, + 0x0a, 0x04, 0x57, 0x61, 0x69, 0x74, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x61, 0x69, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x61, 0x69, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x53, 0x74, 0x61, + 0x74, 0x73, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x08, 0x53, + 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x68, 0x75, + 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x74, 0x61, 0x73, 0x6b, 0x2f, 0x76, 0x32, 0x3b, 0x74, 0x61, 0x73, + 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_runtime_task_v2_shim_proto_rawDescOnce sync.Once + file_runtime_task_v2_shim_proto_rawDescData = file_runtime_task_v2_shim_proto_rawDesc +) + +func file_runtime_task_v2_shim_proto_rawDescGZIP() []byte { + file_runtime_task_v2_shim_proto_rawDescOnce.Do(func() { + file_runtime_task_v2_shim_proto_rawDescData = protoimpl.X.CompressGZIP(file_runtime_task_v2_shim_proto_rawDescData) + }) + return file_runtime_task_v2_shim_proto_rawDescData +} + +var file_runtime_task_v2_shim_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_runtime_task_v2_shim_proto_goTypes = []interface{}{ + (*CreateTaskRequest)(nil), // 0: containerd.task.v2.CreateTaskRequest + (*CreateTaskResponse)(nil), // 1: containerd.task.v2.CreateTaskResponse + (*DeleteRequest)(nil), // 2: containerd.task.v2.DeleteRequest + (*DeleteResponse)(nil), // 3: containerd.task.v2.DeleteResponse + (*ExecProcessRequest)(nil), // 4: containerd.task.v2.ExecProcessRequest + (*ExecProcessResponse)(nil), // 5: containerd.task.v2.ExecProcessResponse + (*ResizePtyRequest)(nil), // 6: containerd.task.v2.ResizePtyRequest + (*StateRequest)(nil), // 7: containerd.task.v2.StateRequest + (*StateResponse)(nil), // 8: containerd.task.v2.StateResponse + (*KillRequest)(nil), // 9: containerd.task.v2.KillRequest + (*CloseIORequest)(nil), // 10: containerd.task.v2.CloseIORequest + (*PidsRequest)(nil), // 11: containerd.task.v2.PidsRequest + (*PidsResponse)(nil), // 12: containerd.task.v2.PidsResponse + (*CheckpointTaskRequest)(nil), // 13: containerd.task.v2.CheckpointTaskRequest + (*UpdateTaskRequest)(nil), // 14: containerd.task.v2.UpdateTaskRequest + (*StartRequest)(nil), // 15: containerd.task.v2.StartRequest + (*StartResponse)(nil), // 16: containerd.task.v2.StartResponse + (*WaitRequest)(nil), // 17: containerd.task.v2.WaitRequest + (*WaitResponse)(nil), // 18: containerd.task.v2.WaitResponse + (*StatsRequest)(nil), // 19: containerd.task.v2.StatsRequest + (*StatsResponse)(nil), // 20: containerd.task.v2.StatsResponse + (*ConnectRequest)(nil), // 21: containerd.task.v2.ConnectRequest + (*ConnectResponse)(nil), // 22: containerd.task.v2.ConnectResponse + (*ShutdownRequest)(nil), // 23: containerd.task.v2.ShutdownRequest + (*PauseRequest)(nil), // 24: containerd.task.v2.PauseRequest + (*ResumeRequest)(nil), // 25: containerd.task.v2.ResumeRequest + nil, // 26: containerd.task.v2.UpdateTaskRequest.AnnotationsEntry + (*types.Mount)(nil), // 27: containerd.types.Mount + (*anypb.Any)(nil), // 28: google.protobuf.Any + (*timestamppb.Timestamp)(nil), // 29: google.protobuf.Timestamp + (task.Status)(0), // 30: containerd.v1.types.Status + (*task.ProcessInfo)(nil), // 31: containerd.v1.types.ProcessInfo + (*emptypb.Empty)(nil), // 32: google.protobuf.Empty +} +var file_runtime_task_v2_shim_proto_depIdxs = []int32{ + 27, // 0: containerd.task.v2.CreateTaskRequest.rootfs:type_name -> containerd.types.Mount + 28, // 1: containerd.task.v2.CreateTaskRequest.options:type_name -> google.protobuf.Any + 29, // 2: containerd.task.v2.DeleteResponse.exited_at:type_name -> google.protobuf.Timestamp + 28, // 3: containerd.task.v2.ExecProcessRequest.spec:type_name -> google.protobuf.Any + 30, // 4: containerd.task.v2.StateResponse.status:type_name -> containerd.v1.types.Status + 29, // 5: containerd.task.v2.StateResponse.exited_at:type_name -> google.protobuf.Timestamp + 31, // 6: containerd.task.v2.PidsResponse.processes:type_name -> containerd.v1.types.ProcessInfo + 28, // 7: containerd.task.v2.CheckpointTaskRequest.options:type_name -> google.protobuf.Any + 28, // 8: containerd.task.v2.UpdateTaskRequest.resources:type_name -> google.protobuf.Any + 26, // 9: containerd.task.v2.UpdateTaskRequest.annotations:type_name -> containerd.task.v2.UpdateTaskRequest.AnnotationsEntry + 29, // 10: containerd.task.v2.WaitResponse.exited_at:type_name -> google.protobuf.Timestamp + 28, // 11: containerd.task.v2.StatsResponse.stats:type_name -> google.protobuf.Any + 7, // 12: containerd.task.v2.Task.State:input_type -> containerd.task.v2.StateRequest + 0, // 13: containerd.task.v2.Task.Create:input_type -> containerd.task.v2.CreateTaskRequest + 15, // 14: containerd.task.v2.Task.Start:input_type -> containerd.task.v2.StartRequest + 2, // 15: containerd.task.v2.Task.Delete:input_type -> containerd.task.v2.DeleteRequest + 11, // 16: containerd.task.v2.Task.Pids:input_type -> containerd.task.v2.PidsRequest + 24, // 17: containerd.task.v2.Task.Pause:input_type -> containerd.task.v2.PauseRequest + 25, // 18: containerd.task.v2.Task.Resume:input_type -> containerd.task.v2.ResumeRequest + 13, // 19: containerd.task.v2.Task.Checkpoint:input_type -> containerd.task.v2.CheckpointTaskRequest + 9, // 20: containerd.task.v2.Task.Kill:input_type -> containerd.task.v2.KillRequest + 4, // 21: containerd.task.v2.Task.Exec:input_type -> containerd.task.v2.ExecProcessRequest + 6, // 22: containerd.task.v2.Task.ResizePty:input_type -> containerd.task.v2.ResizePtyRequest + 10, // 23: containerd.task.v2.Task.CloseIO:input_type -> containerd.task.v2.CloseIORequest + 14, // 24: containerd.task.v2.Task.Update:input_type -> containerd.task.v2.UpdateTaskRequest + 17, // 25: containerd.task.v2.Task.Wait:input_type -> containerd.task.v2.WaitRequest + 19, // 26: containerd.task.v2.Task.Stats:input_type -> containerd.task.v2.StatsRequest + 21, // 27: containerd.task.v2.Task.Connect:input_type -> containerd.task.v2.ConnectRequest + 23, // 28: containerd.task.v2.Task.Shutdown:input_type -> containerd.task.v2.ShutdownRequest + 8, // 29: containerd.task.v2.Task.State:output_type -> containerd.task.v2.StateResponse + 1, // 30: containerd.task.v2.Task.Create:output_type -> containerd.task.v2.CreateTaskResponse + 16, // 31: containerd.task.v2.Task.Start:output_type -> containerd.task.v2.StartResponse + 3, // 32: containerd.task.v2.Task.Delete:output_type -> containerd.task.v2.DeleteResponse + 12, // 33: containerd.task.v2.Task.Pids:output_type -> containerd.task.v2.PidsResponse + 32, // 34: containerd.task.v2.Task.Pause:output_type -> google.protobuf.Empty + 32, // 35: containerd.task.v2.Task.Resume:output_type -> google.protobuf.Empty + 32, // 36: containerd.task.v2.Task.Checkpoint:output_type -> google.protobuf.Empty + 32, // 37: containerd.task.v2.Task.Kill:output_type -> google.protobuf.Empty + 32, // 38: containerd.task.v2.Task.Exec:output_type -> google.protobuf.Empty + 32, // 39: containerd.task.v2.Task.ResizePty:output_type -> google.protobuf.Empty + 32, // 40: containerd.task.v2.Task.CloseIO:output_type -> google.protobuf.Empty + 32, // 41: containerd.task.v2.Task.Update:output_type -> google.protobuf.Empty + 18, // 42: containerd.task.v2.Task.Wait:output_type -> containerd.task.v2.WaitResponse + 20, // 43: containerd.task.v2.Task.Stats:output_type -> containerd.task.v2.StatsResponse + 22, // 44: containerd.task.v2.Task.Connect:output_type -> containerd.task.v2.ConnectResponse + 32, // 45: containerd.task.v2.Task.Shutdown:output_type -> google.protobuf.Empty + 29, // [29:46] is the sub-list for method output_type + 12, // [12:29] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_runtime_task_v2_shim_proto_init() } +func file_runtime_task_v2_shim_proto_init() { + if File_runtime_task_v2_shim_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_runtime_task_v2_shim_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateTaskResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExecProcessRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExecProcessResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResizePtyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KillRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CloseIORequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PidsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PidsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckpointTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WaitRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WaitResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConnectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConnectResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShutdownRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PauseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runtime_task_v2_shim_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResumeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_runtime_task_v2_shim_proto_rawDesc, + NumEnums: 0, + NumMessages: 27, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_runtime_task_v2_shim_proto_goTypes, + DependencyIndexes: file_runtime_task_v2_shim_proto_depIdxs, + MessageInfos: file_runtime_task_v2_shim_proto_msgTypes, + }.Build() + File_runtime_task_v2_shim_proto = out.File + file_runtime_task_v2_shim_proto_rawDesc = nil + file_runtime_task_v2_shim_proto_goTypes = nil + file_runtime_task_v2_shim_proto_depIdxs = nil +} diff --git a/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim.proto b/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim.proto new file mode 100644 index 00000000..6d9c36e0 --- /dev/null +++ b/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim.proto @@ -0,0 +1,200 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +syntax = "proto3"; + +package containerd.task.v2; + +import "google/protobuf/any.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; +import "types/mount.proto"; +import "types/task/task.proto"; + +option go_package = "github.com/containerd/containerd/api/runtime/task/v2;task"; + +// Shim service is launched for each container and is responsible for owning the IO +// for the container and its additional processes. The shim is also the parent of +// each container and allows reattaching to the IO and receiving the exit status +// for the container processes. +service Task { + rpc State(StateRequest) returns (StateResponse); + rpc Create(CreateTaskRequest) returns (CreateTaskResponse); + rpc Start(StartRequest) returns (StartResponse); + rpc Delete(DeleteRequest) returns (DeleteResponse); + rpc Pids(PidsRequest) returns (PidsResponse); + rpc Pause(PauseRequest) returns (google.protobuf.Empty); + rpc Resume(ResumeRequest) returns (google.protobuf.Empty); + rpc Checkpoint(CheckpointTaskRequest) returns (google.protobuf.Empty); + rpc Kill(KillRequest) returns (google.protobuf.Empty); + rpc Exec(ExecProcessRequest) returns (google.protobuf.Empty); + rpc ResizePty(ResizePtyRequest) returns (google.protobuf.Empty); + rpc CloseIO(CloseIORequest) returns (google.protobuf.Empty); + rpc Update(UpdateTaskRequest) returns (google.protobuf.Empty); + rpc Wait(WaitRequest) returns (WaitResponse); + rpc Stats(StatsRequest) returns (StatsResponse); + rpc Connect(ConnectRequest) returns (ConnectResponse); + rpc Shutdown(ShutdownRequest) returns (google.protobuf.Empty); +} + +message CreateTaskRequest { + string id = 1; + string bundle = 2; + repeated containerd.types.Mount rootfs = 3; + bool terminal = 4; + string stdin = 5; + string stdout = 6; + string stderr = 7; + string checkpoint = 8; + string parent_checkpoint = 9; + google.protobuf.Any options = 10; +} + +message CreateTaskResponse { + uint32 pid = 1; +} + +message DeleteRequest { + string id = 1; + string exec_id = 2; +} + +message DeleteResponse { + uint32 pid = 1; + uint32 exit_status = 2; + google.protobuf.Timestamp exited_at = 3; +} + +message ExecProcessRequest { + string id = 1; + string exec_id = 2; + bool terminal = 3; + string stdin = 4; + string stdout = 5; + string stderr = 6; + google.protobuf.Any spec = 7; +} + +message ExecProcessResponse {} + +message ResizePtyRequest { + string id = 1; + string exec_id = 2; + uint32 width = 3; + uint32 height = 4; +} + +message StateRequest { + string id = 1; + string exec_id = 2; +} + +message StateResponse { + string id = 1; + string bundle = 2; + uint32 pid = 3; + containerd.v1.types.Status status = 4; + string stdin = 5; + string stdout = 6; + string stderr = 7; + bool terminal = 8; + uint32 exit_status = 9; + google.protobuf.Timestamp exited_at = 10; + string exec_id = 11; +} + +message KillRequest { + string id = 1; + string exec_id = 2; + uint32 signal = 3; + bool all = 4; +} + +message CloseIORequest { + string id = 1; + string exec_id = 2; + bool stdin = 3; +} + +message PidsRequest { + string id = 1; +} + +message PidsResponse { + repeated containerd.v1.types.ProcessInfo processes = 1; +} + +message CheckpointTaskRequest { + string id = 1; + string path = 2; + google.protobuf.Any options = 3; +} + +message UpdateTaskRequest { + string id = 1; + google.protobuf.Any resources = 2; + map annotations = 3; +} + +message StartRequest { + string id = 1; + string exec_id = 2; +} + +message StartResponse { + uint32 pid = 1; +} + +message WaitRequest { + string id = 1; + string exec_id = 2; +} + +message WaitResponse { + uint32 exit_status = 1; + google.protobuf.Timestamp exited_at = 2; +} + +message StatsRequest { + string id = 1; +} + +message StatsResponse { + google.protobuf.Any stats = 1; +} + +message ConnectRequest { + string id = 1; +} + +message ConnectResponse { + uint32 shim_pid = 1; + uint32 task_pid = 2; + string version = 3; +} + +message ShutdownRequest { + string id = 1; + bool now = 2; +} + +message PauseRequest { + string id = 1; +} + +message ResumeRequest { + string id = 1; +} diff --git a/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim_ttrpc.pb.go b/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim_ttrpc.pb.go new file mode 100644 index 00000000..822d7dad --- /dev/null +++ b/vendor/github.com/containerd/containerd/api/runtime/task/v2/shim_ttrpc.pb.go @@ -0,0 +1,301 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: runtime/task/v2/shim.proto +package task + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCTaskService interface { + State(context.Context, *StateRequest) (*StateResponse, error) + Create(context.Context, *CreateTaskRequest) (*CreateTaskResponse, error) + Start(context.Context, *StartRequest) (*StartResponse, error) + Delete(context.Context, *DeleteRequest) (*DeleteResponse, error) + Pids(context.Context, *PidsRequest) (*PidsResponse, error) + Pause(context.Context, *PauseRequest) (*emptypb.Empty, error) + Resume(context.Context, *ResumeRequest) (*emptypb.Empty, error) + Checkpoint(context.Context, *CheckpointTaskRequest) (*emptypb.Empty, error) + Kill(context.Context, *KillRequest) (*emptypb.Empty, error) + Exec(context.Context, *ExecProcessRequest) (*emptypb.Empty, error) + ResizePty(context.Context, *ResizePtyRequest) (*emptypb.Empty, error) + CloseIO(context.Context, *CloseIORequest) (*emptypb.Empty, error) + Update(context.Context, *UpdateTaskRequest) (*emptypb.Empty, error) + Wait(context.Context, *WaitRequest) (*WaitResponse, error) + Stats(context.Context, *StatsRequest) (*StatsResponse, error) + Connect(context.Context, *ConnectRequest) (*ConnectResponse, error) + Shutdown(context.Context, *ShutdownRequest) (*emptypb.Empty, error) +} + +func RegisterTTRPCTaskService(srv *ttrpc.Server, svc TTRPCTaskService) { + srv.RegisterService("containerd.task.v2.Task", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "State": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StateRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.State(ctx, &req) + }, + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Start": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StartRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Start(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + "Pids": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PidsRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Pids(ctx, &req) + }, + "Pause": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PauseRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Pause(ctx, &req) + }, + "Resume": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ResumeRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Resume(ctx, &req) + }, + "Checkpoint": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CheckpointTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Checkpoint(ctx, &req) + }, + "Kill": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req KillRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Kill(ctx, &req) + }, + "Exec": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ExecProcessRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Exec(ctx, &req) + }, + "ResizePty": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ResizePtyRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.ResizePty(ctx, &req) + }, + "CloseIO": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CloseIORequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.CloseIO(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UpdateTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Wait": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req WaitRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Wait(ctx, &req) + }, + "Stats": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StatsRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Stats(ctx, &req) + }, + "Connect": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ConnectRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Connect(ctx, &req) + }, + "Shutdown": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ShutdownRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Shutdown(ctx, &req) + }, + }, + }) +} + +type ttrpctaskClient struct { + client *ttrpc.Client +} + +func NewTTRPCTaskClient(client *ttrpc.Client) TTRPCTaskService { + return &ttrpctaskClient{ + client: client, + } +} + +func (c *ttrpctaskClient) State(ctx context.Context, req *StateRequest) (*StateResponse, error) { + var resp StateResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "State", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error) { + var resp CreateTaskResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Start(ctx context.Context, req *StartRequest) (*StartResponse, error) { + var resp StartResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Start", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Delete(ctx context.Context, req *DeleteRequest) (*DeleteResponse, error) { + var resp DeleteResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Pids(ctx context.Context, req *PidsRequest) (*PidsResponse, error) { + var resp PidsResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Pids", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Pause(ctx context.Context, req *PauseRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Pause", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Resume(ctx context.Context, req *ResumeRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Resume", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Checkpoint", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Kill(ctx context.Context, req *KillRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Kill", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Exec(ctx context.Context, req *ExecProcessRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Exec", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) ResizePty(ctx context.Context, req *ResizePtyRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "ResizePty", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) CloseIO(ctx context.Context, req *CloseIORequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "CloseIO", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Update(ctx context.Context, req *UpdateTaskRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) { + var resp WaitResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Wait", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Stats(ctx context.Context, req *StatsRequest) (*StatsResponse, error) { + var resp StatsResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Stats", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Connect(ctx context.Context, req *ConnectRequest) (*ConnectResponse, error) { + var resp ConnectResponse + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Connect", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctaskClient) Shutdown(ctx context.Context, req *ShutdownRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.task.v2.Task", "Shutdown", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/vendor/github.com/containerd/shimtest/README.md b/vendor/github.com/containerd/shimtest/README.md index 7f702f41..b563ca58 100644 --- a/vendor/github.com/containerd/shimtest/README.md +++ b/vendor/github.com/containerd/shimtest/README.md @@ -95,6 +95,7 @@ config, the tree is `TestShim//`. | `Exec` | exec | Exec a process inside a running container | | `StdioRoundTrip` | exec | Write to stdin, read from stdout via exec | | `LargeStdioRoundTrip` | exec | Pipe 20 MiB through stdin→`cat`→stdout via exec; verify full byte count and CRC-32. Catches truncation in the exec stdio pipeline under sustained load | +| `StdinDetachReattach` | exec | Write to an exec's stdin, close the local write end without CloseIO (detach), then open a new writer on the same stdin path (re-attach) and write again; verify both writes reach stdout. Only an explicit CloseIO may deliver stdin EOF | | `Clock` | exec | Verify VM clock is synchronized with host | | `ExitCodes` | exec | Exec processes that exit with a range of status codes and verify propagation | | `InitExitCodes` | — | Run the container's init process with `/bin/exit N` and verify task-level exit status propagation | diff --git a/vendor/github.com/containerd/shimtest/exec_bench.go b/vendor/github.com/containerd/shimtest/exec_bench.go index 5617e860..f48b0fe5 100644 --- a/vendor/github.com/containerd/shimtest/exec_bench.go +++ b/vendor/github.com/containerd/shimtest/exec_bench.go @@ -59,7 +59,7 @@ func (s *ExecSuite) benchExec(b *testing.B) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(b, ctx, stdoutPath) drainFifo(b, ctx, stderrPath) @@ -134,7 +134,7 @@ func (s *ExecSuite) benchStdioRoundTrip(b *testing.B) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(b, ctx, stdoutPath) drainFifo(b, ctx, stderrPath) @@ -294,7 +294,7 @@ func (s *ExecSuite) benchHashverify(b *testing.B, path, hashHex string, extraMou client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(b, ctx, stdoutPath) drainFifo(b, ctx, stderrPath) diff --git a/vendor/github.com/containerd/shimtest/exec_suite.go b/vendor/github.com/containerd/shimtest/exec_suite.go index 346562fb..102378a7 100644 --- a/vendor/github.com/containerd/shimtest/exec_suite.go +++ b/vendor/github.com/containerd/shimtest/exec_suite.go @@ -58,6 +58,7 @@ func (s *ExecSuite) Run(t *testing.T) { t.Run("Exec", s.testExec) t.Run("StdioRoundTrip", s.testStdioRoundTrip) t.Run("LargeStdioRoundTrip", s.testLargeStdioRoundTrip) + t.Run("StdinDetachReattach", s.testStdinDetachReattach) t.Run("Clock", s.testClock) t.Run("ExitCodes", s.testExitCodes) t.Run("LargeFileRead", s.testLargeFileRead) @@ -85,7 +86,7 @@ func (s *ExecSuite) testExec(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -172,7 +173,7 @@ func (s *ExecSuite) testStdioRoundTrip(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -271,7 +272,7 @@ func (s *ExecSuite) testClock(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -373,7 +374,7 @@ func (s *ExecSuite) testExitCodes(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -491,7 +492,7 @@ func (s *ExecSuite) runHashverify(t *testing.T, path, hashHex string, extraMount client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -614,7 +615,7 @@ func (s *ExecSuite) testLargeStdioRoundTrip(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -755,6 +756,155 @@ func (s *ExecSuite) testLargeStdioRoundTrip(t *testing.T) { tc.Shutdown(ctx, &taskAPI.ShutdownRequest{ID: containerID}) } +// testStdinDetachReattach verifies the detach/re-attach half of the stdin +// EOF contract described in testLargeStdioRoundTrip: a client closing its +// own stdin write end, without issuing CloseIO, must not deliver EOF to +// the process. This lets one client detach from stdin and a later client +// attach and continue writing to the same process, exactly as `ctr +// attach` followed by a later re-attach would require. Only an explicit +// CloseIO(Stdin=true) may cause the process to observe stdin EOF. +// +// The test writes a line to the exec's stdin, closes only its own write +// end (detach) without CloseIO, then opens a new writer on the same stdin +// path (re-attach) and writes a second line. Since /bin/cat's stdin must +// not have seen EOF after the first detach, both lines must appear on +// stdout. CloseIO is then issued to let the process exit. +// +// The first writer is opened before Exec, matching the convention used by +// testLargeStdioRoundTrip and testStdioRoundTrip: on Windows the shim +// dials the stdin pipe synchronously as part of the Exec RPC, so the +// test's server-side Accept must already be in flight (openPipeWriter +// starts it in a background goroutine) before that RPC is issued, or the +// dial has nothing to connect to within its timeout. +func (s *ExecSuite) testStdinDetachReattach(t *testing.T) { + shimBin, bundleDir, rootfsMounts := shimSetup(t, s.cfg) + containerID := containerID(t) + + createOCISpec(t, bundleDir, []string{"/bin/forever"}, s.cfg) + + stdoutPath, stderrPath := createIOFifos(t, bundleDir) + ns := uniqueTestNamespace(t, "exec") + ctx := namespaces.WithNamespace(t.Context(), ns) + + params := startShim(t, shimBin, bundleDir, containerID, ns, s.cfg) + conn := connectShim(t, params.Address) + client := ttrpc.NewClient(conn) + defer client.Close() + + tc := taskAPI.NewTTRPCTaskClient(client) + + drainFifo(t, ctx, stdoutPath) + drainFifo(t, ctx, stderrPath) + + if _, err := tc.Create(ctx, newCreateTaskRequest(t, containerID, bundleDir, stdoutPath, stderrPath, rootfsMounts)); err != nil { + t.Fatal("create failed:", err) + } + if _, err := tc.Start(ctx, &taskAPI.StartRequest{ID: containerID}); err != nil { + t.Fatal("start failed:", err) + } + + execID := "detach-rt" + execDir := t.TempDir() + execStdin, execStdout, execStderr := createStdioFifos(t, execDir) + + var outBuf bytes.Buffer + var outMu sync.Mutex + drainFifoInto(t, ctx, execStdout, &outBuf, &outMu) + drainFifo(t, ctx, execStderr) + + // Open the first writer before Exec (see the doc comment above for + // why this ordering matters). + w1, err := openPipeWriter(ctx, execStdin) + if err != nil { + t.Fatal("open stdin (first writer):", err) + } + + procSpec, err := typeurl.MarshalAnyToProto(&specs.Process{ + Args: []string{"/bin/cat"}, + Cwd: "/", + Env: []string{"PATH=/bin:/usr/bin"}, + }) + if err != nil { + t.Fatal("marshal exec spec:", err) + } + + if _, err := tc.Exec(ctx, &taskAPI.ExecProcessRequest{ + ID: containerID, + ExecID: execID, + Spec: procSpec, + Stdin: execStdin, + Stdout: execStdout, + Stderr: execStderr, + }); err != nil { + t.Fatal("exec failed:", err) + } + if _, err := tc.Start(ctx, &taskAPI.StartRequest{ID: containerID, ExecID: execID}); err != nil { + t.Fatal("exec start failed:", err) + } + + // First writer: write a line, then detach by closing only the local + // write end. No CloseIO is issued here, so the shim API must not + // deliver EOF to the process. + if _, err := w1.Write([]byte("first\n")); err != nil { + t.Fatal("write first line:", err) + } + w1.Close() + + // Give the process a moment to have (incorrectly) observed EOF here + // if the shim does not honor detach semantics. + time.Sleep(500 * time.Millisecond) + + // Second writer: a new client re-opens the same stdin FIFO path + // ("re-attach") and writes a second line. If the process had already + // exited after the first writer detached, this data would never reach + // stdout even though the write itself may still succeed. + w2, err := openPipeWriter(ctx, execStdin) + if err != nil { + t.Fatal("open stdin (second writer, re-attach):", err) + } + if _, err := w2.Write([]byte("second\n")); err != nil { + t.Fatal("write second line:", err) + } + w2.Close() + + // Give cat a moment to read and echo the second line before EOF. + time.Sleep(500 * time.Millisecond) + + // Now signal real EOF via CloseIO so the process exits. + if _, err := tc.CloseIO(ctx, &taskAPI.CloseIORequest{ + ID: containerID, + ExecID: execID, + Stdin: true, + }); err != nil { + t.Fatal("CloseIO failed:", err) + } + + waitResp, err := tc.Wait(ctx, &taskAPI.WaitRequest{ID: containerID, ExecID: execID}) + if err != nil { + t.Fatal("exec wait failed:", err) + } + if waitResp.ExitStatus != 0 { + t.Fatalf("cat exited with status %d", waitResp.ExitStatus) + } + + if _, err := tc.Delete(ctx, &taskAPI.DeleteRequest{ID: containerID, ExecID: execID}); err != nil { + t.Fatal("exec delete failed:", err) + } + + outMu.Lock() + out := outBuf.String() + outMu.Unlock() + + if !strings.Contains(out, "first") || !strings.Contains(out, "second") { + t.Fatalf("expected output to contain both the pre-detach and post-reattach writes, got: %q", out) + } + + tc.Kill(ctx, &taskAPI.KillRequest{ID: containerID, Signal: uint32(syscall.SIGKILL), All: true}) + tc.Wait(ctx, &taskAPI.WaitRequest{ID: containerID}) + tc.Delete(ctx, &taskAPI.DeleteRequest{ID: containerID}) + tc.Shutdown(ctx, &taskAPI.ShutdownRequest{ID: containerID}) +} + // burstPayloadSize is the number of bytes written by /bin/burstexit in // the FastExitOutput and FastExitInit tests. It must be large enough // that the kernel socket buffers cannot absorb the entire stream @@ -852,7 +1002,7 @@ func (s *ExecSuite) testFastExitOutput(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -972,7 +1122,7 @@ func (s *ExecSuite) testExecOutputDrainAfterExit(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) if _, err := tc.Create(ctx, newCreateTaskRequest(t, containerID, bundleDir, "", "", rootfsMounts)); err != nil { t.Fatal("create failed:", err) @@ -1069,7 +1219,7 @@ func (s *ExecSuite) testExecDiscardIO(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -1151,7 +1301,7 @@ func (s *ExecSuite) testExecCommandNotFound(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) diff --git a/vendor/github.com/containerd/shimtest/helpers.go b/vendor/github.com/containerd/shimtest/helpers.go index 3f641a9a..af29c264 100644 --- a/vendor/github.com/containerd/shimtest/helpers.go +++ b/vendor/github.com/containerd/shimtest/helpers.go @@ -36,6 +36,7 @@ import ( runcopt "github.com/containerd/containerd/api/types/runc/options" "github.com/containerd/containerd/v2/core/mount" "github.com/containerd/ttrpc" + "github.com/containerd/typeurl/v2" "github.com/opencontainers/runtime-spec/specs-go" "google.golang.org/protobuf/encoding/protowire" @@ -478,6 +479,14 @@ func startShim(tb testing.TB, shimBin, bundleDir, id, ns string, cfg Config) boo if params.Address == "" { tb.Fatal("shim returned empty address") } + if params.Version == 0 { + // A params payload without a version is treated as a version 2 + // shim, matching containerd. + params.Version = 2 + } + if params.Version != 2 && params.Version != 3 { + tb.Fatalf("unsupported shim task API version %d", params.Version) + } tb.Cleanup(func() { // Match containerd's cleanup behavior: invoke the shim binary's @@ -516,6 +525,7 @@ func deleteShim(tb testing.TB, shimBin, bundleDir, id, ns string, cfg Config) { defer cancel() cmd := exec.CommandContext(ctx, shimBin, args...) cmd.Dir = bundleDir + cmd.Env = append(os.Environ(), "TTRPC_ADDRESS="+containerdAddr) var stderr bytes.Buffer cmd.Stderr = &stderr @@ -524,6 +534,14 @@ func deleteShim(tb testing.TB, shimBin, bundleDir, id, ns string, cfg Config) { } } +// newTaskClient returns the task client for the API version the shim +// declared in its bootstrap params, exactly as containerd selects it +// (core/runtime/v2 NewTaskClient): a version 3 shim is dialed on +// containerd.task.v3.Task, a version 2 shim through the v2 bridge. +func newTaskClient(client *ttrpc.Client, version int) taskAPI.TTRPCTaskService { + return taskClientForVersion(client, version) +} + // shimPidViaConnect dials the shim's TTRPC address and asks for its // pid via the task service Connect RPC. Retries with a short backoff // for up to retryFor since the server may take a few milliseconds to @@ -534,7 +552,7 @@ func deleteShim(tb testing.TB, shimBin, bundleDir, id, ns string, cfg Config) { // it after tc.Create when every conformant shim responds. // // dialShimConn is platform-specific (connect_unix.go / connect_windows.go). -func shimPidViaConnect(address, id string, retryFor time.Duration) (int, error) { +func shimPidViaConnect(address, id string, version int, retryFor time.Duration) (int, error) { deadline := time.Now().Add(retryFor) var lastErr error for { @@ -543,7 +561,7 @@ func shimPidViaConnect(address, id string, retryFor time.Duration) (int, error) lastErr = fmt.Errorf("dial: %w", err) } else { client := ttrpc.NewClient(conn) - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, version) ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) resp, callErr := tc.Connect(ctx, &taskAPI.ConnectRequest{ID: id}) cancel() diff --git a/vendor/github.com/containerd/shimtest/layers_bench.go b/vendor/github.com/containerd/shimtest/layers_bench.go index fe89f818..6b6f708b 100644 --- a/vendor/github.com/containerd/shimtest/layers_bench.go +++ b/vendor/github.com/containerd/shimtest/layers_bench.go @@ -115,7 +115,7 @@ func (s *LayersSuite) benchThirtyLayers(b *testing.B) { params := startShim(b, shimBin, bundleDir, cid, ns, s.cfg) conn := connectShim(b, params.Address) client := ttrpc.NewClient(conn) - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) tShimStart := time.Since(t0) t1 := time.Now() diff --git a/vendor/github.com/containerd/shimtest/layers_suite.go b/vendor/github.com/containerd/shimtest/layers_suite.go index 3ecf1c96..58ffde2e 100644 --- a/vendor/github.com/containerd/shimtest/layers_suite.go +++ b/vendor/github.com/containerd/shimtest/layers_suite.go @@ -122,7 +122,7 @@ func (s *LayersSuite) testHundredLayers(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) diff --git a/vendor/github.com/containerd/shimtest/network_suite.go b/vendor/github.com/containerd/shimtest/network_suite.go index e320f020..7c5b06f3 100644 --- a/vendor/github.com/containerd/shimtest/network_suite.go +++ b/vendor/github.com/containerd/shimtest/network_suite.go @@ -130,13 +130,24 @@ func (s *NetworkSuite) testOutboundTCP(t *testing.T) { client := ttrpc.NewClient(shimConn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) var stdoutBuf bytes.Buffer var stdoutMu sync.Mutex stdoutDone := drainFifoIntoDone(t, ctx, stdoutPath, &stdoutBuf, &stdoutMu) drainFifo(t, ctx, stderrPath) + // Open the stdin pipe writer before Create. On Windows the shim dials + // the stdin named pipe synchronously during the Create RPC, so the + // server-side listener must already be accepting before that call is + // issued — exactly the same ordering constraint as with exec stdin in + // testStdinDetachReattach. openPipeWriter starts the Accept in a + // background goroutine so the call returns immediately. + stdinFifo, err := openPipeWriter(ctx, stdinPath) + if err != nil { + t.Fatalf("open stdin fifo: %v", err) + } + if _, err := tc.Create(ctx, newCreateTaskRequestStdin(t, cid, bundleDir, stdinPath, stdoutPath, stderrPath, rootfsMounts)); err != nil { t.Fatal("create failed:", err) } @@ -145,15 +156,20 @@ func (s *NetworkSuite) testOutboundTCP(t *testing.T) { } // Write the token to the container's stdin so nc sends it to the host. - stdinFifo, err := openPipeWriter(ctx, stdinPath) - if err != nil { - t.Fatalf("open stdin fifo: %v", err) - } if _, err := fmt.Fprintf(stdinFifo, "%s\n", token); err != nil { t.Fatalf("write token to stdin: %v", err) } stdinFifo.Close() + // Signal EOF to nc via the CloseIO RPC. Closing the test's own FIFO + // write end alone is not sufficient: the shim holds its own write-end + // reference on the stdin FIFO and only releases it upon CloseIO, + // exactly as documented for exec stdin in exec_suite.go. Without this + // call the container's init process would never observe stdin EOF. + if _, err := tc.CloseIO(ctx, &taskAPI.CloseIORequest{ID: cid, Stdin: true}); err != nil { + t.Fatal("close stdin failed:", err) + } + waitResp, err := tc.Wait(ctx, &taskAPI.WaitRequest{ID: cid}) if err != nil { t.Fatal("wait failed:", err) @@ -244,13 +260,21 @@ func (s *NetworkSuite) testOutboundUDP(t *testing.T) { client := ttrpc.NewClient(shimConn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) var stdoutBuf bytes.Buffer var stdoutMu sync.Mutex stdoutDone := drainFifoIntoDone(t, ctx, stdoutPath, &stdoutBuf, &stdoutMu) drainFifo(t, ctx, stderrPath) + // Open the stdin pipe writer before Create for the same reason as + // testOutboundTCP: the shim dials stdin synchronously during Create on + // Windows, so the listener must be accepting before that RPC is issued. + stdinFifo, err := openPipeWriter(ctx, stdinPath) + if err != nil { + t.Fatalf("open stdin fifo: %v", err) + } + if _, err := tc.Create(ctx, newCreateTaskRequestStdin(t, cid, bundleDir, stdinPath, stdoutPath, stderrPath, rootfsMounts)); err != nil { t.Fatal("create failed:", err) } @@ -259,15 +283,17 @@ func (s *NetworkSuite) testOutboundUDP(t *testing.T) { } // Write the token to stdin and close so nc reads EOF and sends one datagram. - stdinFifo, err := openPipeWriter(ctx, stdinPath) - if err != nil { - t.Fatalf("open stdin fifo: %v", err) - } if _, err := fmt.Fprint(stdinFifo, token); err != nil { t.Fatalf("write token to stdin: %v", err) } stdinFifo.Close() + // Signal EOF to nc via the CloseIO RPC; see testOutboundTCP for why + // closing the test's own FIFO write end alone is not sufficient. + if _, err := tc.CloseIO(ctx, &taskAPI.CloseIORequest{ID: cid, Stdin: true}); err != nil { + t.Fatal("close stdin failed:", err) + } + waitResp, err := tc.Wait(ctx, &taskAPI.WaitRequest{ID: cid}) if err != nil { t.Fatal("wait failed:", err) @@ -334,7 +360,7 @@ func (s *NetworkSuite) testDNSResolve(t *testing.T) { client := ttrpc.NewClient(shimConn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) var stdoutBuf bytes.Buffer var stdoutMu sync.Mutex diff --git a/vendor/github.com/containerd/shimtest/oom_suite.go b/vendor/github.com/containerd/shimtest/oom_suite.go index 786b54b6..ff216c1f 100644 --- a/vendor/github.com/containerd/shimtest/oom_suite.go +++ b/vendor/github.com/containerd/shimtest/oom_suite.go @@ -63,7 +63,7 @@ func (s *OOMSuite) testOOM(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) diff --git a/vendor/github.com/containerd/shimtest/run_bench.go b/vendor/github.com/containerd/shimtest/run_bench.go index 49fcb8b7..d73f773d 100644 --- a/vendor/github.com/containerd/shimtest/run_bench.go +++ b/vendor/github.com/containerd/shimtest/run_bench.go @@ -98,7 +98,7 @@ func (s *RunSuite) benchLifecycle(b *testing.B) { params := startShim(b, shimBin, bundleDir, cid, ns, s.cfg) conn := connectShim(b, params.Address) client := ttrpc.NewClient(conn) - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) sumShim += time.Since(t) t = time.Now() @@ -194,7 +194,7 @@ func (s *RunSuite) benchStartup(b *testing.B) { params := startShim(b, shimBin, bundleDir, cid, ns, s.cfg) conn := connectShim(b, params.Address) client := ttrpc.NewClient(conn) - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) if _, err := tc.Create(ctx, newCreateTaskRequest(b, cid, bundleDir, stdoutPath, stderrPath, rootfsMounts)); err != nil { b.Fatal("create failed:", err) @@ -279,7 +279,7 @@ func (s *RunSuite) benchStartupPhases(b *testing.B) { t1 := time.Now() conn := connectShim(b, params.Address) client := ttrpc.NewClient(conn) - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) tConnect := time.Since(t1) t2 := time.Now() @@ -383,7 +383,7 @@ func (s *RunSuite) benchStart(b *testing.B) { conn := connectShim(b, params.Address) client := ttrpc.NewClient(conn) - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) tc.Shutdown(ctx, &taskAPI.ShutdownRequest{ID: cid}) client.Close() } diff --git a/vendor/github.com/containerd/shimtest/run_suite.go b/vendor/github.com/containerd/shimtest/run_suite.go index 68005dcf..8836d264 100644 --- a/vendor/github.com/containerd/shimtest/run_suite.go +++ b/vendor/github.com/containerd/shimtest/run_suite.go @@ -31,6 +31,8 @@ import ( taskAPI "github.com/containerd/containerd/api/runtime/task/v3" tasktypes "github.com/containerd/containerd/api/types/task" "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/errdefs" + "github.com/containerd/errdefs/pkg/errgrpc" "github.com/containerd/ttrpc" typeurl "github.com/containerd/typeurl/v2" ) @@ -79,7 +81,7 @@ func (s *RunSuite) testLifecycle(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) var stdoutBuf bytes.Buffer var stdoutMu sync.Mutex @@ -133,7 +135,13 @@ func (s *RunSuite) testLifecycle(t *testing.T) { Signal: uint32(syscall.SIGKILL), All: true, }); err != nil { - t.Fatal("failed to kill task:", err) + // The process may have exited naturally before Kill is called. + // NotFound means the process is already in a terminal state, + // which is fine - proceed to Wait and Delete. + if !errdefs.IsNotFound(errgrpc.ToNative(err)) { + t.Fatal("failed to kill task:", err) + } + t.Log("task already finished before kill (benign race):", err) } t.Log("waiting for task exit") @@ -173,7 +181,7 @@ func (s *RunSuite) testInitExitCodes(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -217,7 +225,7 @@ func (s *RunSuite) testOutputThenExit(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) var stdoutBuf bytes.Buffer var stdoutMu sync.Mutex @@ -298,7 +306,7 @@ func (s *RunSuite) testEvents(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) @@ -397,7 +405,7 @@ func (s *RunSuite) testFastExitInit(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) var stdoutBuf bytes.Buffer var stdoutMu sync.Mutex diff --git a/vendor/github.com/containerd/shimtest/shimenv.go b/vendor/github.com/containerd/shimtest/shimenv.go index 4e5da5be..d2794ff5 100644 --- a/vendor/github.com/containerd/shimtest/shimenv.go +++ b/vendor/github.com/containerd/shimtest/shimenv.go @@ -84,7 +84,7 @@ func newShimEnv(tb testing.TB, baseCtx context.Context, cfg Config, suite string client := ttrpc.NewClient(conn) tb.Cleanup(func() { client.Close() }) - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) sc := &ttrpcStreamCreator{client: streamingapi.NewTTRPCStreamingClient(client)} @@ -103,7 +103,7 @@ func newShimEnv(tb testing.TB, baseCtx context.Context, cfg Config, suite string // also respond. Falls back to shim.pid for shims that fail // Connect entirely. shimPID := 0 - if pid, err := shimPidViaConnect(params.Address, cid, 1*time.Second); err == nil { + if pid, err := shimPidViaConnect(params.Address, cid, params.Version, 1*time.Second); err == nil { shimPID = pid } else if data, err := os.ReadFile(filepath.Join(bundleDir, "shim.pid")); err == nil { shimPID, _ = parseIntBytes(data) diff --git a/vendor/github.com/containerd/shimtest/stress_suite.go b/vendor/github.com/containerd/shimtest/stress_suite.go index 921ad6f6..44dcb6d5 100644 --- a/vendor/github.com/containerd/shimtest/stress_suite.go +++ b/vendor/github.com/containerd/shimtest/stress_suite.go @@ -152,7 +152,7 @@ func doFullLifecycle(t *testing.T, baseCtx context.Context, cfg Config, ttrpcClo client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) var stdoutBuf bytes.Buffer var stdoutMu sync.Mutex @@ -753,7 +753,7 @@ func runExecRoundTrip(parentCtx context.Context, env *shimEnv, execID string, si } // Stream the tiled payload to stdin without allocating the full - // buffer; closing stdin signals EOF to /bin/cat, causing it to exit. + // buffer, then close the local write end. writeDone := make(chan error, 1) go func() { _, err := io.Copy(stdin, io.LimitReader(&infiniteTileReader{}, int64(size))) @@ -770,6 +770,14 @@ func runExecRoundTrip(parentCtx context.Context, env *shimEnv, execID string, si return fmt.Errorf("stdin write timed out: %w", subCtx.Err()) } + // Signal EOF to /bin/cat via the CloseIO RPC. Closing the local FIFO + // write end alone is not sufficient: the shim holds its own write-end + // reference on the stdin FIFO and only releases it upon CloseIO (see + // exec_suite.go's testLargeStdioRoundTrip for the full contract). + if _, err := env.tc.CloseIO(subCtx, &taskAPI.CloseIORequest{ID: env.containerID, ExecID: execID, Stdin: true}); err != nil { + return fmt.Errorf("close stdin: %w", err) + } + if _, err := env.tc.Wait(subCtx, &taskAPI.WaitRequest{ID: env.containerID, ExecID: execID}); err != nil { return fmt.Errorf("wait: %w", err) } diff --git a/vendor/github.com/containerd/shimtest/taskclient.go b/vendor/github.com/containerd/shimtest/taskclient.go new file mode 100644 index 00000000..04cd0b1f --- /dev/null +++ b/vendor/github.com/containerd/shimtest/taskclient.go @@ -0,0 +1,213 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package shimtest + +import ( + "context" + "fmt" + + taskV2 "github.com/containerd/containerd/api/runtime/task/v2" + taskAPI "github.com/containerd/containerd/api/runtime/task/v3" + "github.com/containerd/ttrpc" + "google.golang.org/protobuf/types/known/emptypb" +) + +// taskClientForVersion selects the TTRPC task client for the API +// version a shim declared in its bootstrap params, matching +// containerd's own dispatch: a version 3 shim is dialed on +// containerd.task.v3.Task directly, a version 2 shim through the +// ttrpcV2Bridge below, which translates every v3 request/response +// pair to and from the v2 wire format. +// +// This mirrors the client-selection behavior of containerd's +// core/runtime/v2 NewTaskClient without importing that higher +// level package. +func taskClientForVersion(client *ttrpc.Client, version int) taskAPI.TTRPCTaskService { + switch version { + case 2: + return &ttrpcV2Bridge{client: taskV2.NewTTRPCTaskClient(client)} + case 3: + return taskAPI.NewTTRPCTaskClient(client) + default: + // Unreachable: startShim validated the version at bootstrap. + panic(fmt.Errorf("unsupported shim task API version %d", version)) + } +} + +// ttrpcV2Bridge adapts a containerd.task.v2.Task TTRPC client to the +// taskAPI.TTRPCTaskService (v3) interface used throughout this repo, +// so callers don't need to special-case the shim's declared version. +type ttrpcV2Bridge struct { + client taskV2.TTRPCTaskService +} + +var _ taskAPI.TTRPCTaskService = (*ttrpcV2Bridge)(nil) + +func (b *ttrpcV2Bridge) State(ctx context.Context, req *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { + resp, err := b.client.State(ctx, &taskV2.StateRequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + }) + return &taskAPI.StateResponse{ + ID: resp.GetID(), + Bundle: resp.GetBundle(), + Pid: resp.GetPid(), + Status: resp.GetStatus(), + Stdin: resp.GetStdin(), + Stdout: resp.GetStdout(), + Stderr: resp.GetStderr(), + Terminal: resp.GetTerminal(), + ExitStatus: resp.GetExitStatus(), + ExitedAt: resp.GetExitedAt(), + ExecID: resp.GetExecID(), + }, err +} + +func (b *ttrpcV2Bridge) Create(ctx context.Context, req *taskAPI.CreateTaskRequest) (*taskAPI.CreateTaskResponse, error) { + resp, err := b.client.Create(ctx, &taskV2.CreateTaskRequest{ + ID: req.GetID(), + Bundle: req.GetBundle(), + Rootfs: req.GetRootfs(), + Terminal: req.GetTerminal(), + Stdin: req.GetStdin(), + Stdout: req.GetStdout(), + Stderr: req.GetStderr(), + Checkpoint: req.GetCheckpoint(), + ParentCheckpoint: req.GetParentCheckpoint(), + Options: req.GetOptions(), + }) + return &taskAPI.CreateTaskResponse{Pid: resp.GetPid()}, err +} + +func (b *ttrpcV2Bridge) Start(ctx context.Context, req *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { + resp, err := b.client.Start(ctx, &taskV2.StartRequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + }) + return &taskAPI.StartResponse{Pid: resp.GetPid()}, err +} + +func (b *ttrpcV2Bridge) Delete(ctx context.Context, req *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { + resp, err := b.client.Delete(ctx, &taskV2.DeleteRequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + }) + return &taskAPI.DeleteResponse{ + Pid: resp.GetPid(), + ExitStatus: resp.GetExitStatus(), + ExitedAt: resp.GetExitedAt(), + }, err +} + +func (b *ttrpcV2Bridge) Pids(ctx context.Context, req *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { + resp, err := b.client.Pids(ctx, &taskV2.PidsRequest{ID: req.GetID()}) + return &taskAPI.PidsResponse{Processes: resp.GetProcesses()}, err +} + +func (b *ttrpcV2Bridge) Pause(ctx context.Context, req *taskAPI.PauseRequest) (*emptypb.Empty, error) { + return b.client.Pause(ctx, &taskV2.PauseRequest{ID: req.GetID()}) +} + +func (b *ttrpcV2Bridge) Resume(ctx context.Context, req *taskAPI.ResumeRequest) (*emptypb.Empty, error) { + return b.client.Resume(ctx, &taskV2.ResumeRequest{ID: req.GetID()}) +} + +func (b *ttrpcV2Bridge) Checkpoint(ctx context.Context, req *taskAPI.CheckpointTaskRequest) (*emptypb.Empty, error) { + return b.client.Checkpoint(ctx, &taskV2.CheckpointTaskRequest{ + ID: req.GetID(), + Path: req.GetPath(), + Options: req.GetOptions(), + }) +} + +func (b *ttrpcV2Bridge) Kill(ctx context.Context, req *taskAPI.KillRequest) (*emptypb.Empty, error) { + return b.client.Kill(ctx, &taskV2.KillRequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + Signal: req.GetSignal(), + All: req.GetAll(), + }) +} + +func (b *ttrpcV2Bridge) Exec(ctx context.Context, req *taskAPI.ExecProcessRequest) (*emptypb.Empty, error) { + return b.client.Exec(ctx, &taskV2.ExecProcessRequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + Terminal: req.GetTerminal(), + Stdin: req.GetStdin(), + Stdout: req.GetStdout(), + Stderr: req.GetStderr(), + Spec: req.GetSpec(), + }) +} + +func (b *ttrpcV2Bridge) ResizePty(ctx context.Context, req *taskAPI.ResizePtyRequest) (*emptypb.Empty, error) { + return b.client.ResizePty(ctx, &taskV2.ResizePtyRequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + Width: req.GetWidth(), + Height: req.GetHeight(), + }) +} + +func (b *ttrpcV2Bridge) CloseIO(ctx context.Context, req *taskAPI.CloseIORequest) (*emptypb.Empty, error) { + return b.client.CloseIO(ctx, &taskV2.CloseIORequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + Stdin: req.GetStdin(), + }) +} + +func (b *ttrpcV2Bridge) Update(ctx context.Context, req *taskAPI.UpdateTaskRequest) (*emptypb.Empty, error) { + return b.client.Update(ctx, &taskV2.UpdateTaskRequest{ + ID: req.GetID(), + Resources: req.GetResources(), + Annotations: req.GetAnnotations(), + }) +} + +func (b *ttrpcV2Bridge) Wait(ctx context.Context, req *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { + resp, err := b.client.Wait(ctx, &taskV2.WaitRequest{ + ID: req.GetID(), + ExecID: req.GetExecID(), + }) + return &taskAPI.WaitResponse{ + ExitStatus: resp.GetExitStatus(), + ExitedAt: resp.GetExitedAt(), + }, err +} + +func (b *ttrpcV2Bridge) Stats(ctx context.Context, req *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + resp, err := b.client.Stats(ctx, &taskV2.StatsRequest{ID: req.GetID()}) + return &taskAPI.StatsResponse{Stats: resp.GetStats()}, err +} + +func (b *ttrpcV2Bridge) Connect(ctx context.Context, req *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { + resp, err := b.client.Connect(ctx, &taskV2.ConnectRequest{ID: req.GetID()}) + return &taskAPI.ConnectResponse{ + ShimPid: resp.GetShimPid(), + TaskPid: resp.GetTaskPid(), + Version: resp.GetVersion(), + }, err +} + +func (b *ttrpcV2Bridge) Shutdown(ctx context.Context, req *taskAPI.ShutdownRequest) (*emptypb.Empty, error) { + return b.client.Shutdown(ctx, &taskV2.ShutdownRequest{ + ID: req.GetID(), + Now: req.GetNow(), + }) +} diff --git a/vendor/github.com/containerd/shimtest/uds_bench.go b/vendor/github.com/containerd/shimtest/uds_bench.go index 5750f12c..3dd0f0ea 100644 --- a/vendor/github.com/containerd/shimtest/uds_bench.go +++ b/vendor/github.com/containerd/shimtest/uds_bench.go @@ -79,7 +79,7 @@ func (s *UDSSuite) benchUDSRoundTrip(b *testing.B) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(b, ctx, stdoutPath) drainFifo(b, ctx, stderrPath) diff --git a/vendor/github.com/containerd/shimtest/uds_suite.go b/vendor/github.com/containerd/shimtest/uds_suite.go index 8e25515c..7f8e363f 100644 --- a/vendor/github.com/containerd/shimtest/uds_suite.go +++ b/vendor/github.com/containerd/shimtest/uds_suite.go @@ -89,7 +89,7 @@ func (s *UDSSuite) testRoundTrip(t *testing.T) { client := ttrpc.NewClient(conn) defer client.Close() - tc := taskAPI.NewTTRPCTaskClient(client) + tc := newTaskClient(client, params.Version) drainFifo(t, ctx, stdoutPath) drainFifo(t, ctx, stderrPath) diff --git a/vendor/modules.txt b/vendor/modules.txt index d34bad23..e291efd9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -67,6 +67,7 @@ github.com/containerd/console ## explicit; go 1.24.0 github.com/containerd/containerd/api/events github.com/containerd/containerd/api/runtime/bootstrap/v1 +github.com/containerd/containerd/api/runtime/task/v2 github.com/containerd/containerd/api/runtime/task/v3 github.com/containerd/containerd/api/services/streaming/v1 github.com/containerd/containerd/api/services/transfer/v1 @@ -145,7 +146,7 @@ github.com/containerd/platforms ## explicit; go 1.22 github.com/containerd/plugin github.com/containerd/plugin/registry -# github.com/containerd/shimtest v0.3.0 +# github.com/containerd/shimtest v0.3.3 ## explicit; go 1.26.3 github.com/containerd/shimtest github.com/containerd/shimtest/internal/transfer