Skip to content

Commit c818a6b

Browse files
committed
Merges the oci package for Linux and Windows
On Windows we need to be able to create both Linux and Windows OCI spec files by default to support WCOW and LCOW scenarios. This merges the compile time differences into runtime differences between the two based on the spec and platform the user sets. It maintains the old behavior with Default specs resulting in the platform default the binary is compiled for. Signed-off-by: Justin Terry (VM) <[email protected]>
1 parent 0649e38 commit c818a6b

9 files changed

Lines changed: 1076 additions & 1141 deletions

File tree

cmd/ctr/commands/run/run_windows.go

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,12 @@ import (
2222
"github.com/containerd/console"
2323
"github.com/containerd/containerd"
2424
"github.com/containerd/containerd/cmd/ctr/commands"
25-
"github.com/containerd/containerd/containers"
2625
"github.com/containerd/containerd/oci"
2726
specs "github.com/opencontainers/runtime-spec/specs-go"
2827
"github.com/sirupsen/logrus"
2928
"github.com/urfave/cli"
3029
)
3130

32-
func withTTY(terminal bool) oci.SpecOpts {
33-
if !terminal {
34-
return func(ctx gocontext.Context, client oci.Client, c *containers.Container, s *specs.Spec) error {
35-
s.Process.Terminal = false
36-
return nil
37-
}
38-
}
39-
40-
con := console.Current()
41-
size, err := con.Size()
42-
if err != nil {
43-
logrus.WithError(err).Error("console size")
44-
}
45-
return oci.WithTTY(int(size.Width), int(size.Height))
46-
}
47-
4831
// NewContainer creates a new container
4932
func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
5033
var (
@@ -73,7 +56,17 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
7356
opts = append(opts, oci.WithImageConfig(image))
7457
opts = append(opts, oci.WithEnv(context.StringSlice("env")))
7558
opts = append(opts, withMounts(context))
76-
opts = append(opts, withTTY(context.Bool("tty")))
59+
if context.Bool("tty") {
60+
opts = append(opts, oci.WithTTY)
61+
62+
con := console.Current()
63+
size, err := con.Size()
64+
if err != nil {
65+
logrus.WithError(err).Error("console size")
66+
}
67+
opts = append(opts, oci.WithTTYSize(int(size.Width), int(size.Height)))
68+
}
69+
7770
if len(args) > 0 {
7871
opts = append(opts, oci.WithProcessArgs(args...))
7972
}

oci/spec.go

Lines changed: 202 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,55 @@ package oci
1818

1919
import (
2020
"context"
21+
"path/filepath"
22+
23+
"github.com/containerd/containerd/namespaces"
24+
"github.com/containerd/containerd/platforms"
2125

2226
"github.com/containerd/containerd/containers"
2327
specs "github.com/opencontainers/runtime-spec/specs-go"
2428
)
2529

30+
const (
31+
rwm = "rwm"
32+
defaultRootfsPath = "rootfs"
33+
)
34+
35+
var (
36+
defaultUnixEnv = []string{
37+
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
38+
}
39+
)
40+
2641
// Spec is a type alias to the OCI runtime spec to allow third part SpecOpts
2742
// to be created without the "issues" with go vendoring and package imports
2843
type Spec = specs.Spec
2944

3045
// GenerateSpec will generate a default spec from the provided image
3146
// for use as a containerd container
3247
func GenerateSpec(ctx context.Context, client Client, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
33-
s, err := createDefaultSpec(ctx, c.ID)
48+
return GenerateSpecWithPlatform(ctx, client, platforms.DefaultString(), c, opts...)
49+
}
50+
51+
// GenerateSpecWithPlatform will generate a default spec from the provided image
52+
// for use as a containerd container in the platform requested.
53+
func GenerateSpecWithPlatform(ctx context.Context, client Client, platform string, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
54+
plat, err := platforms.Parse(platform)
3455
if err != nil {
3556
return nil, err
3657
}
3758

38-
return s, ApplyOpts(ctx, client, c, s, opts...)
59+
var s Spec
60+
if plat.OS == "windows" {
61+
err = populateDefaultWindowsSpec(ctx, &s, c.ID)
62+
} else {
63+
err = populateDefaultUnixSpec(ctx, &s, c.ID)
64+
}
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
return &s, ApplyOpts(ctx, client, c, &s, opts...)
3970
}
4071

4172
// ApplyOpts applys the options to the given spec, injecting data from the
@@ -50,7 +81,173 @@ func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *S
5081
return nil
5182
}
5283

