123 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"net"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"sync"
 | |
| 	"syscall"
 | |
| 	"time"
 | |
| 
 | |
| 	gocontext "context"
 | |
| 
 | |
| 	"github.com/docker/containerd/api/execution"
 | |
| 	"github.com/tonistiigi/fifo"
 | |
| 	"github.com/urfave/cli"
 | |
| 	"google.golang.org/grpc"
 | |
| 	"google.golang.org/grpc/grpclog"
 | |
| )
 | |
| 
 | |
| var grpcConn *grpc.ClientConn
 | |
| 
 | |
| func prepareStdio(in, out, err string) (*sync.WaitGroup, error) {
 | |
| 	var (
 | |
| 		wg sync.WaitGroup
 | |
| 
 | |
| 		dst   io.Writer
 | |
| 		src   io.Reader
 | |
| 		close func()
 | |
| 	)
 | |
| 
 | |
| 	for _, f := range []struct {
 | |
| 		name   string
 | |
| 		flags  int
 | |
| 		src    bool
 | |
| 		reader io.Reader
 | |
| 		writer io.Writer
 | |
| 	}{
 | |
| 		{in, syscall.O_WRONLY | syscall.O_CREAT | syscall.O_NONBLOCK, false, os.Stdin, nil},
 | |
| 		{out, syscall.O_RDONLY | syscall.O_CREAT | syscall.O_NONBLOCK, true, nil, os.Stdout},
 | |
| 		{err, syscall.O_RDONLY | syscall.O_CREAT | syscall.O_NONBLOCK, true, nil, os.Stderr},
 | |
| 	} {
 | |
| 		ff, err := fifo.OpenFifo(gocontext.Background(), f.name, f.flags, 0700)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		defer func(c io.Closer) {
 | |
| 			if err != nil {
 | |
| 				c.Close()
 | |
| 			}
 | |
| 		}(ff)
 | |
| 
 | |
| 		if f.src {
 | |
| 			src = ff
 | |
| 			dst = f.writer
 | |
| 			close = func() {
 | |
| 				ff.Close()
 | |
| 				wg.Done()
 | |
| 			}
 | |
| 			wg.Add(1)
 | |
| 		} else {
 | |
| 			src = f.reader
 | |
| 			dst = ff
 | |
| 			close = func() { ff.Close() }
 | |
| 		}
 | |
| 
 | |
| 		go func(dst io.Writer, src io.Reader, close func()) {
 | |
| 			io.Copy(dst, src)
 | |
| 			close()
 | |
| 		}(dst, src, close)
 | |
| 	}
 | |
| 
 | |
| 	return &wg, nil
 | |
| }
 | |
| 
 | |
| func getGRPCConnection(context *cli.Context) (*grpc.ClientConn, error) {
 | |
| 	if grpcConn != nil {
 | |
| 		return grpcConn, nil
 | |
| 	}
 | |
| 
 | |
| 	bindSocket := context.GlobalString("socket")
 | |
| 	// reset the logger for grpc to log to dev/null so that it does not mess with our stdio
 | |
| 	grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
 | |
| 	dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithTimeout(100 * time.Second)}
 | |
| 	dialOpts = append(dialOpts,
 | |
| 		grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
 | |
| 			return net.DialTimeout("unix", bindSocket, timeout)
 | |
| 		},
 | |
| 		))
 | |
| 
 | |
| 	conn, err := grpc.Dial(fmt.Sprintf("unix://%s", bindSocket), dialOpts...)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	grpcConn = conn
 | |
| 	return grpcConn, nil
 | |
| }
 | |
| 
 | |
| func getExecutionService(context *cli.Context) (execution.ExecutionServiceClient, error) {
 | |
| 	conn, err := getGRPCConnection(context)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return execution.NewExecutionServiceClient(conn), nil
 | |
| }
 | |
| 
 | |
| func getTempDir(id string) (string, error) {
 | |
| 	err := os.MkdirAll(filepath.Join(os.TempDir(), "ctr"), 0700)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	tmpDir, err := ioutil.TempDir(filepath.Join(os.TempDir(), "ctr"), fmt.Sprintf("%s-", id))
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	return tmpDir, nil
 | |
| }
 | 
