cri: add the sandboxfiles package

The files a pod shares with its containers (hostname, hosts, resolv.conf,
the shm tmpfs) are produced by the podsandbox controller from the pod
config. A sandbox implementation outside the CRI server, such as a
Sandbox API shim, has to produce the same files. Put the pure helpers
(file and mount path constants, hostname and resolv.conf content, the shm
mount data) in a leaf package with no CRI server dependencies so that
both can use them. podsandbox is left unchanged for now.

Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
This commit is contained in:
Maksym Pavlenko committed 2026-11-02 09:45:08 -08:00
1 parent 5aaba1c85d
commit 3c0e785149
2 files changed
+152

No files matched your search

+88
View File
@@ -0,0 +1,88 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package sandboxfiles builds the content of the files a pod sandbox shares
// with every container of the pod: /etc/hostname, /etc/hosts, /etc/resolv.conf
// and the /dev/shm tmpfs.
//
// The package is deliberately a leaf: it has no dependency on the CRI server
// or on any sandbox implementation, so that both the in-process podsandbox
// controller and a shim that implements the Sandbox API can produce the same
// files. Where the files live and how they reach the containers is decided by
// the caller.
package sandboxfiles
import (
"fmt"
"strings"
)
const (
// HostnameFile is the file name of the pod hostname file.
HostnameFile = "hostname"
// HostsFile is the file name of the pod hosts file.
HostsFile = "hosts"
// ResolvConfFile is the file name of the pod resolv.conf.
ResolvConfFile = "resolv.conf"
// ShmDir is the directory name of the pod /dev/shm tmpfs.
ShmDir = "shm"
// EtcHostname is the path of the hostname file inside a container.
EtcHostname = "/etc/hostname"
// EtcHosts is the path of the hosts file on the host and inside a container.
EtcHosts = "/etc/hosts"
// ResolvConfPath is the path of resolv.conf on the host and inside a container.
ResolvConfPath = "/etc/resolv.conf"
// DevShm is the path of the shared memory tmpfs on the host and inside a container.
DevShm = "/dev/shm"
// DefaultShmSize is the default size of the pod /dev/shm tmpfs.
DefaultShmSize = int64(1024 * 1024 * 64)
)
// HostnameContent returns the content of the pod hostname file.
func HostnameContent(hostname string) []byte {
return []byte(hostname + "\n")
}
// ResolvConfContent renders resolv.conf content from CRI DNS options. When no
// option is specified the result is empty.
func ResolvConfContent(servers, searches, options []string) []byte {
var b strings.Builder
if len(searches) > 0 {
fmt.Fprintf(&b, "search %s\n", strings.Join(searches, " "))
}
if len(servers) > 0 {
fmt.Fprintf(&b, "nameserver %s\n", strings.Join(servers, "\nnameserver "))
}
if len(options) > 0 {
fmt.Fprintf(&b, "options %s\n", strings.Join(options, " "))
}
return []byte(b.String())
}
// ShmMountData returns the tmpfs mount data for a pod /dev/shm of the given
// size. A non-positive size falls back to DefaultShmSize.
func ShmMountData(size int64) string {
if size <= 0 {
size = DefaultShmSize
}
return fmt.Sprintf("mode=1777,size=%d", size)
}
@@ -0,0 +1,64 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package sandboxfiles
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestResolvConfContent(t *testing.T) {
for _, test := range []struct {
desc string
servers []string
searches []string
options []string
expected string
}{
{
desc: "empty dns options should return empty content",
expected: "",
},
{
desc: "non-empty dns options should return correct content",
servers: []string{"8.8.8.8", "8.8.4.4"},
searches: []string{"114.114.114.114"},
options: []string{"timeout:1"},
expected: "search 114.114.114.114\nnameserver 8.8.8.8\nnameserver 8.8.4.4\noptions timeout:1\n",
},
{
desc: "servers only",
servers: []string{"1.1.1.1"},
expected: "nameserver 1.1.1.1\n",
},
} {
t.Run(test.desc, func(t *testing.T) {
assert.Equal(t, test.expected, string(ResolvConfContent(test.servers, test.searches, test.options)))
})
}
}
func TestHostnameContent(t *testing.T) {
assert.Equal(t, "pod-1\n", string(HostnameContent("pod-1")))
}
func TestShmMountData(t *testing.T) {
assert.Equal(t, "mode=1777,size=67108864", ShmMountData(0))
assert.Equal(t, "mode=1777,size=67108864", ShmMountData(-1))
assert.Equal(t, "mode=1777,size=1024", ShmMountData(1024))
}