Skip to content

Commit 1fa69c7

Browse files
committed
pkg/container: take container namespace configuration
Signed-off-by: Peter Hunt <[email protected]>
1 parent 546732e commit 1fa69c7

File tree

5 files changed

+281
-59
lines changed

5 files changed

+281
-59
lines changed

pkg/container/container.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ type Container interface {
102102
// given the image information and passed-in container config
103103
SpecSetProcessArgs(imageOCIConfig *v1.Image) error
104104

105+
// SpecAddNamespaces sets the container's namespaces.
106+
SpecAddNamespaces(sb *sandbox.Sandbox) error
107+
105108
// WillRunSystemd checks whether the process args
106109
// are configured to be run as a systemd instance.
107110
WillRunSystemd() bool
@@ -260,20 +263,20 @@ func (c *container) Spec() *generate.Generator {
260263
}
261264

262265
// SetConfig sets the configuration to the container and validates it
263-
func (c *container) SetConfig(config *types.ContainerConfig, sboxConfig *types.PodSandboxConfig) error {
266+
func (c *container) SetConfig(cfg *types.ContainerConfig, sboxConfig *types.PodSandboxConfig) error {
264267
if c.config != nil {
265268
return errors.New("config already set")
266269
}
267270

268-
if config == nil {
271+
if cfg == nil {
269272
return errors.New("config is nil")
270273
}
271274

272-
if config.Metadata == nil {
275+
if cfg.Metadata == nil {
273276
return errors.New("metadata is nil")
274277
}
275278

276-
if config.Metadata.Name == "" {
279+
if cfg.Metadata.Name == "" {
277280
return errors.New("name is nil")
278281
}
279282

@@ -285,7 +288,7 @@ func (c *container) SetConfig(config *types.ContainerConfig, sboxConfig *types.P
285288
return errors.New("sandbox config is already set")
286289
}
287290

288-
c.config = config
291+
c.config = cfg
289292
c.sboxConfig = sboxConfig
290293
return nil
291294
}

pkg/container/namespaces.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package container
2+
3+
import (
4+
"github.com/cri-o/cri-o/internal/config/nsmgr"
5+
"github.com/cri-o/cri-o/internal/lib/sandbox"
6+
rspec "github.com/opencontainers/runtime-spec/specs-go"
7+
"github.com/opencontainers/runtime-tools/generate"
8+
"github.com/pkg/errors"
9+
types "k8s.io/cri-api/pkg/apis/runtime/v1"
10+
)
11+
12+
func (c *container) SpecAddNamespaces(sb *sandbox.Sandbox) error {
13+
// Join the namespace paths for the pod sandbox container.
14+
if err := ConfigureGeneratorGivenNamespacePaths(sb.NamespacePaths(), &c.spec); err != nil {
15+
return errors.Wrap(err, "failed to configure namespaces in container create")
16+
}
17+
18+
sc := c.config.Linux.SecurityContext
19+
20+
if sc.NamespaceOptions.Network == types.NamespaceMode_NODE {
21+
if err := c.spec.RemoveLinuxNamespace(string(rspec.NetworkNamespace)); err != nil {
22+
return err
23+
}
24+
}
25+
26+
switch sc.NamespaceOptions.Pid {
27+
case types.NamespaceMode_NODE:
28+
// kubernetes PodSpec specify to use Host PID namespace
29+
if err := c.spec.RemoveLinuxNamespace(string(rspec.PIDNamespace)); err != nil {
30+
return err
31+
}
32+
case types.NamespaceMode_POD:
33+
pidNsPath := sb.PidNsPath()
34+
if pidNsPath == "" {
35+
if sb.NamespaceOptions().Pid != types.NamespaceMode_POD {
36+
return errors.New("Pod level PID namespace requested for the container, but pod sandbox was not similarly configured, and does not have an infra container")
37+
}
38+
return errors.New("PID namespace requested, but sandbox infra container unexpectedly invalid")
39+
}
40+
41+
if err := c.spec.AddOrReplaceLinuxNamespace(string(rspec.PIDNamespace), pidNsPath); err != nil {
42+
return errors.Wrapf(err, "updating container PID namespace to pod")
43+
}
44+
}
45+
return nil
46+
}
47+
48+
// ConfigureGeneratorGivenNamespacePaths takes a map of nsType -> nsPath. It configures the generator
49+
// to add or replace the defaults to these paths
50+
func ConfigureGeneratorGivenNamespacePaths(managedNamespaces []*sandbox.ManagedNamespace, g *generate.Generator) error {
51+
typeToSpec := map[nsmgr.NSType]rspec.LinuxNamespaceType{
52+
nsmgr.IPCNS: rspec.IPCNamespace,
53+
nsmgr.NETNS: rspec.NetworkNamespace,
54+
nsmgr.UTSNS: rspec.UTSNamespace,
55+
nsmgr.USERNS: rspec.UserNamespace,
56+
}
57+
58+
for _, ns := range managedNamespaces {
59+
// allow for empty paths, as this namespace just shouldn't be configured
60+
if ns.Path() == "" {
61+
continue
62+
}
63+
nsForSpec := typeToSpec[ns.Type()]
64+
if nsForSpec == "" {
65+
return errors.Errorf("Invalid namespace type %s", ns.Type())
66+
}
67+
if err := g.AddOrReplaceLinuxNamespace(string(nsForSpec), ns.Path()); err != nil {
68+
return err
69+
}
70+
}
71+
return nil
72+
}

pkg/container/namespaces_test.go

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
package container_test
2+
3+
import (
4+
"os"
5+
6+
"github.com/cri-o/cri-o/internal/config/nsmgr"
7+
nsmgrtest "github.com/cri-o/cri-o/internal/config/nsmgr/test"
8+
"github.com/cri-o/cri-o/internal/lib/sandbox"
9+
. "github.com/onsi/ginkgo"
10+
. "github.com/onsi/gomega"
11+
rspec "github.com/opencontainers/runtime-spec/specs-go"
12+
types "k8s.io/cri-api/pkg/apis/runtime/v1"
13+
)
14+
15+
var _ = t.Describe("Container:SpecAddNamespaces", func() {
16+
It("should inherit pod namespaces", func() {
17+
// Given
18+
config := &types.ContainerConfig{
19+
Metadata: &types.ContainerMetadata{Name: "name"},
20+
Linux: &types.LinuxContainerConfig{
21+
SecurityContext: &types.LinuxContainerSecurityContext{
22+
NamespaceOptions: &types.NamespaceOption{
23+
Network: types.NamespaceMode_POD,
24+
Ipc: types.NamespaceMode_POD,
25+
Pid: types.NamespaceMode_CONTAINER,
26+
},
27+
},
28+
},
29+
}
30+
31+
sboxConfig := &types.PodSandboxConfig{}
32+
sb := &sandbox.Sandbox{}
33+
sb.AddManagedNamespaces(nsmgrtest.AllSpoofedNamespaces)
34+
sut.Spec().ClearLinuxNamespaces()
35+
36+
// When
37+
Expect(sut.SetConfig(config, sboxConfig)).To(BeNil())
38+
Expect(sut.SpecAddNamespaces(sb)).To(BeNil())
39+
40+
// Then
41+
spec := sut.Spec()
42+
Expect(len(spec.Config.Linux.Namespaces)).To(Equal(len(nsmgrtest.AllSpoofedNamespaces)))
43+
for _, ns := range nsmgrtest.AllSpoofedNamespaces {
44+
found := false
45+
for _, specNs := range spec.Config.Linux.Namespaces {
46+
if specNs.Path == ns.Path() {
47+
found = true
48+
}
49+
}
50+
Expect(found).To(Equal(true))
51+
}
52+
})
53+
It("should drop network if hostNet", func() {
54+
// Given
55+
config := &types.ContainerConfig{
56+
Metadata: &types.ContainerMetadata{Name: "name"},
57+
Linux: &types.LinuxContainerConfig{
58+
SecurityContext: &types.LinuxContainerSecurityContext{
59+
NamespaceOptions: &types.NamespaceOption{
60+
Network: types.NamespaceMode_NODE,
61+
Ipc: types.NamespaceMode_POD,
62+
Pid: types.NamespaceMode_CONTAINER,
63+
},
64+
},
65+
},
66+
}
67+
68+
sboxConfig := &types.PodSandboxConfig{}
69+
sb := &sandbox.Sandbox{}
70+
sb.AddManagedNamespaces(nsmgrtest.AllSpoofedNamespaces)
71+
72+
// When
73+
Expect(sut.SetConfig(config, sboxConfig)).To(BeNil())
74+
sut.Spec().ClearLinuxNamespaces()
75+
Expect(sut.SpecAddNamespaces(sb)).To(BeNil())
76+
77+
// Then
78+
spec := sut.Spec()
79+
Expect(len(spec.Config.Linux.Namespaces)).To(Equal(len(nsmgrtest.AllSpoofedNamespaces) - 1))
80+
81+
for _, specNs := range spec.Config.Linux.Namespaces {
82+
Expect(specNs.Type).NotTo(Equal(rspec.NetworkNamespace))
83+
}
84+
})
85+
It("should drop PID if hostPID", func() {
86+
// Given
87+
config := &types.ContainerConfig{
88+
Metadata: &types.ContainerMetadata{Name: "name"},
89+
Linux: &types.LinuxContainerConfig{
90+
SecurityContext: &types.LinuxContainerSecurityContext{
91+
NamespaceOptions: &types.NamespaceOption{
92+
Network: types.NamespaceMode_POD,
93+
Ipc: types.NamespaceMode_POD,
94+
Pid: types.NamespaceMode_NODE,
95+
},
96+
},
97+
},
98+
}
99+
100+
sboxConfig := &types.PodSandboxConfig{}
101+
sb := &sandbox.Sandbox{}
102+
sb.AddManagedNamespaces(nsmgrtest.AllSpoofedNamespaces)
103+
104+
// When
105+
Expect(sut.SetConfig(config, sboxConfig)).To(BeNil())
106+
sut.Spec().ClearLinuxNamespaces()
107+
Expect(sut.SpecAddNamespaces(sb)).To(BeNil())
108+
109+
// Then
110+
spec := sut.Spec()
111+
Expect(len(spec.Config.Linux.Namespaces)).To(Equal(len(nsmgrtest.AllSpoofedNamespaces)))
112+
113+
for _, specNs := range spec.Config.Linux.Namespaces {
114+
Expect(specNs.Type).NotTo(Equal(rspec.PIDNamespace))
115+
}
116+
})
117+
It("should use pod PID", func() {
118+
// Given
119+
config := &types.ContainerConfig{
120+
Metadata: &types.ContainerMetadata{Name: "name"},
121+
Linux: &types.LinuxContainerConfig{
122+
SecurityContext: &types.LinuxContainerSecurityContext{
123+
NamespaceOptions: &types.NamespaceOption{
124+
Network: types.NamespaceMode_POD,
125+
Ipc: types.NamespaceMode_POD,
126+
Pid: types.NamespaceMode_POD,
127+
},
128+
},
129+
},
130+
}
131+
132+
sboxConfig := &types.PodSandboxConfig{
133+
Linux: &types.LinuxPodSandboxConfig{
134+
SecurityContext: &types.LinuxSandboxSecurityContext{
135+
NamespaceOptions: &types.NamespaceOption{
136+
Network: types.NamespaceMode_POD,
137+
Ipc: types.NamespaceMode_POD,
138+
Pid: types.NamespaceMode_POD,
139+
},
140+
},
141+
},
142+
}
143+
sb := &sandbox.Sandbox{}
144+
infra, err := nsmgrtest.ContainerWithPid(os.Getpid())
145+
Expect(err).To(BeNil())
146+
Expect(sb.SetInfraContainer(infra)).To(BeNil())
147+
sb.AddManagedNamespaces(nsmgrtest.AllSpoofedNamespaces)
148+
149+
// When
150+
Expect(sut.SetConfig(config, sboxConfig)).To(BeNil())
151+
sut.Spec().ClearLinuxNamespaces()
152+
Expect(sut.SpecAddNamespaces(sb)).To(BeNil())
153+
154+
// Then
155+
spec := sut.Spec()
156+
Expect(len(spec.Config.Linux.Namespaces)).To(Equal(len(nsmgrtest.AllSpoofedNamespaces) + 1))
157+
158+
found := false
159+
for _, specNs := range spec.Config.Linux.Namespaces {
160+
if specNs.Type == rspec.PIDNamespace {
161+
found = true
162+
}
163+
}
164+
Expect(found).To(Equal(true))
165+
})
166+
It("should ignore if empty", func() {
167+
// Given
168+
config := &types.ContainerConfig{
169+
Metadata: &types.ContainerMetadata{Name: "name"},
170+
Linux: &types.LinuxContainerConfig{
171+
SecurityContext: &types.LinuxContainerSecurityContext{
172+
NamespaceOptions: &types.NamespaceOption{
173+
Network: types.NamespaceMode_POD,
174+
Ipc: types.NamespaceMode_POD,
175+
Pid: types.NamespaceMode_CONTAINER,
176+
},
177+
},
178+
},
179+
}
180+
181+
sboxConfig := &types.PodSandboxConfig{}
182+
sb := &sandbox.Sandbox{}
183+
sb.AddManagedNamespaces([]nsmgr.Namespace{&nsmgrtest.SpoofedNamespace{
184+
NsType: nsmgr.IPCNS,
185+
EmptyPath: true,
186+
}})
187+
188+
// When
189+
Expect(sut.SetConfig(config, sboxConfig)).To(BeNil())
190+
sut.Spec().ClearLinuxNamespaces()
191+
Expect(sut.SpecAddNamespaces(sb)).To(BeNil())
192+
193+
// Then
194+
spec := sut.Spec()
195+
Expect(len(spec.Config.Linux.Namespaces)).To(Equal(0))
196+
})
197+
})

server/container_create_linux.go

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -482,36 +482,12 @@ func (s *Server) createSandboxContainer(ctx context.Context, ctr ctrIface.Contai
482482
return nil, err
483483
}
484484

485-
// Join the namespace paths for the pod sandbox container.
486-
if err := configureGeneratorGivenNamespacePaths(sb.NamespacePaths(), specgen); err != nil {
487-
return nil, errors.Wrap(err, "failed to configure namespaces in container create")
488-
}
489-
490-
if securityContext.NamespaceOptions.Pid == types.NamespaceMode_NODE {
491-
// kubernetes PodSpec specify to use Host PID namespace
492-
if err := specgen.RemoveLinuxNamespace(string(rspec.PIDNamespace)); err != nil {
493-
return nil, err
494-
}
495-
} else if securityContext.NamespaceOptions.Pid == types.NamespaceMode_POD {
496-
pidNsPath := sb.PidNsPath()
497-
if pidNsPath == "" {
498-
if sb.NamespaceOptions().Pid != types.NamespaceMode_POD {
499-
return nil, errors.New("Pod level PID namespace requested for the container, but pod sandbox was not similarly configured, and does not have an infra container")
500-
}
501-
return nil, errors.New("PID namespace requested, but sandbox infra container unexpectedly invalid")
502-
}
503-
504-
if err := specgen.AddOrReplaceLinuxNamespace(string(rspec.PIDNamespace), pidNsPath); err != nil {
505-
return nil, err
506-
}
485+
if err := ctr.SpecAddNamespaces(sb); err != nil {
486+
return nil, err
507487
}
508488

509489
// If the sandbox is configured to run in the host network, do not create a new network namespace
510490
if hostNet {
511-
if err := specgen.RemoveLinuxNamespace(string(rspec.NetworkNamespace)); err != nil {
512-
return nil, err
513-
}
514-
515491
if !isInCRIMounts("/sys", containerConfig.Mounts) {
516492
ctr.SpecAddMount(rspec.Mount{
517493
Destination: "/sys",

server/sandbox_run_linux.go

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/cri-o/cri-o/internal/resourcestore"
2626
ann "github.com/cri-o/cri-o/pkg/annotations"
2727
libconfig "github.com/cri-o/cri-o/pkg/config"
28+
ctrIface "github.com/cri-o/cri-o/pkg/container"
2829
"github.com/cri-o/cri-o/pkg/sandbox"
2930
"github.com/cri-o/cri-o/utils"
3031
json "github.com/json-iterator/go"
@@ -1073,36 +1074,9 @@ func (s *Server) configureGeneratorForSandboxNamespaces(hostNetwork, hostIPC, ho
10731074

10741075
cleanupFuncs = append(cleanupFuncs, sb.RemoveManagedNamespaces)
10751076

1076-
if err := configureGeneratorGivenNamespacePaths(sb.NamespacePaths(), g); err != nil {
1077+
if err := ctrIface.ConfigureGeneratorGivenNamespacePaths(sb.NamespacePaths(), g); err != nil {
10771078
return cleanupFuncs, err
10781079
}
10791080

10801081
return cleanupFuncs, nil
10811082
}
1082-
1083-
// configureGeneratorGivenNamespacePaths takes a map of nsType -> nsPath. It configures the generator
1084-
// to add or replace the defaults to these paths
1085-
func configureGeneratorGivenNamespacePaths(managedNamespaces []*libsandbox.ManagedNamespace, g *generate.Generator) error {
1086-
typeToSpec := map[nsmgr.NSType]spec.LinuxNamespaceType{
1087-
nsmgr.IPCNS: spec.IPCNamespace,
1088-
nsmgr.NETNS: spec.NetworkNamespace,
1089-
nsmgr.UTSNS: spec.UTSNamespace,
1090-
nsmgr.USERNS: spec.UserNamespace,
1091-
}
1092-
1093-
for _, ns := range managedNamespaces {
1094-
// allow for empty paths, as this namespace just shouldn't be configured
1095-
if ns.Path() == "" {
1096-
continue
1097-
}
1098-
nsForSpec := typeToSpec[ns.Type()]
1099-
if nsForSpec == "" {
1100-
return errors.Errorf("Invalid namespace type %s", nsForSpec)
1101-
}
1102-
err := g.AddOrReplaceLinuxNamespace(string(nsForSpec), ns.Path())
1103-
if err != nil {
1104-
return err
1105-
}
1106-
}
1107-
return nil
1108-
}

0 commit comments

Comments
 (0)