53-
func createDefaultSpec(ctx context.Context, id string) (*Spec, error) {
54-
var s Spec
55-
return &s, populateDefaultSpec(ctx, &s, id)
84+
func defaultUnixCaps() []string {
85+
return []string{
86+
"CAP_CHOWN",
87+
"CAP_DAC_OVERRIDE",
88+
"CAP_FSETID",
89+
"CAP_FOWNER",
90+
"CAP_MKNOD",
91+
"CAP_NET_RAW",
92+
"CAP_SETGID",
93+
"CAP_SETUID",
94+
"CAP_SETFCAP",
95+
"CAP_SETPCAP",
96+
"CAP_NET_BIND_SERVICE",
97+
"CAP_SYS_CHROOT",
98+
"CAP_KILL",
99+
"CAP_AUDIT_WRITE",
100+
}
101+
}
102+
103+
func defaultUnixNamespaces() []specs.LinuxNamespace {
104+
return []specs.LinuxNamespace{
105+
{
106+
Type: specs.PIDNamespace,
107+
},
108+
{
109+
Type: specs.IPCNamespace,
110+
},
111+
{
112+
Type: specs.UTSNamespace,
113+
},
114+
{
115+
Type: specs.MountNamespace,
116+
},
117+
{
118+
Type: specs.NetworkNamespace,
119+
},
120+
}
121+
}
122+
123+
func populateDefaultUnixSpec(ctx context.Context, s *Spec, id string) error {
124+
ns, err := namespaces.NamespaceRequired(ctx)
125+
if err != nil {
126+
return err
127+
}
128+
129+
*s = Spec{
130+
Version: specs.Version,
131+
Root: &specs.Root{
132+
Path: defaultRootfsPath,
133+
},
134+
Process: &specs.Process{
135+
Env: defaultUnixEnv,
136+
Cwd: "/",
137+
NoNewPrivileges: true,
138+
User: specs.User{
139+
UID: 0,
140+
GID: 0,
141+
},
142+
Capabilities: &specs.LinuxCapabilities{
143+
Bounding: defaultUnixCaps(),
144+
Permitted: defaultUnixCaps(),
145+
Inheritable: defaultUnixCaps(),
146+
Effective: defaultUnixCaps(),
147+
},
148+
Rlimits: []specs.POSIXRlimit{
149+
{
150+
Type: "RLIMIT_NOFILE",
151+
Hard: uint64(1024),
152+
Soft: uint64(1024),
153+
},
154+
},
155+
},
156+
Mounts: []specs.Mount{
157+
{
158+
Destination: "/proc",
159+
Type: "proc",
160+
Source: "proc",
161+
},
162+
{
163+
Destination: "/dev",
164+
Type: "tmpfs",
165+
Source: "tmpfs",
166+
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
167+
},
168+
{
169+
Destination: "/dev/pts",
170+
Type: "devpts",
171+
Source: "devpts",
172+
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
173+
},
174+
{
175+
Destination: "/dev/shm",
176+
Type: "tmpfs",
177+
Source: "shm",
178+
Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
179+
},
180+
{
181+
Destination: "/dev/mqueue",
182+
Type: "mqueue",
183+
Source: "mqueue",
184+
Options: []string{"nosuid", "noexec", "nodev"},
185+
},
186+
{
187+
Destination: "/sys",
188+
Type: "sysfs",
189+
Source: "sysfs",
190+
Options: []string{"nosuid", "noexec", "nodev", "ro"},
191+
},
192+
{
193+
Destination: "/run",
194+
Type: "tmpfs",
195+
Source: "tmpfs",
196+
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
197+
},
198+
},
199+
Linux: &specs.Linux{
200+
MaskedPaths: []string{
201+
"/proc/acpi",
202+
"/proc/kcore",
203+
"/proc/keys",
204+
"/proc/latency_stats",
205+
"/proc/timer_list",
206+
"/proc/timer_stats",
207+
"/proc/sched_debug",
208+
"/sys/firmware",
209+
"/proc/scsi",
210+
},
211+
ReadonlyPaths: []string{
212+
"/proc/asound",
213+
"/proc/bus",
214+
"/proc/fs",
215+
"/proc/irq",
216+
"/proc/sys",
217+
"/proc/sysrq-trigger",
218+
},
219+
CgroupsPath: filepath.Join("/", ns, id),
220+
Resources: &specs.LinuxResources{
221+
Devices: []specs.LinuxDeviceCgroup{
222+
{
223+
Allow: false,
224+
Access: rwm,
225+
},
226+
},
227+
},
228+
Namespaces: defaultUnixNamespaces(),
229+
},
230+
}
231+
return nil
232+
}
233+
234+
func populateDefaultWindowsSpec(ctx context.Context, s *Spec, id string) error {
235+
*s = Spec{
236+
Version: specs.Version,
237+
Root: &specs.Root{},
238+
Process: &specs.Process{
239+
Cwd: `C:\`,
240+
ConsoleSize: &specs.Box{
241+
Width: 80,
242+
Height: 20,
243+
},
244+
},
245+
Windows: &specs.Windows{
246+
IgnoreFlushesDuringBoot: true,
247+
Network: &specs.WindowsNetwork{
248+
AllowUnqualifiedDNSQuery: true,
249+
},
250+
},
251+
}
252+
return nil
56253
}

0 commit comments

Comments
 (0)