Skip to content

Commit

Permalink
Introduce containerd-shim-runhcs-v1 on Windows
Browse files Browse the repository at this point in the history
Implements the containerd-shim-runhcs-v1 shim on Windows for the runtime
v2 shim API.

Signed-off-by: Justin Terry (VM) <juterry@microsoft.com>
  • Loading branch information
jterry75 committed Aug 22, 2018
1 parent 3f42445 commit 019b0c3
Show file tree
Hide file tree
Showing 101 changed files with 6,743 additions and 3,657 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ bin/containerd-shim-runc-v1: cmd/containerd-shim-runc-v1 FORCE # set !cgo and om
@echo "$(WHALE) bin/containerd-shim-runc-v1"
@CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v1 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v1

bin/containerd-shim-runhcs-v1: cmd/containerd-shim-runhcs-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220
@echo "$(WHALE) bin/containerd-shim-runhcs-v1${BINARY_SUFFIX}"
@CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runhcs-v1${BINARY_SUFFIX} ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runhcs-v1

binaries: $(BINARIES) ## build binaries
@echo "$(WHALE) $@"

Expand Down
1 change: 1 addition & 0 deletions Makefile.windows
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#Windows specific settings.
WHALE = "+"
ONI = "-"
COMMANDS += containerd-shim-runhcs-v1

BINARY_SUFFIX=".exe"

Expand Down
2 changes: 1 addition & 1 deletion cio/io_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) {
if fifos.Stdout != "" {
l, err := winio.ListenPipe(fifos.Stdout, nil)
if err != nil {
return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdout)
return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout)
}
defer func(l net.Listener) {
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions cmd/containerd-shim-runhcs-v1/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// +build windows

/*
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 main

import (
"github.com/containerd/containerd/runtime/v2/runhcs"
"github.com/containerd/containerd/runtime/v2/shim"
)

func main() {
shim.Run("io.containerd.runhcs.v1", runhcs.New)
}
98 changes: 98 additions & 0 deletions runtime/v2/runhcs/cmdutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// +build windows

/*
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 runhcs

import (
"bytes"
"context"
"os/exec"
"sync"
"syscall"
"time"
)

var (
bytesBufferPool = sync.Pool{
New: func() interface{} {
return bytes.NewBuffer(nil)
},
}
)

func getBuffer() *bytes.Buffer {
return bytesBufferPool.Get().(*bytes.Buffer)
}

func putBuffer(b *bytes.Buffer) {
b.Reset()
bytesBufferPool.Put(b)
}

type processExit struct {
pid uint32
exitStatus uint32
exitedAt time.Time
exitErr error
}

func runCmd(ctx context.Context, c *exec.Cmd) (*processExit, error) {
ec, startErr := startCmd(ctx, c)
if startErr != nil {
return nil, startErr
}
er, cmdErr := waitCmd(ctx, ec)
return er, cmdErr
}

func startCmd(ctx context.Context, c *exec.Cmd) (<-chan *processExit, error) {
if err := c.Start(); err != nil {
return nil, err
}
ec := make(chan *processExit, 1)
go func() {
defer close(ec)

var status int
eerr := c.Wait()
if eerr != nil {
status = 255
if exitErr, ok := eerr.(*exec.ExitError); ok {
if ws, ok := exitErr.Sys().(syscall.WaitStatus); ok {
status = ws.ExitStatus()
}
}
}
ec <- &processExit{
pid: uint32(c.Process.Pid),
exitStatus: uint32(status),
exitedAt: time.Now(),
exitErr: eerr,
}
}()

return ec, nil
}

func waitCmd(ctx context.Context, ec <-chan *processExit) (*processExit, error) {
e := <-ec
if e.exitStatus != 0 {
return e, e.exitErr
}
return e, nil
}
159 changes: 159 additions & 0 deletions runtime/v2/runhcs/io.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// +build windows

/*
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 runhcs

import (
"context"
"io"
"net"
"sync"
"time"

"github.com/Microsoft/go-winio"
"github.com/containerd/containerd/log"
runc "github.com/containerd/go-runc"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)

type pipeSet struct {
stdin net.Conn
stdout net.Conn
stderr net.Conn
}

// newPipeSet connects to the provided pipe addresses
func newPipeSet(ctx context.Context, stdin, stdout, stderr string, terminal bool) (*pipeSet, error) {
var (
err error
set = &pipeSet{}
)

defer func() {
if err != nil {
set.Close()
}
}()

g, _ := errgroup.WithContext(ctx)

dialfn := func(name string, conn *net.Conn) error {
if name == "" {
return nil
}
dialTimeout := 3 * time.Second
c, err := winio.DialPipe(name, &dialTimeout)
if err != nil {
return errors.Wrapf(err, "failed to connect to %s", name)
}
*conn = c
return nil
}

g.Go(func() error {
return dialfn(stdin, &set.stdin)
})
g.Go(func() error {
return dialfn(stdout, &set.stdout)
})
g.Go(func() error {
return dialfn(stderr, &set.stderr)
})

err = g.Wait()
if err != nil {
return nil, err
}
return set, nil
}

// Close terminates all successfully dialed IO connections
func (p *pipeSet) Close() {
for _, cn := range []net.Conn{p.stdin, p.stdout, p.stderr} {
if cn != nil {
cn.Close()
}
}
}

type pipeRelay struct {
ctx context.Context

ps *pipeSet
io runc.IO

wg sync.WaitGroup
once sync.Once
}

func newPipeRelay(ctx context.Context, ps *pipeSet, downstream runc.IO) *pipeRelay {
pr := &pipeRelay{
ctx: ctx,
ps: ps,
io: downstream,
}
if ps.stdin != nil {
go func() {
if _, err := io.Copy(downstream.Stdin(), ps.stdin); err != nil {
if err != winio.ErrFileClosed {
log.G(ctx).WithError(err).Error("error copying stdin to pipe")
}
}
}()
}
if ps.stdout != nil {
pr.wg.Add(1)
go func() {
if _, err := io.Copy(ps.stdout, downstream.Stdout()); err != nil {
log.G(ctx).WithError(err).Error("error copying stdout from pipe")
}
pr.wg.Done()
}()
}
if ps.stderr != nil {
pr.wg.Add(1)
go func() {
if _, err := io.Copy(ps.stderr, downstream.Stderr()); err != nil {
log.G(pr.ctx).WithError(err).Error("error copying stderr from pipe")
}
pr.wg.Done()
}()
}
return pr
}

func (pr *pipeRelay) wait() {
pr.wg.Wait()
}

// closeIO closes stdin to unblock an waiters
func (pr *pipeRelay) closeIO() {
if pr.ps.stdin != nil {
pr.ps.Close()
pr.io.Stdin().Close()
}
}

// close closes all open pipes
func (pr *pipeRelay) close() {
pr.once.Do(func() {
pr.io.Close()
pr.ps.Close()
})
}
Loading

0 comments on commit 019b0c3

Please sign in to comment.