Skip to content

Commit

Permalink
Merge pull request #992 from katiewasnothere/test_execinhost_utility
Browse files Browse the repository at this point in the history
Add a utility function to exec in shimdiag for cri-containerd tests
  • Loading branch information
katiewasnothere authored Apr 8, 2021
2 parents 2b139f6 + 8a22e26 commit da33ecd
Show file tree
Hide file tree
Showing 42 changed files with 1,284 additions and 246 deletions.
39 changes: 5 additions & 34 deletions cmd/shimdiag/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import (
"os/signal"
"syscall"

"github.com/Microsoft/go-winio"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/appargs"
"github.com/Microsoft/hcsshim/internal/cmd"
"github.com/Microsoft/hcsshim/internal/shimdiag"
"github.com/containerd/console"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)

Expand Down Expand Up @@ -46,7 +44,7 @@ var execCommand = cli.Command{
Before: appargs.Validate(appargs.String, appargs.String, appargs.Rest(appargs.String)),
Action: func(clictx *cli.Context) error {
args := clictx.Args()
shim, err := getShim(args[0])
shim, err := shimdiag.GetShim(args[0])
if err != nil {
return err
}
Expand All @@ -69,17 +67,17 @@ var execCommand = cli.Command{
}
}

stdin, err := makePipe(osStdin, true)
stdin, err := cmd.CreatePipeAndListen(osStdin, true)
if err != nil {
return err
}
stdout, err := makePipe(os.Stdout, false)
stdout, err := cmd.CreatePipeAndListen(os.Stdout, false)
if err != nil {
return err
}
var stderr string
if !execTty {
stderr, err = makePipe(os.Stderr, false)
stderr, err = cmd.CreatePipeAndListen(os.Stderr, false)
if err != nil {
return err
}
Expand All @@ -105,30 +103,3 @@ var execCommand = cli.Command{
return cli.NewExitError(errors.New(""), int(resp.ExitCode))
},
}

func makePipe(f interface{}, in bool) (string, error) {
r, err := guid.NewV4()
if err != nil {
return "", err
}
p := `\\.\pipe\` + r.String()
l, err := winio.ListenPipe(p, nil)
if err != nil {
return "", err
}
go func() {
c, err := l.Accept()
if err != nil {
logrus.WithError(err).Error("failed to accept pipe")
return
}

if in {
_, _ = io.Copy(c, f.(io.Reader))
c.Close()
} else {
_, _ = io.Copy(f.(io.Writer), c)
}
}()
return p, nil
}
3 changes: 2 additions & 1 deletion cmd/shimdiag/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"text/tabwriter"

"github.com/Microsoft/hcsshim/internal/appargs"
"github.com/Microsoft/hcsshim/internal/shimdiag"
"github.com/urfave/cli"
)

Expand All @@ -22,7 +23,7 @@ var listCommand = cli.Command{
Before: appargs.Validate(),
Action: func(ctx *cli.Context) error {
pids := ctx.Bool("pids")
shims, err := findShims("")
shims, err := shimdiag.FindShims("")
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/shimdiag/share.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var shareCommand = cli.Command{
hostPath = args[1]
uvmPath = args[2]
)
shim, err := getShim(shimName)
shim, err := shimdiag.GetShim(shimName)
if err != nil {
return err
}
Expand Down
82 changes: 1 addition & 81 deletions cmd/shimdiag/shimdiag.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,9 @@ import (
"context"
"fmt"
"os"
"path/filepath"
"sort"
"strings"

"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/shimdiag"
"github.com/containerd/ttrpc"
"github.com/urfave/cli"
"golang.org/x/sys/windows"
)

const (
shimPrefix = `\\.\pipe\ProtectedPrefix\Administrators\containerd-shim-`
shimSuffix = `-pipe`
)

func main() {
Expand All @@ -36,77 +25,8 @@ func main() {
}
}

func findPipes(pattern string) ([]string, error) {
path := `\\.\pipe\*`
path16, err := windows.UTF16FromString(path)
if err != nil {
return nil, err
}
var data windows.Win32finddata
h, err := windows.FindFirstFile(&path16[0], &data)
if err != nil {
return nil, &os.PathError{Op: "FindFirstFile", Path: path, Err: err}
}
var names []string
for {
name := `\\.\pipe\` + windows.UTF16ToString(data.FileName[:])
if matched, _ := filepath.Match(pattern, name); matched {
names = append(names, name)
}
err = windows.FindNextFile(h, &data)
if err == windows.ERROR_NO_MORE_FILES {
break
}
if err != nil {
return nil, &os.PathError{Op: "FindNextFile", Path: path, Err: err}
}
}
return names, nil
}

func findShims(name string) ([]string, error) {
pipes, err := findPipes(shimPrefix + name + "*" + shimSuffix)
if err != nil {
return nil, err
}
for i, p := range pipes {
pipes[i] = p[len(shimPrefix) : len(p)-len(shimSuffix)]
}
sort.Strings(pipes)
return pipes, nil
}

func findShim(name string) (string, error) {
if strings.ContainsAny(name, "*?\\/") {
return "", fmt.Errorf("invalid shim name %s", name)
}
shims, err := findShims(name)
if err != nil {
return "", err
}
if len(shims) == 0 {
return "", fmt.Errorf("no such shim %s", name)
}
if len(shims) > 1 && shims[0] != name {
return "", fmt.Errorf("multiple shims beginning with %s", name)
}
return shims[0], nil
}

func getShim(name string) (*ttrpc.Client, error) {
shim, err := findShim(name)
if err != nil {
return nil, err
}
conn, err := winio.DialPipe(shimPrefix+shim+shimSuffix, nil)
if err != nil {
return nil, err
}
return ttrpc.NewClient(conn), nil
}

func getPid(shimName string) (int32, error) {
shim, err := getShim(shimName)
shim, err := shimdiag.GetShim(shimName)
if err != nil {
return 0, err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/shimdiag/stacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var stacksCommand = cli.Command{
ArgsUsage: "<shim name>",
Before: appargs.Validate(appargs.String),
Action: func(c *cli.Context) error {
shim, err := getShim(c.Args()[0])
shim, err := shimdiag.GetShim(c.Args()[0])
if err != nil {
return err
}
Expand Down
44 changes: 44 additions & 0 deletions internal/cmd/io_npipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package cmd
import (
"context"
"io"
"net"
"sync"

winio "github.com/Microsoft/go-winio"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -136,3 +138,45 @@ func (nio *npipeio) StderrPath() string {
func (nio *npipeio) Terminal() bool {
return nio.terminal
}

// CreatePipeAndListen is a helper function to create a pipe listener
// and accept connections. Returns the created pipe path on success.
//
// If `in` is true, `f` should implement io.Reader
// If `in` is false, `f` should implement io.Writer
func CreatePipeAndListen(f interface{}, in bool) (string, error) {
p, l, err := CreateNamedPipeListener()
if err != nil {
return "", err
}
go func() {
c, err := l.Accept()
if err != nil {
logrus.WithError(err).Error("failed to accept pipe")
return
}

if in {
_, _ = io.Copy(c, f.(io.Reader))
c.Close()
} else {
_, _ = io.Copy(f.(io.Writer), c)
}
}()
return p, nil
}

// CreateNamedPipeListener is a helper function to create and return a pipe listener
// and it's created path.
func CreateNamedPipeListener() (string, net.Listener, error) {
g, err := guid.NewV4()
if err != nil {
return "", nil, err
}
p := `\\.\pipe\` + g.String()
l, err := winio.ListenPipe(p, nil)
if err != nil {
return "", nil, err
}
return p, l, nil
}
19 changes: 1 addition & 18 deletions internal/devices/assigned_devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"net"
"strings"

winio "github.com/Microsoft/go-winio"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/cmd"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/shimdiag"
Expand Down Expand Up @@ -62,7 +60,7 @@ func AddDevice(ctx context.Context, vm *uvm.UtilityVM, idType, deviceID, deviceU
// parent bus device for the children devices' location paths from the uvm's view.
// Returns a slice of strings representing the resulting children location paths
func getChildrenDeviceLocationPaths(ctx context.Context, vm *uvm.UtilityVM, vmBusInstanceID string, deviceUtilPath string) ([]string, error) {
p, l, err := createNamedPipeListener()
p, l, err := cmd.CreateNamedPipeListener()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -111,21 +109,6 @@ func createDeviceUtilChildrenCommand(deviceUtilPath string, vmBusInstanceID stri
return args
}

// createNamedPipeListener is a helper function to create and return a pipe listener
// and it's created path.
func createNamedPipeListener() (string, net.Listener, error) {
g, err := guid.NewV4()
if err != nil {
return "", nil, err
}
p := `\\.\pipe\` + g.String()
l, err := winio.ListenPipe(p, nil)
if err != nil {
return "", nil, err
}
return p, l, nil
}

// readCsPipeOutput is a helper function that connects to a listener and reads
// the connection's comma separated output until done. resulting comma separated
// values are returned in the `result` param. The `errChan` param is used to
Expand Down
87 changes: 87 additions & 0 deletions internal/shimdiag/shimdiag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package shimdiag

import (
fmt "fmt"
"os"
"path/filepath"
"sort"
strings "strings"

"github.com/Microsoft/go-winio"
"github.com/containerd/ttrpc"
"golang.org/x/sys/windows"
)

const (
shimPrefix = `\\.\pipe\ProtectedPrefix\Administrators\containerd-shim-`
shimSuffix = `-pipe`
)

func findPipes(pattern string) ([]string, error) {
path := `\\.\pipe\*`
path16, err := windows.UTF16FromString(path)
if err != nil {
return nil, err
}
var data windows.Win32finddata
h, err := windows.FindFirstFile(&path16[0], &data)
if err != nil {
return nil, &os.PathError{Op: "FindFirstFile", Path: path, Err: err}
}
var names []string
for {
name := `\\.\pipe\` + windows.UTF16ToString(data.FileName[:])
if matched, _ := filepath.Match(pattern, name); matched {
names = append(names, name)
}
err = windows.FindNextFile(h, &data)
if err == windows.ERROR_NO_MORE_FILES {
break
}
if err != nil {
return nil, &os.PathError{Op: "FindNextFile", Path: path, Err: err}
}
}
return names, nil
}

func FindShims(name string) ([]string, error) {
pipes, err := findPipes(shimPrefix + name + "*" + shimSuffix)
if err != nil {
return nil, err
}
for i, p := range pipes {
pipes[i] = p[len(shimPrefix) : len(p)-len(shimSuffix)]
}
sort.Strings(pipes)
return pipes, nil
}

func findShim(name string) (string, error) {
if strings.ContainsAny(name, "*?\\/") {
return "", fmt.Errorf("invalid shim name %s", name)
}
shims, err := FindShims(name)
if err != nil {
return "", err
}
if len(shims) == 0 {
return "", fmt.Errorf("no such shim %s", name)
}
if len(shims) > 1 && shims[0] != name {
return "", fmt.Errorf("multiple shims beginning with %s", name)
}
return shims[0], nil
}

func GetShim(name string) (*ttrpc.Client, error) {
shim, err := findShim(name)
if err != nil {
return nil, err
}
conn, err := winio.DialPipe(shimPrefix+shim+shimSuffix, nil)
if err != nil {
return nil, err
}
return ttrpc.NewClient(conn), nil
}
Loading

0 comments on commit da33ecd

Please sign in to comment.