| // +build !windows |
| |
| package main |
| |
| import ( |
| gocontext "context" |
| "fmt" |
| "io" |
| "io/ioutil" |
| "log" |
| "net" |
| "os" |
| "sync" |
| "syscall" |
| "time" |
| |
| "github.com/containerd/fifo" |
| "github.com/pkg/errors" |
| "github.com/urfave/cli" |
| "google.golang.org/grpc" |
| "google.golang.org/grpc/grpclog" |
| ) |
| |
| func prepareStdio(stdin, stdout, stderr string, console bool) (wg *sync.WaitGroup, err error) { |
| wg = &sync.WaitGroup{} |
| ctx := gocontext.Background() |
| |
| f, err := fifo.OpenFifo(ctx, stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) |
| if err != nil { |
| return nil, err |
| } |
| defer func(c io.Closer) { |
| if err != nil { |
| c.Close() |
| } |
| }(f) |
| go func(w io.WriteCloser) { |
| io.Copy(w, os.Stdin) |
| w.Close() |
| }(f) |
| |
| f, err = fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) |
| if err != nil { |
| return nil, err |
| } |
| defer func(c io.Closer) { |
| if err != nil { |
| c.Close() |
| } |
| }(f) |
| wg.Add(1) |
| go func(r io.ReadCloser) { |
| io.Copy(os.Stdout, r) |
| r.Close() |
| wg.Done() |
| }(f) |
| |
| f, err = fifo.OpenFifo(ctx, stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700) |
| if err != nil { |
| return nil, err |
| } |
| defer func(c io.Closer) { |
| if err != nil { |
| c.Close() |
| } |
| }(f) |
| if !console { |
| wg.Add(1) |
| go func(r io.ReadCloser) { |
| io.Copy(os.Stderr, r) |
| r.Close() |
| wg.Done() |
| }(f) |
| } |
| |
| return wg, nil |
| } |
| |
| func getGRPCConnection(context *cli.Context) (*grpc.ClientConn, error) { |
| if grpcConn != nil { |
| return grpcConn, nil |
| } |
| |
| bindSocket := 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 net.DialTimeout("unix", bindSocket, timeout) |
| }, |
| )) |
| |
| conn, err := grpc.Dial(fmt.Sprintf("unix://%s", bindSocket), dialOpts...) |
| if err != nil { |
| return nil, errors.Wrapf(err, "failed to dial %q", bindSocket) |
| } |
| |
| grpcConn = conn |
| return grpcConn, nil |
| } |