Add a Windows section for Linux oci on LCOW
When creating a default OCI spec on Windows that is targeting the LCOW platform it needs to contain a Windows section as well. This adds the Windows section by default. It also protects against this case for all OCI creation that doesnt use the OCI package in the runhcs-shim. Signed-off-by: Justin Terry (VM) <juterry@microsoft.com>
This commit is contained in:
parent
96986c04db
commit
ef910311e8
31
oci/spec.go
31
oci/spec.go
@ -19,6 +19,7 @@ package oci
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
"github.com/containerd/containerd/platforms"
|
"github.com/containerd/containerd/platforms"
|
||||||
@ -51,24 +52,32 @@ func GenerateSpec(ctx context.Context, client Client, c *containers.Container, o
|
|||||||
// GenerateSpecWithPlatform will generate a default spec from the provided image
|
// GenerateSpecWithPlatform will generate a default spec from the provided image
|
||||||
// for use as a containerd container in the platform requested.
|
// for use as a containerd container in the platform requested.
|
||||||
func GenerateSpecWithPlatform(ctx context.Context, client Client, platform string, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
|
func GenerateSpecWithPlatform(ctx context.Context, client Client, platform string, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
|
||||||
plat, err := platforms.Parse(platform)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var s Spec
|
var s Spec
|
||||||
if plat.OS == "windows" {
|
if err := generateDefaultSpecWithPlatform(ctx, platform, c.ID, &s); err != nil {
|
||||||
err = populateDefaultWindowsSpec(ctx, &s, c.ID)
|
|
||||||
} else {
|
|
||||||
err = populateDefaultUnixSpec(ctx, &s, c.ID)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &s, ApplyOpts(ctx, client, c, &s, opts...)
|
return &s, ApplyOpts(ctx, client, c, &s, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateDefaultSpecWithPlatform(ctx context.Context, platform, id string, s *Spec) error {
|
||||||
|
plat, err := platforms.Parse(platform)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if plat.OS == "windows" {
|
||||||
|
err = populateDefaultWindowsSpec(ctx, s, id)
|
||||||
|
} else {
|
||||||
|
err = populateDefaultUnixSpec(ctx, s, id)
|
||||||
|
if err == nil && runtime.GOOS == "windows" {
|
||||||
|
// To run LCOW we have a Linux and Windows section. Add an empty one now.
|
||||||
|
s.Windows = &specs.Windows{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// ApplyOpts applys the options to the given spec, injecting data from the
|
// ApplyOpts applys the options to the given spec, injecting data from the
|
||||||
// context, client and container instance.
|
// context, client and container instance.
|
||||||
func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error {
|
func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error {
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -91,10 +90,7 @@ func setCapabilities(s *Spec) {
|
|||||||
// Use as the first option to clear the spec, then apply options afterwards.
|
// Use as the first option to clear the spec, then apply options afterwards.
|
||||||
func WithDefaultSpec() SpecOpts {
|
func WithDefaultSpec() SpecOpts {
|
||||||
return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
|
return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
|
||||||
if runtime.GOOS == "windows" {
|
return generateDefaultSpecWithPlatform(ctx, platforms.DefaultString(), c.ID, s)
|
||||||
return populateDefaultWindowsSpec(ctx, s, c.ID)
|
|
||||||
}
|
|
||||||
return populateDefaultUnixSpec(ctx, s, c.ID)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,15 +100,7 @@ func WithDefaultSpec() SpecOpts {
|
|||||||
// Use as the first option to clear the spec, then apply options afterwards.
|
// Use as the first option to clear the spec, then apply options afterwards.
|
||||||
func WithDefaultSpecForPlatform(platform string) SpecOpts {
|
func WithDefaultSpecForPlatform(platform string) SpecOpts {
|
||||||
return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
|
return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
|
||||||
plat, err := platforms.Parse(platform)
|
return generateDefaultSpecWithPlatform(ctx, platform, c.ID, s)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if plat.OS == "windows" {
|
|
||||||
return populateDefaultWindowsSpec(ctx, s, c.ID)
|
|
||||||
}
|
|
||||||
return populateDefaultUnixSpec(ctx, s, c.ID)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,44 @@ func TestGenerateSpec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerateSpecWithPlatform(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ctx := namespaces.WithNamespace(context.Background(), "testing")
|
||||||
|
platforms := []string{"windows/amd64", "linux/amd64"}
|
||||||
|
for _, p := range platforms {
|
||||||
|
t.Logf("Testing platform: %s", p)
|
||||||
|
s, err := GenerateSpecWithPlatform(ctx, nil, p, &containers.Container{ID: t.Name()})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to generate spec: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Root == nil {
|
||||||
|
t.Fatal("expected non nil Root section.")
|
||||||
|
}
|
||||||
|
if s.Process == nil {
|
||||||
|
t.Fatal("expected non nil Process section.")
|
||||||
|
}
|
||||||
|
if p == "windows/amd64" {
|
||||||
|
if s.Linux != nil {
|
||||||
|
t.Fatal("expected nil Linux section")
|
||||||
|
}
|
||||||
|
if s.Windows == nil {
|
||||||
|
t.Fatal("expected non nil Windows section")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if s.Linux == nil {
|
||||||
|
t.Fatal("expected non nil Linux section")
|
||||||
|
}
|
||||||
|
if runtime.GOOS == "windows" && s.Windows == nil {
|
||||||
|
t.Fatal("expected non nil Windows section for LCOW")
|
||||||
|
} else if runtime.GOOS != "windows" && s.Windows != nil {
|
||||||
|
t.Fatal("expected nil Windows section")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSpecWithTTY(t *testing.T) {
|
func TestSpecWithTTY(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
@ -314,6 +314,14 @@ func writeMountsToConfig(bundle string, mounts []*containerd_types.Mount) error
|
|||||||
return errors.Wrap(err, "failed to seek to 0 in config.json")
|
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{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Append the parents
|
// Append the parents
|
||||||
spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, parentLayerPaths...)
|
spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, parentLayerPaths...)
|
||||||
// Append the scratch
|
// Append the scratch
|
||||||
|
Loading…
Reference in New Issue
Block a user