Browse code

Update daemon code for containerd API changes

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Michael Crosby authored on 2017/11/30 09:15:20
Showing 12 changed files
... ...
@@ -15,7 +15,7 @@ import (
15 15
 	"syscall"
16 16
 	"time"
17 17
 
18
-	"github.com/containerd/containerd"
18
+	"github.com/containerd/containerd/cio"
19 19
 	containertypes "github.com/docker/docker/api/types/container"
20 20
 	mounttypes "github.com/docker/docker/api/types/mount"
21 21
 	networktypes "github.com/docker/docker/api/types/network"
... ...
@@ -1004,7 +1004,7 @@ func (container *Container) CloseStreams() error {
1004 1004
 }
1005 1005
 
1006 1006
 // InitializeStdio is called by libcontainerd to connect the stdio.
1007
-func (container *Container) InitializeStdio(iop *libcontainerd.IOPipe) (containerd.IO, error) {
1007
+func (container *Container) InitializeStdio(iop *libcontainerd.IOPipe) (cio.IO, error) {
1008 1008
 	if err := container.startLogging(); err != nil {
1009 1009
 		container.Reset(false)
1010 1010
 		return nil, err
... ...
@@ -1020,7 +1020,7 @@ func (container *Container) InitializeStdio(iop *libcontainerd.IOPipe) (containe
1020 1020
 		}
1021 1021
 	}
1022 1022
 
1023
-	return &cio{IO: iop, sc: container.StreamConfig}, nil
1023
+	return &rio{IO: iop, sc: container.StreamConfig}, nil
1024 1024
 }
1025 1025
 
1026 1026
 // SecretMountPath returns the path of the secret mount for the container
... ...
@@ -1078,19 +1078,19 @@ func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string
1078 1078
 	return env
1079 1079
 }
1080 1080
 
1081
-type cio struct {
1082
-	containerd.IO
1081
+type rio struct {
1082
+	cio.IO
1083 1083
 
1084 1084
 	sc *stream.Config
1085 1085
 }
1086 1086
 
1087
-func (i *cio) Close() error {
1087
+func (i *rio) Close() error {
1088 1088
 	i.IO.Close()
1089 1089
 
1090 1090
 	return i.sc.CloseStreams()
1091 1091
 }
1092 1092
 
1093
-func (i *cio) Wait() {
1093
+func (i *rio) Wait() {
1094 1094
 	i.sc.Wait()
1095 1095
 
1096 1096
 	i.IO.Wait()
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"runtime"
5 5
 	"sync"
6 6
 
7
-	"github.com/containerd/containerd"
7
+	"github.com/containerd/containerd/cio"
8 8
 	"github.com/docker/docker/container/stream"
9 9
 	"github.com/docker/docker/libcontainerd"
10 10
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -43,26 +43,26 @@ func NewConfig() *Config {
43 43
 	}
44 44
 }
45 45
 
46
-type cio struct {
47
-	containerd.IO
46
+type rio struct {
47
+	cio.IO
48 48
 
49 49
 	sc *stream.Config
50 50
 }
51 51
 
52
-func (i *cio) Close() error {
52
+func (i *rio) Close() error {
53 53
 	i.IO.Close()
54 54
 
55 55
 	return i.sc.CloseStreams()
56 56
 }
57 57
 
58
-func (i *cio) Wait() {
58
+func (i *rio) Wait() {
59 59
 	i.sc.Wait()
60 60
 
61 61
 	i.IO.Wait()
62 62
 }
63 63
 
64 64
 // InitializeStdio is called by libcontainerd to connect the stdio.
65
-func (c *Config) InitializeStdio(iop *libcontainerd.IOPipe) (containerd.IO, error) {
65
+func (c *Config) InitializeStdio(iop *libcontainerd.IOPipe) (cio.IO, error) {
66 66
 	c.StreamConfig.CopyToPipe(iop)
67 67
 
68 68
 	if c.StreamConfig.Stdin() == nil && !c.Tty && runtime.GOOS == "windows" {
... ...
@@ -73,7 +73,7 @@ func (c *Config) InitializeStdio(iop *libcontainerd.IOPipe) (containerd.IO, erro
73 73
 		}
74 74
 	}
75 75
 
76
-	return &cio{IO: iop, sc: c.StreamConfig}, nil
76
+	return &rio{IO: iop, sc: c.StreamConfig}, nil
77 77
 }
78 78
 
79 79
 // CloseStreams closes the stdio streams for the exec
... ...
@@ -7,7 +7,7 @@ import (
7 7
 	"os/exec"
8 8
 	"path/filepath"
9 9
 
10
-	"github.com/containerd/containerd/linux/runcopts"
10
+	"github.com/containerd/containerd/linux/runctypes"
11 11
 	"github.com/docker/docker/container"
12 12
 	"github.com/pkg/errors"
13 13
 )
... ...
@@ -42,7 +42,7 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
42 42
 	if err != nil {
43 43
 		return nil, err
44 44
 	}
45
-	opts := &runcopts.RuncOptions{
45
+	opts := &runctypes.RuncOptions{
46 46
 		Runtime: path,
47 47
 		RuntimeRoot: filepath.Join(daemon.configStore.ExecRoot,
48 48
 			fmt.Sprintf("runtime-%s", container.HostConfig.Runtime)),
... ...
@@ -21,12 +21,14 @@ import (
21 21
 	"google.golang.org/grpc/status"
22 22
 
23 23
 	"github.com/containerd/containerd"
24
+	"github.com/containerd/containerd/api/events"
24 25
 	eventsapi "github.com/containerd/containerd/api/services/events/v1"
25 26
 	"github.com/containerd/containerd/api/types"
26 27
 	"github.com/containerd/containerd/archive"
28
+	"github.com/containerd/containerd/cio"
27 29
 	"github.com/containerd/containerd/content"
28 30
 	"github.com/containerd/containerd/images"
29
-	"github.com/containerd/containerd/linux/runcopts"
31
+	"github.com/containerd/containerd/linux/runctypes"
30 32
 	"github.com/containerd/typeurl"
31 33
 	"github.com/docker/docker/pkg/ioutils"
32 34
 	"github.com/opencontainers/image-spec/specs-go/v1"
... ...
@@ -70,7 +72,7 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallba
70 70
 	c.Lock()
71 71
 	defer c.Unlock()
72 72
 
73
-	var cio containerd.IO
73
+	var rio cio.IO
74 74
 	defer func() {
75 75
 		err = wrapError(err)
76 76
 	}()
... ...
@@ -81,20 +83,20 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallba
81 81
 	}
82 82
 
83 83
 	defer func() {
84
-		if err != nil && cio != nil {
85
-			cio.Cancel()
86
-			cio.Close()
84
+		if err != nil && rio != nil {
85
+			rio.Cancel()
86
+			rio.Close()
87 87
 		}
88 88
 	}()
89 89
 
90
-	t, err := ctr.Task(ctx, func(fifos *containerd.FIFOSet) (containerd.IO, error) {
90
+	t, err := ctr.Task(ctx, func(fifos *cio.FIFOSet) (cio.IO, error) {
91 91
 		io, err := newIOPipe(fifos)
92 92
 		if err != nil {
93 93
 			return nil, err
94 94
 		}
95 95
 
96
-		cio, err = attachStdio(io)
97
-		return cio, err
96
+		rio, err = attachStdio(io)
97
+		return rio, err
98 98
 	})
99 99
 	if err != nil && !strings.Contains(err.Error(), "no running task found") {
100 100
 		return false, -1, err
... ...
@@ -168,7 +170,7 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
168 168
 	var (
169 169
 		cp             *types.Descriptor
170 170
 		t              containerd.Task
171
-		cio            containerd.IO
171
+		rio            cio.IO
172 172
 		err            error
173 173
 		stdinCloseSync = make(chan struct{})
174 174
 	)
... ...
@@ -203,14 +205,14 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
203 203
 	}
204 204
 	uid, gid := getSpecUser(spec)
205 205
 	t, err = ctr.ctr.NewTask(ctx,
206
-		func(id string) (containerd.IO, error) {
206
+		func(id string) (cio.IO, error) {
207 207
 			fifos := newFIFOSet(ctr.bundleDir, id, InitProcessName, withStdin, spec.Process.Terminal)
208
-			cio, err = c.createIO(fifos, id, InitProcessName, stdinCloseSync, attachStdio)
209
-			return cio, err
208
+			rio, err = c.createIO(fifos, id, InitProcessName, stdinCloseSync, attachStdio)
209
+			return rio, err
210 210
 		},
211 211
 		func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error {
212 212
 			info.Checkpoint = cp
213
-			info.Options = &runcopts.CreateOptions{
213
+			info.Options = &runctypes.CreateOptions{
214 214
 				IoUid: uint32(uid),
215 215
 				IoGid: uint32(gid),
216 216
 			}
... ...
@@ -218,9 +220,9 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
218 218
 		})
219 219
 	if err != nil {
220 220
 		close(stdinCloseSync)
221
-		if cio != nil {
222
-			cio.Cancel()
223
-			cio.Close()
221
+		if rio != nil {
222
+			rio.Cancel()
223
+			rio.Close()
224 224
 		}
225 225
 		return -1, err
226 226
 	}
... ...
@@ -259,7 +261,7 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
259 259
 
260 260
 	var (
261 261
 		p              containerd.Process
262
-		cio            containerd.IO
262
+		rio            cio.IO
263 263
 		err            error
264 264
 		stdinCloseSync = make(chan struct{})
265 265
 	)
... ...
@@ -268,23 +270,23 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
268 268
 
269 269
 	defer func() {
270 270
 		if err != nil {
271
-			if cio != nil {
272
-				cio.Cancel()
273
-				cio.Close()
271
+			if rio != nil {
272
+				rio.Cancel()
273
+				rio.Close()
274 274
 			}
275 275
 			rmFIFOSet(fifos)
276 276
 		}
277 277
 	}()
278 278
 
279
-	p, err = ctr.task.Exec(ctx, processID, spec, func(id string) (containerd.IO, error) {
280
-		cio, err = c.createIO(fifos, containerID, processID, stdinCloseSync, attachStdio)
281
-		return cio, err
279
+	p, err = ctr.task.Exec(ctx, processID, spec, func(id string) (cio.IO, error) {
280
+		rio, err = c.createIO(fifos, containerID, processID, stdinCloseSync, attachStdio)
281
+		return rio, err
282 282
 	})
283 283
 	if err != nil {
284 284
 		close(stdinCloseSync)
285
-		if cio != nil {
286
-			cio.Cancel()
287
-			cio.Close()
285
+		if rio != nil {
286
+			rio.Cancel()
287
+			rio.Close()
288 288
 		}
289 289
 		return -1, err
290 290
 	}
... ...
@@ -569,7 +571,7 @@ func (c *client) getProcess(containerID, processID string) (containerd.Process,
569 569
 
570 570
 // createIO creates the io to be used by a process
571 571
 // This needs to get a pointer to interface as upon closure the process may not have yet been registered
572
-func (c *client) createIO(fifos *containerd.FIFOSet, containerID, processID string, stdinCloseSync chan struct{}, attachStdio StdioCallback) (containerd.IO, error) {
572
+func (c *client) createIO(fifos *cio.FIFOSet, containerID, processID string, stdinCloseSync chan struct{}, attachStdio StdioCallback) (cio.IO, error) {
573 573
 	io, err := newIOPipe(fifos)
574 574
 	if err != nil {
575 575
 		return nil, err
... ...
@@ -601,12 +603,12 @@ func (c *client) createIO(fifos *containerd.FIFOSet, containerID, processID stri
601 601
 		})
602 602
 	}
603 603
 
604
-	cio, err := attachStdio(io)
604
+	rio, err := attachStdio(io)
605 605
 	if err != nil {
606 606
 		io.Cancel()
607 607
 		io.Close()
608 608
 	}
609
-	return cio, err
609
+	return rio, err
610 610
 }
611 611
 
612 612
 func (c *client) processEvent(ctr *container, et EventType, ei EventInfo) {
... ...
@@ -710,21 +712,21 @@ func (c *client) processEventStream(ctx context.Context) {
710 710
 		c.logger.WithField("topic", ev.Topic).Debug("event")
711 711
 
712 712
 		switch t := v.(type) {
713
-		case *eventsapi.TaskCreate:
713
+		case *events.TaskCreate:
714 714
 			et = EventCreate
715 715
 			ei = EventInfo{
716 716
 				ContainerID: t.ContainerID,
717 717
 				ProcessID:   t.ContainerID,
718 718
 				Pid:         t.Pid,
719 719
 			}
720
-		case *eventsapi.TaskStart:
720
+		case *events.TaskStart:
721 721
 			et = EventStart
722 722
 			ei = EventInfo{
723 723
 				ContainerID: t.ContainerID,
724 724
 				ProcessID:   t.ContainerID,
725 725
 				Pid:         t.Pid,
726 726
 			}
727
-		case *eventsapi.TaskExit:
727
+		case *events.TaskExit:
728 728
 			et = EventExit
729 729
 			ei = EventInfo{
730 730
 				ContainerID: t.ContainerID,
... ...
@@ -733,32 +735,32 @@ func (c *client) processEventStream(ctx context.Context) {
733 733
 				ExitCode:    t.ExitStatus,
734 734
 				ExitedAt:    t.ExitedAt,
735 735
 			}
736
-		case *eventsapi.TaskOOM:
736
+		case *events.TaskOOM:
737 737
 			et = EventOOM
738 738
 			ei = EventInfo{
739 739
 				ContainerID: t.ContainerID,
740 740
 				OOMKilled:   true,
741 741
 			}
742 742
 			oomKilled = true
743
-		case *eventsapi.TaskExecAdded:
743
+		case *events.TaskExecAdded:
744 744
 			et = EventExecAdded
745 745
 			ei = EventInfo{
746 746
 				ContainerID: t.ContainerID,
747 747
 				ProcessID:   t.ExecID,
748 748
 			}
749
-		case *eventsapi.TaskExecStarted:
749
+		case *events.TaskExecStarted:
750 750
 			et = EventExecStarted
751 751
 			ei = EventInfo{
752 752
 				ContainerID: t.ContainerID,
753 753
 				ProcessID:   t.ExecID,
754 754
 				Pid:         t.Pid,
755 755
 			}
756
-		case *eventsapi.TaskPaused:
756
+		case *events.TaskPaused:
757 757
 			et = EventPaused
758 758
 			ei = EventInfo{
759 759
 				ContainerID: t.ContainerID,
760 760
 			}
761
-		case *eventsapi.TaskResumed:
761
+		case *events.TaskResumed:
762 762
 			et = EventResumed
763 763
 			ei = EventInfo{
764 764
 				ContainerID: t.ContainerID,
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"strings"
9 9
 
10 10
 	"github.com/containerd/containerd"
11
+	"github.com/containerd/containerd/cio"
11 12
 	"github.com/docker/docker/pkg/idtools"
12 13
 	specs "github.com/opencontainers/runtime-spec/specs-go"
13 14
 	"github.com/sirupsen/logrus"
... ...
@@ -79,8 +80,8 @@ func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
79 79
 	return p, nil
80 80
 }
81 81
 
82
-func newFIFOSet(bundleDir, containerID, processID string, withStdin, withTerminal bool) *containerd.FIFOSet {
83
-	fifos := &containerd.FIFOSet{
82
+func newFIFOSet(bundleDir, containerID, processID string, withStdin, withTerminal bool) *cio.FIFOSet {
83
+	fifos := &cio.FIFOSet{
84 84
 		Terminal: withTerminal,
85 85
 		Out:      filepath.Join(bundleDir, processID+"-stdout"),
86 86
 	}
... ...
@@ -96,7 +97,7 @@ func newFIFOSet(bundleDir, containerID, processID string, withStdin, withTermina
96 96
 	return fifos
97 97
 }
98 98
 
99
-func rmFIFOSet(fset *containerd.FIFOSet) {
99
+func rmFIFOSet(fset *cio.FIFOSet) {
100 100
 	for _, fn := range []string{fset.Out, fset.In, fset.Err} {
101 101
 		if fn != "" {
102 102
 			if err := os.RemoveAll(fn); err != nil {
... ...
@@ -3,7 +3,7 @@ package libcontainerd
3 3
 import (
4 4
 	"fmt"
5 5
 
6
-	"github.com/containerd/containerd"
6
+	"github.com/containerd/containerd/cio"
7 7
 	"github.com/containerd/containerd/windows/hcsshimtypes"
8 8
 	specs "github.com/opencontainers/runtime-spec/specs-go"
9 9
 	"github.com/pkg/errors"
... ...
@@ -35,8 +35,8 @@ func pipeName(containerID, processID, name string) string {
35 35
 	return fmt.Sprintf(`\\.\pipe\containerd-%s-%s-%s`, containerID, processID, name)
36 36
 }
37 37
 
38
-func newFIFOSet(bundleDir, containerID, processID string, withStdin, withTerminal bool) *containerd.FIFOSet {
39
-	fifos := &containerd.FIFOSet{
38
+func newFIFOSet(bundleDir, containerID, processID string, withStdin, withTerminal bool) *cio.FIFOSet {
39
+	fifos := &cio.FIFOSet{
40 40
 		Terminal: withTerminal,
41 41
 		Out:      pipeName(containerID, processID, "stdout"),
42 42
 	}
... ...
@@ -1,9 +1,9 @@
1 1
 package libcontainerd
2 2
 
3
-import "github.com/containerd/containerd"
3
+import "github.com/containerd/containerd/cio"
4 4
 
5 5
 // Config returns the containerd.IOConfig of this pipe set
6
-func (p *IOPipe) Config() containerd.IOConfig {
6
+func (p *IOPipe) Config() cio.Config {
7 7
 	return p.config
8 8
 }
9 9
 
... ...
@@ -7,12 +7,12 @@ import (
7 7
 	"io"
8 8
 	"syscall"
9 9
 
10
-	"github.com/containerd/containerd"
10
+	"github.com/containerd/containerd/cio"
11 11
 	"github.com/containerd/fifo"
12 12
 	"github.com/pkg/errors"
13 13
 )
14 14
 
15
-func newIOPipe(fifos *containerd.FIFOSet) (*IOPipe, error) {
15
+func newIOPipe(fifos *cio.FIFOSet) (*IOPipe, error) {
16 16
 	var (
17 17
 		err         error
18 18
 		ctx, cancel = context.WithCancel(context.Background())
... ...
@@ -20,7 +20,7 @@ func newIOPipe(fifos *containerd.FIFOSet) (*IOPipe, error) {
20 20
 		iop         = &IOPipe{
21 21
 			Terminal: fifos.Terminal,
22 22
 			cancel:   cancel,
23
-			config: containerd.IOConfig{
23
+			config: cio.Config{
24 24
 				Terminal: fifos.Terminal,
25 25
 				Stdin:    fifos.In,
26 26
 				Stdout:   fifos.Out,
... ...
@@ -7,7 +7,7 @@ import (
7 7
 	"sync"
8 8
 
9 9
 	winio "github.com/Microsoft/go-winio"
10
-	"github.com/containerd/containerd"
10
+	"github.com/containerd/containerd/cio"
11 11
 	"github.com/pkg/errors"
12 12
 )
13 13
 
... ...
@@ -90,7 +90,7 @@ func (wp *winpipe) Close() error {
90 90
 	}
91 91
 }
92 92
 
93
-func newIOPipe(fifos *containerd.FIFOSet) (*IOPipe, error) {
93
+func newIOPipe(fifos *cio.FIFOSet) (*IOPipe, error) {
94 94
 	var (
95 95
 		err         error
96 96
 		ctx, cancel = context.WithCancel(context.Background())
... ...
@@ -98,7 +98,7 @@ func newIOPipe(fifos *containerd.FIFOSet) (*IOPipe, error) {
98 98
 		iop         = &IOPipe{
99 99
 			Terminal: fifos.Terminal,
100 100
 			cancel:   cancel,
101
-			config: containerd.IOConfig{
101
+			config: cio.Config{
102 102
 				Terminal: fifos.Terminal,
103 103
 				Stdin:    fifos.In,
104 104
 				Stdout:   fifos.Out,
... ...
@@ -27,7 +27,7 @@ type subreaper bool
27 27
 
28 28
 func (s subreaper) Apply(r Remote) error {
29 29
 	if remote, ok := r.(*remote); ok {
30
-		remote.Subreaper = bool(s)
30
+		remote.NoSubreaper = !bool(s)
31 31
 		return nil
32 32
 	}
33 33
 	return fmt.Errorf("WithSubreaper option not supported for this remote")
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"time"
7 7
 
8 8
 	"github.com/containerd/containerd"
9
+	"github.com/containerd/containerd/cio"
9 10
 	"github.com/opencontainers/runtime-spec/specs-go"
10 11
 )
11 12
 
... ...
@@ -106,7 +107,7 @@ type Client interface {
106 106
 }
107 107
 
108 108
 // StdioCallback is called to connect a container or process stdio.
109
-type StdioCallback func(*IOPipe) (containerd.IO, error)
109
+type StdioCallback func(*IOPipe) (cio.IO, error)
110 110
 
111 111
 // IOPipe contains the stdio streams.
112 112
 type IOPipe struct {
... ...
@@ -116,7 +117,7 @@ type IOPipe struct {
116 116
 	Terminal bool // Whether stderr is connected on Windows
117 117
 
118 118
 	cancel context.CancelFunc
119
-	config containerd.IOConfig
119
+	config cio.Config
120 120
 }
121 121
 
122 122
 // ServerVersion contains version information as retrieved from the
... ...
@@ -6,8 +6,8 @@ import (
6 6
 	"path/filepath"
7 7
 	"sync"
8 8
 
9
-	"github.com/containerd/containerd"
10
-	"github.com/containerd/containerd/linux/runcopts"
9
+	"github.com/containerd/containerd/cio"
10
+	"github.com/containerd/containerd/linux/runctypes"
11 11
 	"github.com/docker/docker/api/errdefs"
12 12
 	"github.com/docker/docker/libcontainerd"
13 13
 	"github.com/opencontainers/runtime-spec/specs-go"
... ...
@@ -46,7 +46,7 @@ type Executor struct {
46 46
 
47 47
 // Create creates a new container
48 48
 func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteCloser) error {
49
-	opts := runcopts.RuncOptions{
49
+	opts := runctypes.RuncOptions{
50 50
 		RuntimeRoot: filepath.Join(e.rootDir, "runtime-root"),
51 51
 	}
52 52
 	ctx := context.Background()
... ...
@@ -110,37 +110,37 @@ func (e *Executor) ProcessEvent(id string, et libcontainerd.EventType, ei libcon
110 110
 	return nil
111 111
 }
112 112
 
113
-type cio struct {
114
-	containerd.IO
113
+type rio struct {
114
+	cio.IO
115 115
 
116 116
 	wg sync.WaitGroup
117 117
 }
118 118
 
119
-func (c *cio) Wait() {
119
+func (c *rio) Wait() {
120 120
 	c.wg.Wait()
121 121
 	c.IO.Wait()
122 122
 }
123 123
 
124 124
 func attachStreamsFunc(stdout, stderr io.WriteCloser) libcontainerd.StdioCallback {
125
-	return func(iop *libcontainerd.IOPipe) (containerd.IO, error) {
125
+	return func(iop *libcontainerd.IOPipe) (cio.IO, error) {
126 126
 		if iop.Stdin != nil {
127 127
 			iop.Stdin.Close()
128 128
 			// closing stdin shouldn't be needed here, it should never be open
129 129
 			panic("plugin stdin shouldn't have been created!")
130 130
 		}
131 131
 
132
-		cio := &cio{IO: iop}
133
-		cio.wg.Add(2)
132
+		rio := &rio{IO: iop}
133
+		rio.wg.Add(2)
134 134
 		go func() {
135 135
 			io.Copy(stdout, iop.Stdout)
136 136
 			stdout.Close()
137
-			cio.wg.Done()
137
+			rio.wg.Done()
138 138
 		}()
139 139
 		go func() {
140 140
 			io.Copy(stderr, iop.Stderr)
141 141
 			stderr.Close()
142
-			cio.wg.Done()
142
+			rio.wg.Done()
143 143
 		}()
144
-		return cio, nil
144
+		return rio, nil
145 145
 	}
146 146
 }