145 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|    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 io
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"sync"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"github.com/containerd/containerd/cio"
 | |
| 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
 | |
| )
 | |
| 
 | |
| // AttachOptions specifies how to attach to a container.
 | |
| type AttachOptions struct {
 | |
| 	Stdin     io.Reader
 | |
| 	Stdout    io.WriteCloser
 | |
| 	Stderr    io.WriteCloser
 | |
| 	Tty       bool
 | |
| 	StdinOnce bool
 | |
| 	// CloseStdin is the function to close container stdin.
 | |
| 	CloseStdin func() error
 | |
| }
 | |
| 
 | |
| // StreamType is the type of the stream, stdout/stderr.
 | |
| type StreamType string
 | |
| 
 | |
| const (
 | |
| 	// Stdin stream type.
 | |
| 	Stdin StreamType = "stdin"
 | |
| 	// Stdout stream type.
 | |
| 	Stdout = StreamType(runtime.Stdout)
 | |
| 	// Stderr stream type.
 | |
| 	Stderr = StreamType(runtime.Stderr)
 | |
| )
 | |
| 
 | |
| type wgCloser struct {
 | |
| 	ctx    context.Context
 | |
| 	wg     *sync.WaitGroup
 | |
| 	set    []io.Closer
 | |
| 	cancel context.CancelFunc
 | |
| }
 | |
| 
 | |
| func (g *wgCloser) Wait() {
 | |
| 	g.wg.Wait()
 | |
| }
 | |
| 
 | |
| func (g *wgCloser) Close() {
 | |
| 	for _, f := range g.set {
 | |
| 		f.Close()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (g *wgCloser) Cancel() {
 | |
| 	g.cancel()
 | |
| }
 | |
| 
 | |
| // newFifos creates fifos directory for a container.
 | |
| func newFifos(root, id string, tty, stdin bool) (*cio.FIFOSet, error) {
 | |
| 	root = filepath.Join(root, "io")
 | |
| 	if err := os.MkdirAll(root, 0700); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	fifos, err := cio.NewFIFOSetInDir(root, id, tty)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if !stdin {
 | |
| 		fifos.Stdin = ""
 | |
| 	}
 | |
| 	return fifos, nil
 | |
| }
 | |
| 
 | |
| type stdioPipes struct {
 | |
| 	stdin  io.WriteCloser
 | |
| 	stdout io.ReadCloser
 | |
| 	stderr io.ReadCloser
 | |
| }
 | |
| 
 | |
| // newStdioPipes creates actual fifos for stdio.
 | |
| func newStdioPipes(fifos *cio.FIFOSet) (_ *stdioPipes, _ *wgCloser, err error) {
 | |
| 	var (
 | |
| 		f           io.ReadWriteCloser
 | |
| 		set         []io.Closer
 | |
| 		ctx, cancel = context.WithCancel(context.Background())
 | |
| 		p           = &stdioPipes{}
 | |
| 	)
 | |
| 	defer func() {
 | |
| 		if err != nil {
 | |
| 			for _, f := range set {
 | |
| 				f.Close()
 | |
| 			}
 | |
| 			cancel()
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	if fifos.Stdin != "" {
 | |
| 		if f, err = openPipe(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
 | |
| 			return nil, nil, err
 | |
| 		}
 | |
| 		p.stdin = f
 | |
| 		set = append(set, f)
 | |
| 	}
 | |
| 
 | |
| 	if fifos.Stdout != "" {
 | |
| 		if f, err = openPipe(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
 | |
| 			return nil, nil, err
 | |
| 		}
 | |
| 		p.stdout = f
 | |
| 		set = append(set, f)
 | |
| 	}
 | |
| 
 | |
| 	if fifos.Stderr != "" {
 | |
| 		if f, err = openPipe(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
 | |
| 			return nil, nil, err
 | |
| 		}
 | |
| 		p.stderr = f
 | |
| 		set = append(set, f)
 | |
| 	}
 | |
| 
 | |
| 	return p, &wgCloser{
 | |
| 		wg:     &sync.WaitGroup{},
 | |
| 		set:    set,
 | |
| 		ctx:    ctx,
 | |
| 		cancel: cancel,
 | |
| 	}, nil
 | |
| }
 | 
