From 6bf74c7a229bf6c4b1e1562deb6f69e17981b5ad Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Fri, 10 Aug 2018 09:52:02 -0700 Subject: [PATCH 1/4] Fixes an issue with state Occasionally the product will fail the state query and return "operation is not valid in the current sate". Rather than returning an error in this case we want to return state "unknown" with a valid json output for clients to be able to handle. Signed-off-by: Justin Terry (VM) --- cmd/runhcs/state.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/runhcs/state.go b/cmd/runhcs/state.go index 816230bd30..1d8a8ba08f 100644 --- a/cmd/runhcs/state.go +++ b/cmd/runhcs/state.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "os" + "strings" "github.com/Microsoft/hcsshim/internal/appargs" "github.com/urfave/cli" @@ -25,7 +26,10 @@ instance of a container.`, } status, err := c.Status() if err != nil { - return err + if !strings.Contains(err.Error(), "operation is not valid in the current state") { + return err + } + status = containerUnknown } cs := containerState{ Version: c.Spec.Version, From a7b6c59a3f451c582bc7013390978c19a9795081 Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Mon, 13 Aug 2018 08:20:41 -0700 Subject: [PATCH 2/4] Removes punctuation from start error Signed-off-by: Justin Terry (VM) --- cmd/runhcs/start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/runhcs/start.go b/cmd/runhcs/start.go index 788cbfc5f3..b510c88363 100644 --- a/cmd/runhcs/start.go +++ b/cmd/runhcs/start.go @@ -36,7 +36,7 @@ your host.`, case containerRunning: return errors.New("cannot start an already running container") default: - return fmt.Errorf("cannot start a container in the %s state\n", status) + return fmt.Errorf("cannot start a container in the '%s' state", status) } }, } From 2175e3ebbde2e86efa871db8aeef873d59551554 Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Tue, 14 Aug 2018 08:13:07 -0700 Subject: [PATCH 3/4] Add runhcs.exe create-scratch command Signed-off-by: Justin Terry (VM) --- cmd/runhcs/create-scratch.go | 75 ++++++++++++++++++++++++++++++++++++ cmd/runhcs/main.go | 1 + 2 files changed, 76 insertions(+) create mode 100644 cmd/runhcs/create-scratch.go diff --git a/cmd/runhcs/create-scratch.go b/cmd/runhcs/create-scratch.go new file mode 100644 index 0000000000..fe63cd336c --- /dev/null +++ b/cmd/runhcs/create-scratch.go @@ -0,0 +1,75 @@ +package main + +import ( + "os" + "path/filepath" + + "github.com/Microsoft/hcsshim/internal/osversion" + gcsclient "github.com/Microsoft/opengcs/client" + + "github.com/Microsoft/hcsshim/internal/appargs" + "github.com/Microsoft/hcsshim/internal/lcow" + "github.com/Microsoft/hcsshim/internal/uvm" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var createScratchCommand = cli.Command{ + Name: "create-scratch", + Usage: "creates a scratch vhdx at 'destpath' that is ext4 formatted", + Description: "Creates a scratch vhdx at 'destpath' that is ext4 formatted", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "destpath", + Usage: "Required: describes the destination vhd path", + }, + }, + Before: appargs.Validate(), + Action: func(context *cli.Context) error { + dest := context.String("destpath") + if dest == "" { + return errors.New("'destpath' is required") + } + + // If we only have v1 lcow support do it the old way. + if osversion.Get().Build < osversion.RS5 { + cfg := gcsclient.Config{ + Options: gcsclient.Options{ + KirdPath: filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers"), + KernelFile: "kernel", + InitrdFile: "initrd.img", + }, + Name: "createscratch-uvm", + UvmTimeoutSeconds: 5 * 60, // 5 Min + } + + if err := cfg.StartUtilityVM(); err != nil { + return errors.Wrapf(err, "failed to start '%s'", cfg.Name) + } + defer cfg.Uvm.Terminate() + + if err := cfg.CreateExt4Vhdx(dest, lcow.DefaultScratchSizeGB, ""); err != nil { + return errors.Wrapf(err, "failed to create ext4vhdx for '%s'", cfg.Name) + } + } else { + opts := uvm.UVMOptions{ + ID: "createscratch-uvm", + OperatingSystem: "linux", + } + convertUVM, err := uvm.Create(&opts) + if err != nil { + return errors.Wrapf(err, "failed to create '%s'", opts.ID) + } + if err := convertUVM.Start(); err != nil { + return errors.Wrapf(err, "failed to start '%s'", opts.ID) + } + defer convertUVM.Terminate() + + if err := lcow.CreateScratch(convertUVM, dest, lcow.DefaultScratchSizeGB, "", ""); err != nil { + return errors.Wrapf(err, "failed to create ext4vhdx for '%s'", opts.ID) + } + } + + return nil + }, +} diff --git a/cmd/runhcs/main.go b/cmd/runhcs/main.go index f7e7699b28..7386d03252 100644 --- a/cmd/runhcs/main.go +++ b/cmd/runhcs/main.go @@ -91,6 +91,7 @@ func main() { } app.Commands = []cli.Command{ createCommand, + createScratchCommand, deleteCommand, // eventsCommand, execCommand, From 56a3adc6f0e2f0b5e884530239b4a1bb6a4c5204 Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Mon, 13 Aug 2018 13:56:58 -0700 Subject: [PATCH 4/4] Adding runhcs.exe tar2vhd command Signed-off-by: Justin Terry (VM) --- cmd/runhcs/create-scratch.go | 5 +- cmd/runhcs/main.go | 1 + cmd/runhcs/tar2vhd.go | 116 +++++++++++++++++++++++++++++++++++ internal/lcow/tar2vhd.go | 3 + 4 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 cmd/runhcs/tar2vhd.go diff --git a/cmd/runhcs/create-scratch.go b/cmd/runhcs/create-scratch.go index fe63cd336c..55d26b5b07 100644 --- a/cmd/runhcs/create-scratch.go +++ b/cmd/runhcs/create-scratch.go @@ -4,12 +4,11 @@ import ( "os" "path/filepath" - "github.com/Microsoft/hcsshim/internal/osversion" - gcsclient "github.com/Microsoft/opengcs/client" - "github.com/Microsoft/hcsshim/internal/appargs" "github.com/Microsoft/hcsshim/internal/lcow" + "github.com/Microsoft/hcsshim/internal/osversion" "github.com/Microsoft/hcsshim/internal/uvm" + gcsclient "github.com/Microsoft/opengcs/client" "github.com/pkg/errors" "github.com/urfave/cli" ) diff --git a/cmd/runhcs/main.go b/cmd/runhcs/main.go index 7386d03252..eb395f354e 100644 --- a/cmd/runhcs/main.go +++ b/cmd/runhcs/main.go @@ -105,6 +105,7 @@ func main() { shimCommand, startCommand, stateCommand, + tarToVhdCommand, // updateCommand, vmshimCommand, } diff --git a/cmd/runhcs/tar2vhd.go b/cmd/runhcs/tar2vhd.go new file mode 100644 index 0000000000..2a7ed67716 --- /dev/null +++ b/cmd/runhcs/tar2vhd.go @@ -0,0 +1,116 @@ +package main + +import ( + "io" + "os" + "path/filepath" + + "github.com/Microsoft/hcsshim/internal/appargs" + "github.com/Microsoft/hcsshim/internal/lcow" + "github.com/Microsoft/hcsshim/internal/osversion" + "github.com/Microsoft/hcsshim/internal/uvm" + gcsclient "github.com/Microsoft/opengcs/client" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +var tarToVhdCommand = cli.Command{ + Name: "tar2vhd", + Usage: "converts a tar over stdin to a vhd at 'destpath'", + Description: "The tar2vhd command converts the tar at ('sourcepath'|stdin) to a vhd at 'destpath'", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "sourcepath", + Usage: "Optional: describes the path to the tar on disk", + }, + cli.StringFlag{ + Name: "scratchpath", + Usage: "Required: describes the path to the scratch.vhdx file to use for the transformation", + }, + cli.StringFlag{ + Name: "destpath", + Usage: "Required: describes the destination vhd path to write the contents of the tar to on disk", + }, + }, + Before: appargs.Validate(), + Action: func(context *cli.Context) error { + var rdr io.Reader + if src := context.String("sourcepath"); src != "" { + // Source is via file path not stdin + f, err := os.OpenFile(src, os.O_RDONLY, 0) + if err != nil { + return errors.Wrapf(err, "failed to open 'sourcepath': '%s'", src) + } + defer f.Close() + rdr = f + } else { + rdr = os.Stdin + } + + scratch := context.String("scratchpath") + if scratch == "" { + return errors.New("'scratchpath' is required") + } + + dest := context.String("destpath") + if dest == "" { + return errors.New("'destpath' is required") + } + + // If we only have v1 lcow support do it the old way. + if osversion.Get().Build < osversion.RS5 { + cfg := gcsclient.Config{ + Options: gcsclient.Options{ + KirdPath: filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers"), + KernelFile: "kernel", + InitrdFile: "initrd.img", + }, + Name: "tar2vhd-uvm", + UvmTimeoutSeconds: 5 * 60, // 5 Min + } + + if err := cfg.StartUtilityVM(); err != nil { + return errors.Wrapf(err, "failed to start '%s'", cfg.Name) + } + defer cfg.Uvm.Terminate() + + if err := cfg.HotAddVhd(scratch, "/tmp/scratch", false, true); err != nil { + return errors.Wrapf(err, "failed to mount scratch path: '%s' to '%s'", scratch, cfg.Name) + } + + n, err := cfg.TarToVhd(dest, rdr) + if err != nil { + return errors.Wrapf(err, "failed to convert tar2vhd for '%s'", cfg.Name) + } + + logrus.Debugf("wrote %v bytes to %s", n, dest) + } else { + opts := uvm.UVMOptions{ + ID: "tar2vhd-uvm", + OperatingSystem: "linux", + } + convertUVM, err := uvm.Create(&opts) + if err != nil { + return errors.Wrapf(err, "failed to create '%s'", opts.ID) + } + if err := convertUVM.Start(); err != nil { + return errors.Wrapf(err, "failed to start '%s'", opts.ID) + } + defer convertUVM.Terminate() + + if _, _, err := convertUVM.AddSCSI(scratch, "/tmp/scratch"); err != nil { + return errors.Wrapf(err, "failed to mount scratch path: '%s' to '%s'", scratch, opts.ID) + } + + n, err := lcow.TarToVhd(convertUVM, dest, rdr) + if err != nil { + return errors.Wrapf(err, "failed to convert tar2vhd for '%s'", opts.ID) + } + + logrus.Debugf("wrote %v bytes to %s", n, dest) + } + + return nil + }, +} diff --git a/internal/lcow/tar2vhd.go b/internal/lcow/tar2vhd.go index 0c4bdc631d..08d90a736b 100644 --- a/internal/lcow/tar2vhd.go +++ b/internal/lcow/tar2vhd.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "os" + "time" "github.com/Microsoft/hcsshim/internal/uvm" specs "github.com/opencontainers/runtime-spec/specs-go" @@ -28,10 +29,12 @@ func TarToVhd(lcowUVM *uvm.UtilityVM, targetVHDFile string, reader io.Reader) (i // BUGBUG Delete the file on failure tar2vhd, byteCounts, err := CreateProcess(&ProcessOptions{ + HCSSystem: lcowUVM.ComputeSystem(), Process: &specs.Process{Args: []string{"tar2vhd"}}, CreateInUtilityVm: true, Stdin: reader, Stdout: outFile, + CopyTimeout: 2 * time.Minute, }) if err != nil { return 0, fmt.Errorf("failed to start tar2vhd for %s: %s", targetVHDFile, err)