Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 32 additions & 19 deletions libcontainer/specconv/spec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"regexp"
"strings"
"sync"
"time"

systemdDbus "github.com/coreos/go-systemd/v22/dbus"
Expand All @@ -24,26 +25,36 @@ import (
"golang.org/x/sys/unix"
)

var namespaceMapping = map[specs.LinuxNamespaceType]configs.NamespaceType{
specs.PIDNamespace: configs.NEWPID,
specs.NetworkNamespace: configs.NEWNET,
specs.MountNamespace: configs.NEWNS,
specs.UserNamespace: configs.NEWUSER,
specs.IPCNamespace: configs.NEWIPC,
specs.UTSNamespace: configs.NEWUTS,
specs.CgroupNamespace: configs.NEWCGROUP,
}
var (
initMapsOnce sync.Once
namespaceMapping map[specs.LinuxNamespaceType]configs.NamespaceType
mountPropagationMapping map[string]int
)

var mountPropagationMapping = map[string]int{
"rprivate": unix.MS_PRIVATE | unix.MS_REC,
"private": unix.MS_PRIVATE,
"rslave": unix.MS_SLAVE | unix.MS_REC,
"slave": unix.MS_SLAVE,
"rshared": unix.MS_SHARED | unix.MS_REC,
"shared": unix.MS_SHARED,
"runbindable": unix.MS_UNBINDABLE | unix.MS_REC,
"unbindable": unix.MS_UNBINDABLE,
"": 0,
func initMaps() {
initMapsOnce.Do(func() {
namespaceMapping = map[specs.LinuxNamespaceType]configs.NamespaceType{
specs.PIDNamespace: configs.NEWPID,
specs.NetworkNamespace: configs.NEWNET,
specs.MountNamespace: configs.NEWNS,
specs.UserNamespace: configs.NEWUSER,
specs.IPCNamespace: configs.NEWIPC,
specs.UTSNamespace: configs.NEWUTS,
specs.CgroupNamespace: configs.NEWCGROUP,
}

mountPropagationMapping = map[string]int{
"rprivate": unix.MS_PRIVATE | unix.MS_REC,
"private": unix.MS_PRIVATE,
"rslave": unix.MS_SLAVE | unix.MS_REC,
"slave": unix.MS_SLAVE,
"rshared": unix.MS_SHARED | unix.MS_REC,
"shared": unix.MS_SHARED,
"runbindable": unix.MS_UNBINDABLE | unix.MS_REC,
"unbindable": unix.MS_UNBINDABLE,
"": 0,
}
})
}

// AllowedDevices is the set of devices which are automatically included for
Expand Down Expand Up @@ -256,6 +267,8 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
config.Cgroups = c
// set linux-specific config
if spec.Linux != nil {
initMaps()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the improvement that's brought by this, but (as a follow-up) perhaps we should consider having utilities / accessor functions for these variables, so that the initialisation happens more 'organically' (reducing the cognitive overload of having to thing about first calling initMap() whenever we need to use one of the variables.

In this case it could be a function to check if foo exists in mountPropagationMapping

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean something like

func getNamespaceMapping() map[specs.LinuxNamespaceType]configs.NamespaceType {
    initMaps()
    return namespaceMapping
}

// ... and so on for every other map we lazy init.
....

nsMap := getNamespaceMapping()

To me it looks like a bloat, since the nsMap := getNamespaceMapping() is just a way to sugar-coat initMaps().

A runtime assertion would be nice. If only accessing a nil map would panic....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of anything better than

if namespaceMapping == nil {
   panic("uninitialied map") // we have a bug in the code
}

but it's still inferior to

initMaps()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some kind of a linter to which we can add a rule (in the source code) like "X should be called before using Y" would also be nice to have.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, a lazy way to initialize variables. IOW same as this PR does, but automatically (perhaps via an annotation).

Copy link
Contributor Author

@kolyshkin kolyshkin Nov 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone worked on something like this -- alas it does not look good without generics. https://github.com/zetamatta/go-lazy

I guess we have to postpone it till Go 2.0 ))))


var exists bool
if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists {
return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation)
Expand Down