From 31616e7945ab37f659c97edba4e0238053cfb3c4 Mon Sep 17 00:00:00 2001 From: "Justin Terry (VM)" Date: Mon, 14 Jan 2019 11:46:45 -0800 Subject: [PATCH] Fix runhcs shim bug in Create with "len(Rootfs) == 0" Rootfs length can be set to zero if the upstream caller fully manages storage and mounts on their own. In this case just treat the bundle as a fully complete OCI spec and run it without doing any storage work in the shim. Signed-off-by: Justin Terry (VM) --- runtime/v2/runhcs/service.go | 61 ++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/runtime/v2/runhcs/service.go b/runtime/v2/runhcs/service.go index 421f546b9..9e54dd95c 100644 --- a/runtime/v2/runhcs/service.go +++ b/runtime/v2/runhcs/service.go @@ -337,7 +337,25 @@ func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI. } func writeMountsToConfig(bundle string, mounts []*containerd_types.Mount) error { - if len(mounts) != 1 { + cf, err := os.OpenFile(path.Join(bundle, "config.json"), os.O_RDWR, 0) + if err != nil { + return errors.Wrap(err, "bundle does not contain config.json") + } + defer cf.Close() + var spec oci.Spec + if err := json.NewDecoder(cf).Decode(&spec); err != nil { + return errors.Wrap(err, "bundle config.json is not valid oci spec") + } + + if len(mounts) == 0 { + // If no mounts are passed via the snapshotter its the callers full + // responsibility to manage the storage. Just move on without affecting + // the config.json at all. + if spec.Windows == nil || len(spec.Windows.LayerFolders) < 2 { + return errors.New("no Windows.LayerFolders found in oci spec") + } + return nil + } else if len(mounts) != 1 { return errors.New("Rootfs does not contain exactly 1 mount for the root file system") } @@ -367,29 +385,19 @@ func writeMountsToConfig(bundle string, mounts []*containerd_types.Mount) error opp := len(parentLayerPaths) - 1 - i parentLayerPaths[i], parentLayerPaths[opp] = parentLayerPaths[opp], parentLayerPaths[i] } - } - cf, err := os.OpenFile(path.Join(bundle, "config.json"), os.O_RDWR, 0) - if err != nil { - return errors.Wrap(err, "bundle does not contain config.json") - } - defer cf.Close() - var spec oci.Spec - if err := json.NewDecoder(cf).Decode(&spec); err != nil { - return errors.Wrap(err, "bundle config.json is not valid oci spec") - } - if err := cf.Truncate(0); err != nil { - return errors.Wrap(err, "failed to truncate config.json") - } - if _, err := cf.Seek(0, 0); err != nil { - return errors.Wrap(err, "failed to seek to 0 in config.json") - } - - // If we are creating LCOW make sure that spec.Windows is filled out before - // appending layer folders. - if m.Type == "lcow-layer" && spec.Windows == nil { - spec.Windows = &oci.Windows{ - HyperV: &oci.WindowsHyperV{}, + // If we are creating LCOW make sure that spec.Windows is filled out before + // appending layer folders. + if spec.Windows == nil { + spec.Windows = &oci.Windows{} + } + if spec.Windows.HyperV == nil { + spec.Windows.HyperV = &oci.WindowsHyperV{} + } + } else if spec.Windows.HyperV == nil { + // This is a Windows Argon make sure that we have a Root filled in. + if spec.Root == nil { + spec.Root = &oci.Root{} } } @@ -398,6 +406,13 @@ func writeMountsToConfig(bundle string, mounts []*containerd_types.Mount) error // Append the scratch spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, m.Source) + if err := cf.Truncate(0); err != nil { + return errors.Wrap(err, "failed to truncate config.json") + } + if _, err := cf.Seek(0, 0); err != nil { + return errors.Wrap(err, "failed to seek to 0 in config.json") + } + if err := json.NewEncoder(cf).Encode(spec); err != nil { return errors.Wrap(err, "failed to write Mounts into config.json") }