Merge pull request #15632 from dfr/freebsd-container

Add support for FreeBSD containers
This commit is contained in:
OpenShift Merge Robot
2022-09-06 12:43:55 +02:00
committed by GitHub
12 changed files with 3277 additions and 2866 deletions

View File

@ -1133,20 +1133,6 @@ func (c *Container) NetworkDisabled() (bool, error) {
return networkDisabled(c) return networkDisabled(c)
} }
func networkDisabled(c *Container) (bool, error) {
if c.config.CreateNetNS {
return false, nil
}
if !c.config.PostConfigureNetNS {
for _, ns := range c.config.Spec.Linux.Namespaces {
if ns.Type == spec.NetworkNamespace {
return ns.Path == "", nil
}
}
}
return false, nil
}
func (c *Container) HostNetwork() bool { func (c *Container) HostNetwork() bool {
if c.config.CreateNetNS || c.config.NetNsCtr != "" { if c.config.CreateNetNS || c.config.NetNsCtr != "" {
return false return false

View File

@ -10,3 +10,13 @@ type containerPlatformState struct {
// namespace. // namespace.
NetworkJail string `json:"-"` NetworkJail string `json:"-"`
} }
func networkDisabled(c *Container) (bool, error) {
if c.config.CreateNetNS {
return false, nil
}
if !c.config.PostConfigureNetNS {
return c.state.NetworkJail == "", nil
}
return false, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,285 @@
//go:build freebsd
// +build freebsd
package libpod
import (
"errors"
"fmt"
"os"
"strings"
"sync"
"syscall"
"time"
"github.com/containers/common/libnetwork/types"
"github.com/containers/podman/v4/pkg/rootless"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
var (
bindOptions = []string{}
)
// Network stubs to decouple container_internal_freebsd.go from
// networking_freebsd.go so they can be reviewed separately.
func (r *Runtime) createNetNS(ctr *Container) (netJail string, q map[string]types.StatusBlock, retErr error) {
return "", nil, errors.New("not implemented (*Runtime) createNetNS")
}
func (r *Runtime) teardownNetNS(ctr *Container) error {
return errors.New("not implemented (*Runtime) teardownNetNS")
}
func (r *Runtime) reloadContainerNetwork(ctr *Container) (map[string]types.StatusBlock, error) {
return nil, errors.New("not implemented (*Runtime) reloadContainerNetwork")
}
func (c *Container) mountSHM(shmOptions string) error {
return nil
}
func (c *Container) unmountSHM(path string) error {
return nil
}
// prepare mounts the container and sets up other required resources like net
// namespaces
func (c *Container) prepare() error {
var (
wg sync.WaitGroup
jailName string
networkStatus map[string]types.StatusBlock
createNetNSErr, mountStorageErr error
mountPoint string
tmpStateLock sync.Mutex
)
wg.Add(2)
go func() {
defer wg.Done()
// Set up network namespace if not already set up
noNetNS := c.state.NetworkJail == ""
if c.config.CreateNetNS && noNetNS && !c.config.PostConfigureNetNS {
jailName, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
if createNetNSErr != nil {
return
}
tmpStateLock.Lock()
defer tmpStateLock.Unlock()
// Assign NetNS attributes to container
c.state.NetworkJail = jailName
c.state.NetworkStatus = networkStatus
}
}()
// Mount storage if not mounted
go func() {
defer wg.Done()
mountPoint, mountStorageErr = c.mountStorage()
if mountStorageErr != nil {
return
}
tmpStateLock.Lock()
defer tmpStateLock.Unlock()
// Finish up mountStorage
c.state.Mounted = true
c.state.Mountpoint = mountPoint
logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)
}()
wg.Wait()
var createErr error
if mountStorageErr != nil {
if createErr != nil {
logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
}
createErr = mountStorageErr
}
if createErr != nil {
return createErr
}
// Save changes to container state
if err := c.save(); err != nil {
return err
}
return nil
}
// cleanupNetwork unmounts and cleans up the container's network
func (c *Container) cleanupNetwork() error {
if c.config.NetNsCtr != "" {
return nil
}
netDisabled, err := c.NetworkDisabled()
if err != nil {
return err
}
if netDisabled {
return nil
}
// Stop the container's network namespace (if it has one)
if err := c.runtime.teardownNetNS(c); err != nil {
logrus.Errorf("Unable to cleanup network for container %s: %q", c.ID(), err)
}
if c.valid {
return c.save()
}
return nil
}
// reloadNetwork reloads the network for the given container, recreating
// firewall rules.
func (c *Container) reloadNetwork() error {
result, err := c.runtime.reloadContainerNetwork(c)
if err != nil {
return err
}
c.state.NetworkStatus = result
return c.save()
}
// Add an existing container's network jail
func (c *Container) addNetworkContainer(g *generate.Generator, ctr string) error {
nsCtr, err := c.runtime.state.Container(ctr)
c.runtime.state.UpdateContainer(nsCtr)
if err != nil {
return fmt.Errorf("error retrieving dependency %s of container %s from state: %w", ctr, c.ID(), err)
}
g.AddAnnotation("org.freebsd.parentJail", nsCtr.state.NetworkJail)
return nil
}
func isRootlessCgroupSet(cgroup string) bool {
return false
}
func (c *Container) expectPodCgroup() (bool, error) {
return false, nil
}
func (c *Container) getOCICgroupPath() (string, error) {
return "", nil
}
func openDirectory(path string) (fd int, err error) {
const O_PATH = 0x00400000
return unix.Open(path, unix.O_RDONLY|O_PATH, 0)
}
func (c *Container) addNetworkNamespace(g *generate.Generator) error {
if c.config.CreateNetNS {
g.AddAnnotation("org.freebsd.parentJail", c.state.NetworkJail)
}
return nil
}
func (c *Container) addSystemdMounts(g *generate.Generator) error {
return nil
}
func (c *Container) addSharedNamespaces(g *generate.Generator) error {
if c.config.NetNsCtr != "" {
if err := c.addNetworkContainer(g, c.config.NetNsCtr); err != nil {
return err
}
}
availableUIDs, availableGIDs, err := rootless.GetAvailableIDMaps()
if err != nil {
if os.IsNotExist(err) {
// The kernel-provided files only exist if user namespaces are supported
logrus.Debugf("User or group ID mappings not available: %s", err)
} else {
return err
}
} else {
g.Config.Linux.UIDMappings = rootless.MaybeSplitMappings(g.Config.Linux.UIDMappings, availableUIDs)
g.Config.Linux.GIDMappings = rootless.MaybeSplitMappings(g.Config.Linux.GIDMappings, availableGIDs)
}
// Hostname handling:
// If we have a UTS namespace, set Hostname in the OCI spec.
// Set the HOSTNAME environment variable unless explicitly overridden by
// the user (already present in OCI spec). If we don't have a UTS ns,
// set it to the host's hostname instead.
hostname := c.Hostname()
foundUTS := false
// TODO: make this optional, needs progress on adding FreeBSD section to the spec
foundUTS = true
g.SetHostname(hostname)
if !foundUTS {
tmpHostname, err := os.Hostname()
if err != nil {
return err
}
hostname = tmpHostname
}
needEnv := true
for _, checkEnv := range g.Config.Process.Env {
if strings.SplitN(checkEnv, "=", 2)[0] == "HOSTNAME" {
needEnv = false
break
}
}
if needEnv {
g.AddProcessEnv("HOSTNAME", hostname)
}
return nil
}
func (c *Container) addRootPropagation(g *generate.Generator, mounts []spec.Mount) error {
return nil
}
func (c *Container) setProcessLabel(g *generate.Generator) {
}
func (c *Container) setMountLabel(g *generate.Generator) {
}
func (c *Container) setCgroupsPath(g *generate.Generator) error {
return nil
}
func (c *Container) addSlirp4netnsDNS(nameservers []string) []string {
return nameservers
}
func (c *Container) isSlirp4netnsIPv6() (bool, error) {
return false, nil
}
// check for net=none
func (c *Container) hasNetNone() bool {
return c.state.NetworkJail == ""
}
func setVolumeAtime(mountPoint string, st os.FileInfo) error {
stat := st.Sys().(*syscall.Stat_t)
atime := time.Unix(int64(stat.Atimespec.Sec), int64(stat.Atimespec.Nsec)) //nolint: unconvert
if err := os.Chtimes(mountPoint, atime, st.ModTime()); err != nil {
return err
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
//go:build !linux //go:build !linux && !freebsd
// +build !linux // +build !linux,!freebsd
package libpod package libpod

View File

@ -5,6 +5,7 @@ package libpod
import ( import (
"github.com/containernetworking/plugins/pkg/ns" "github.com/containernetworking/plugins/pkg/ns"
spec "github.com/opencontainers/runtime-spec/specs-go"
) )
type containerPlatformState struct { type containerPlatformState struct {
@ -13,3 +14,17 @@ type containerPlatformState struct {
// told to join another container's network namespace // told to join another container's network namespace
NetNS ns.NetNS `json:"-"` NetNS ns.NetNS `json:"-"`
} }
func networkDisabled(c *Container) (bool, error) {
if c.config.CreateNetNS {
return false, nil
}
if !c.config.PostConfigureNetNS {
for _, ns := range c.config.Spec.Linux.Namespaces {
if ns.Type == spec.NetworkNamespace {
return ns.Path == "", nil
}
}
}
return false, nil
}

View File

@ -5,6 +5,7 @@ package libpod
import ( import (
"errors" "errors"
"net"
"path/filepath" "path/filepath"
"github.com/containers/common/libnetwork/types" "github.com/containers/common/libnetwork/types"
@ -84,3 +85,7 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
func (c *Container) convertPortMappings() []types.PortMapping { func (c *Container) convertPortMappings() []types.PortMapping {
return []types.PortMapping{} return []types.PortMapping{}
} }
func GetSlirp4netnsIP(subnet *net.IPNet) (*net.IP, error) {
return nil, errors.New("not implemented GetSlirp4netnsIP")
}

View File

@ -171,12 +171,17 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
if config == nil { if config == nil {
ctr.config.ID = stringid.GenerateNonCryptoID() ctr.config.ID = stringid.GenerateNonCryptoID()
size, err := units.FromHumanSize(r.config.Containers.ShmSize) size, err := units.FromHumanSize(r.config.Containers.ShmSize)
if err != nil { if useDevShm {
return nil, fmt.Errorf("converting containers.conf ShmSize %s to an int: %w", r.config.Containers.ShmSize, err) if err != nil {
return nil, fmt.Errorf("converting containers.conf ShmSize %s to an int: %w", r.config.Containers.ShmSize, err)
}
ctr.config.ShmSize = size
ctr.config.NoShm = false
ctr.config.NoShmShare = false
} else {
ctr.config.NoShm = true
ctr.config.NoShmShare = true
} }
ctr.config.ShmSize = size
ctr.config.NoShm = false
ctr.config.NoShmShare = false
ctr.config.StopSignal = 15 ctr.config.StopSignal = 15
ctr.config.StopTimeout = r.config.Engine.StopTimeout ctr.config.StopTimeout = r.config.Engine.StopTimeout
@ -528,7 +533,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
} }
} }
if !MountExists(ctr.config.Spec.Mounts, "/dev/shm") && ctr.config.ShmDir == "" && !ctr.config.NoShm { if useDevShm && !MountExists(ctr.config.Spec.Mounts, "/dev/shm") && ctr.config.ShmDir == "" && !ctr.config.NoShm {
ctr.config.ShmDir = filepath.Join(ctr.bundlePath(), "shm") ctr.config.ShmDir = filepath.Join(ctr.bundlePath(), "shm")
if err := os.MkdirAll(ctr.config.ShmDir, 0700); err != nil { if err := os.MkdirAll(ctr.config.ShmDir, 0700); err != nil {
if !os.IsExist(err) { if !os.IsExist(err) {

View File

@ -0,0 +1,5 @@
package libpod
const (
useDevShm = false
)

View File

@ -0,0 +1,5 @@
package libpod
const (
useDevShm = true
)

View File

@ -5,8 +5,14 @@ package util
import ( import (
"errors" "errors"
"github.com/opencontainers/runtime-tools/generate"
) )
func GetContainerPidInformationDescriptors() ([]string, error) { func GetContainerPidInformationDescriptors() ([]string, error) {
return []string{}, errors.New("this function is not supported on freebsd") return []string{}, errors.New("this function is not supported on freebsd")
} }
func AddPrivilegedDevices(g *generate.Generator) error {
return nil
}