Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Commit 3f414ee

Browse files
committed
generate and maintain resolv.conf for sandbox
Signed-off-by: Crazykev <[email protected]>
1 parent 751f119 commit 3f414ee

File tree

5 files changed

+123
-11
lines changed

5 files changed

+123
-11
lines changed

pkg/server/container_start.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func (c *criContainerdService) startContainer(ctx context.Context, id string, me
119119
// Use fixed rootfs path for now.
120120
const rootPath = "/"
121121

122-
spec, err := c.generateContainerSpec(id, sandboxPid, config, sandboxConfig)
122+
spec, err := c.generateContainerSpec(id, sandboxID, sandboxPid, config, sandboxConfig)
123123
if err != nil {
124124
return fmt.Errorf("failed to generate container %q spec: %v", id, err)
125125
}
@@ -219,7 +219,7 @@ func (c *criContainerdService) startContainer(ctx context.Context, id string, me
219219
return nil
220220
}
221221

222-
func (c *criContainerdService) generateContainerSpec(id string, sandboxPid uint32, config *runtime.ContainerConfig, sandboxConfig *runtime.PodSandboxConfig) (*runtimespec.Spec, error) {
222+
func (c *criContainerdService) generateContainerSpec(id, sandboxID string, sandboxPid uint32, config *runtime.ContainerConfig, sandboxConfig *runtime.PodSandboxConfig) (*runtimespec.Spec, error) {
223223
// Creates a spec Generator with the default spec.
224224
// TODO(random-liu): [P2] Move container runtime spec generation into a helper function.
225225
g := generate.New()
@@ -283,7 +283,10 @@ func (c *criContainerdService) generateContainerSpec(id string, sandboxPid uint3
283283

284284
// TODO(random-liu): [P1] Bind mount sandbox /dev/shm.
285285

286-
// TODO(random-liu): [P0] Bind mount sandbox resolv.conf.
286+
// Bind mount sandbox resolv.conf.
287+
if resolvPath := getResolvPath(getSandboxRootDir(c.rootDir, sandboxID), sandboxConfig); resolvPath != "" {
288+
g.AddBindMount(resolvPath, resolvConfPath, []string{"ro"})
289+
}
287290

288291
return g.Spec(), nil
289292
}

pkg/server/container_start_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,22 +164,24 @@ func getStartContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandboxC
164164

165165
func TestGeneralContainerSpec(t *testing.T) {
166166
testID := "test-id"
167+
testPodID := "test-pod-id"
167168
testPid := uint32(1234)
168169
config, sandboxConfig, specCheck := getStartContainerTestData()
169170
c := newTestCRIContainerdService()
170-
spec, err := c.generateContainerSpec(testID, testPid, config, sandboxConfig)
171+
spec, err := c.generateContainerSpec(testID, testPodID, testPid, config, sandboxConfig)
171172
assert.NoError(t, err)
172173
specCheck(t, testID, testPid, spec)
173174
}
174175

175176
func TestContainerSpecTty(t *testing.T) {
176177
testID := "test-id"
178+
testPodID := "test-pod-id"
177179
testPid := uint32(1234)
178180
config, sandboxConfig, specCheck := getStartContainerTestData()
179181
c := newTestCRIContainerdService()
180182
for _, tty := range []bool{true, false} {
181183
config.Tty = tty
182-
spec, err := c.generateContainerSpec(testID, testPid, config, sandboxConfig)
184+
spec, err := c.generateContainerSpec(testID, testPodID, testPid, config, sandboxConfig)
183185
assert.NoError(t, err)
184186
specCheck(t, testID, testPid, spec)
185187
assert.Equal(t, tty, spec.Process.Terminal)
@@ -188,12 +190,13 @@ func TestContainerSpecTty(t *testing.T) {
188190

189191
func TestContainerSpecReadonlyRootfs(t *testing.T) {
190192
testID := "test-id"
193+
testPodID := "test-pod-id"
191194
testPid := uint32(1234)
192195
config, sandboxConfig, specCheck := getStartContainerTestData()
193196
c := newTestCRIContainerdService()
194197
for _, readonly := range []bool{true, false} {
195198
config.Linux.SecurityContext.ReadonlyRootfs = readonly
196-
spec, err := c.generateContainerSpec(testID, testPid, config, sandboxConfig)
199+
spec, err := c.generateContainerSpec(testID, testPodID, testPid, config, sandboxConfig)
197200
assert.NoError(t, err)
198201
specCheck(t, testID, testPid, spec)
199202
assert.Equal(t, readonly, spec.Root.Readonly)

pkg/server/helpers.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package server
1919
import (
2020
"fmt"
2121
"io"
22+
"os"
2223
"path/filepath"
2324
"strings"
2425
"syscall"
@@ -59,6 +60,11 @@ const (
5960
sandboxesDir = "sandboxes"
6061
// containersDir contains all container root.
6162
containersDir = "containers"
63+
// According to http://man7.org/linux/man-pages/man5/resolv.conf.5.html:
64+
// "The search list is currently limited to six domains with a total of 256 characters."
65+
maxDNSSearches = 6
66+
// resolvConfPath is the abs path of resolv.conf on host or container.
67+
resolvConfPath = "/etc/resolv.conf"
6268
// stdinNamedPipe is the name of stdin named pipe.
6369
stdinNamedPipe = "stdin"
6470
// stdoutNamedPipe is the name of stdout named pipe.
@@ -216,3 +222,86 @@ func (c *criContainerdService) getSandbox(id string) (*metadata.SandboxMetadata,
216222
func criContainerStateToString(state runtime.ContainerState) string {
217223
return runtime.ContainerState_name[int32(state)]
218224
}
225+
226+
// getResolvPath returns resolv.conf filepath for specified sandbox.
227+
func getResolvPath(sandboxRoot string, config *runtime.PodSandboxConfig) string {
228+
if config.GetDnsConfig() == nil {
229+
return ""
230+
}
231+
return filepath.Join(sandboxRoot, "resolv.conf")
232+
}
233+
234+
// parseDNSOptions parse and write DNS options to specified path
235+
// if none option is specified, will copy host's resolv.conf.
236+
func parseDNSOptions(servers, searches, options []string, path string) error {
237+
nServers := len(servers)
238+
nSearches := len(searches)
239+
nOptions := len(options)
240+
if nServers == 0 && nSearches == 0 && nOptions == 0 {
241+
return copyFile(resolvConfPath, path)
242+
}
243+
244+
if nSearches > maxDNSSearches {
245+
return fmt.Errorf("DNSOption.Searches has more than 6 domains")
246+
}
247+
248+
f, err := os.Create(path)
249+
if err != nil {
250+
return err
251+
}
252+
defer f.Close()
253+
254+
if nSearches > 0 {
255+
data := fmt.Sprintf("search %s\n", strings.Join(searches, " "))
256+
_, err = f.Write([]byte(data))
257+
if err != nil {
258+
return err
259+
}
260+
}
261+
262+
if nServers > 0 {
263+
data := fmt.Sprintf("nameserver %s\n", strings.Join(servers, "\nnameserver "))
264+
_, err = f.Write([]byte(data))
265+
if err != nil {
266+
return err
267+
}
268+
}
269+
270+
if nOptions > 0 {
271+
data := fmt.Sprintf("options %s\n", strings.Join(options, " "))
272+
_, err = f.Write([]byte(data))
273+
if err != nil {
274+
return err
275+
}
276+
}
277+
278+
return nil
279+
}
280+
281+
// copyFile copy src file to dest file
282+
func copyFile(src, dest string) error {
283+
in, err := os.Open(src)
284+
if err != nil {
285+
return err
286+
}
287+
defer in.Close()
288+
289+
out, err := os.Create(dest)
290+
if err != nil {
291+
return err
292+
}
293+
defer out.Close()
294+
295+
_, err = io.Copy(out, in)
296+
return err
297+
}
298+
299+
// removeFile will remove specified file, return success if not exist
300+
func removeFile(path string) error {
301+
if _, err := os.Stat(path); err == nil {
302+
if err := os.Remove(path); err != nil {
303+
return err
304+
}
305+
}
306+
return nil
307+
}

pkg/server/sandbox_run.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,10 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
124124
}
125125

126126
// Start sandbox container.
127-
spec := c.generateSandboxContainerSpec(id, config)
127+
spec, err := c.generateSandboxContainerSpec(id, config)
128+
if err != nil {
129+
return nil, fmt.Errorf("failed to generate pod spec: %v", err)
130+
}
128131
rawSpec, err := json.Marshal(spec)
129132
if err != nil {
130133
return nil, fmt.Errorf("failed to marshal oci spec %+v: %v", spec, err)
@@ -205,7 +208,7 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
205208
return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil
206209
}
207210

208-
func (c *criContainerdService) generateSandboxContainerSpec(id string, config *runtime.PodSandboxConfig) *runtimespec.Spec {
211+
func (c *criContainerdService) generateSandboxContainerSpec(id string, config *runtime.PodSandboxConfig) (*runtimespec.Spec, error) {
209212
// TODO(random-liu): [P0] Get command from image config.
210213
pauseCommand := []string{"sh", "-c", "while true; do sleep 1000000000; done"}
211214

@@ -225,7 +228,20 @@ func (c *criContainerdService) generateSandboxContainerSpec(id string, config *r
225228
// Set hostname.
226229
g.SetHostname(config.GetHostname())
227230

228-
// TODO(random-liu): [P0] Set DNS options. Maintain a resolv.conf for the sandbox.
231+
// Set DNS options.
232+
if dnsConfig := config.GetDnsConfig(); dnsConfig != nil {
233+
// resolvPath is not "" guaranteed by 'dnsConfig != nil'
234+
resolvPath := getResolvPath(getSandboxRootDir(c.rootDir, id), config)
235+
err := parseDNSOptions(dnsConfig.Servers, dnsConfig.Searches, dnsConfig.Options, resolvPath)
236+
if err != nil {
237+
err1 := removeFile(resolvPath)
238+
if err1 != nil {
239+
return nil, fmt.Errorf("%v; failed to remove %s: %v", err, resolvPath, err1)
240+
}
241+
return nil, err
242+
}
243+
g.AddBindMount(resolvPath, resolvConfPath, []string{"ro"})
244+
}
229245

230246
// TODO(random-liu): [P0] Add NamespaceGetter and PortMappingGetter to initialize network plugin.
231247

@@ -276,5 +292,5 @@ func (c *criContainerdService) generateSandboxContainerSpec(id string, config *r
276292

277293
// TODO(random-liu): [P1] Set default sandbox container resource limit.
278294

279-
return g.Spec()
295+
return g.Spec(), nil
280296
}

pkg/server/sandbox_run_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
113113
if test.configChange != nil {
114114
test.configChange(config)
115115
}
116-
spec := c.generateSandboxContainerSpec(testID, config)
116+
spec, err := c.generateSandboxContainerSpec(testID, config)
117+
assert.NoError(t, err)
117118
specCheck(t, testID, spec)
118119
if test.specCheck != nil {
119120
test.specCheck(t, spec)

0 commit comments

Comments
 (0)