140 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"net"
 | |
| 	"os"
 | |
| 	"sync"
 | |
| 	"syscall"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/Microsoft/go-winio"
 | |
| 	clog "github.com/containerd/containerd/log"
 | |
| 	"github.com/pkg/errors"
 | |
| 	"github.com/urfave/cli"
 | |
| 	"golang.org/x/sys/windows"
 | |
| 	"google.golang.org/grpc"
 | |
| 	"google.golang.org/grpc/grpclog"
 | |
| )
 | |
| 
 | |
| func getGRPCConnection(context *cli.Context) (*grpc.ClientConn, error) {
 | |
| 	if grpcConn != nil {
 | |
| 		return grpcConn, nil
 | |
| 	}
 | |
| 
 | |
| 	bindAddress := context.GlobalString("address")
 | |
| 	// 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 winio.DialPipe(bindAddress, &timeout)
 | |
| 		},
 | |
| 		))
 | |
| 
 | |
| 	conn, err := grpc.Dial(bindAddress, dialOpts...)
 | |
| 	if err != nil {
 | |
| 		return nil, errors.Wrapf(err, "failed to dial %q", bindAddress)
 | |
| 	}
 | |
| 
 | |
| 	grpcConn = conn
 | |
| 	return grpcConn, nil
 | |
| }
 | |
| 
 | |
| func prepareStdio(stdin, stdout, stderr string, console bool) (*sync.WaitGroup, error) {
 | |
| 	var wg sync.WaitGroup
 | |
| 
 | |
| 	if stdin != "" {
 | |
| 		l, err := winio.ListenPipe(stdin, nil)
 | |
| 		if err != nil {
 | |
| 			return nil, errors.Wrapf(err, "failed to create stdin pipe %s", stdin)
 | |
| 		}
 | |
| 		defer func(l net.Listener) {
 | |
| 			if err != nil {
 | |
| 				l.Close()
 | |
| 			}
 | |
| 		}(l)
 | |
| 
 | |
| 		go func() {
 | |
| 			c, err := l.Accept()
 | |
| 			if err != nil {
 | |
| 				clog.L.WithError(err).Errorf("failed to accept stdin connection on %s", stdin)
 | |
| 				return
 | |
| 			}
 | |
| 			io.Copy(c, os.Stdin)
 | |
| 			c.Close()
 | |
| 			l.Close()
 | |
| 		}()
 | |
| 	}
 | |
| 
 | |
| 	if stdout != "" {
 | |
| 		l, err := winio.ListenPipe(stdout, nil)
 | |
| 		if err != nil {
 | |
| 			return nil, errors.Wrapf(err, "failed to create stdin pipe %s", stdout)
 | |
| 		}
 | |
| 		defer func(l net.Listener) {
 | |
| 			if err != nil {
 | |
| 				l.Close()
 | |
| 			}
 | |
| 		}(l)
 | |
| 
 | |
| 		wg.Add(1)
 | |
| 		go func() {
 | |
| 			defer wg.Done()
 | |
| 			c, err := l.Accept()
 | |
| 			if err != nil {
 | |
| 				clog.L.WithError(err).Errorf("failed to accept stdout connection on %s", stdout)
 | |
| 				return
 | |
| 			}
 | |
| 			io.Copy(os.Stdout, c)
 | |
| 			c.Close()
 | |
| 			l.Close()
 | |
| 		}()
 | |
| 	}
 | |
| 
 | |
| 	if !console && stderr != "" {
 | |
| 		l, err := winio.ListenPipe(stderr, nil)
 | |
| 		if err != nil {
 | |
| 			return nil, errors.Wrapf(err, "failed to create stderr pipe %s", stderr)
 | |
| 		}
 | |
| 		defer func(l net.Listener) {
 | |
| 			if err != nil {
 | |
| 				l.Close()
 | |
| 			}
 | |
| 		}(l)
 | |
| 
 | |
| 		wg.Add(1)
 | |
| 		go func() {
 | |
| 			defer wg.Done()
 | |
| 			c, err := l.Accept()
 | |
| 			if err != nil {
 | |
| 				clog.L.WithError(err).Errorf("failed to accept stderr connection on %s", stderr)
 | |
| 				return
 | |
| 			}
 | |
| 			io.Copy(os.Stderr, c)
 | |
| 			c.Close()
 | |
| 			l.Close()
 | |
| 		}()
 | |
| 	}
 | |
| 
 | |
| 	return &wg, nil
 | |
| }
 | |
| 
 | |
| var signalMap = map[string]syscall.Signal{
 | |
| 	"HUP":    syscall.Signal(windows.SIGHUP),
 | |
| 	"INT":    syscall.Signal(windows.SIGINT),
 | |
| 	"QUIT":   syscall.Signal(windows.SIGQUIT),
 | |
| 	"SIGILL": syscall.Signal(windows.SIGILL),
 | |
| 	"TRAP":   syscall.Signal(windows.SIGTRAP),
 | |
| 	"ABRT":   syscall.Signal(windows.SIGABRT),
 | |
| 	"BUS":    syscall.Signal(windows.SIGBUS),
 | |
| 	"FPE":    syscall.Signal(windows.SIGFPE),
 | |
| 	"KILL":   syscall.Signal(windows.SIGKILL),
 | |
| 	"SEGV":   syscall.Signal(windows.SIGSEGV),
 | |
| 	"PIPE":   syscall.Signal(windows.SIGPIPE),
 | |
| 	"ALRM":   syscall.Signal(windows.SIGALRM),
 | |
| 	"TERM":   syscall.Signal(windows.SIGTERM),
 | |
| }
 | 
