Skip to content

Commit eba9367

Browse files
authored
Merge pull request opencontainers#3373 from kolyshkin/less-interfaces
Remove Factory and LinuxFactory
2 parents 6e624d6 + 6a3fe16 commit eba9367

12 files changed

+58
-231
lines changed

init.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ func init() {
3232
logrus.SetFormatter(new(logrus.JSONFormatter))
3333
logrus.Debug("child process in init()")
3434

35-
factory, _ := libcontainer.New("")
36-
if err := factory.StartInitialization(); err != nil {
35+
if err := libcontainer.StartInitialization(); err != nil {
3736
// as the error is sent back to the parent there is no need to log
3837
// or write it to stderr because the parent process will handle this
3938
os.Exit(1)

libcontainer/README.md

+5-16
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,15 @@ func init() {
3232
if len(os.Args) > 1 && os.Args[1] == "init" {
3333
runtime.GOMAXPROCS(1)
3434
runtime.LockOSThread()
35-
factory, _ := libcontainer.New("")
36-
if err := factory.StartInitialization(); err != nil {
35+
if err := libcontainer.StartInitialization(); err != nil {
3736
logrus.Fatal(err)
3837
}
3938
panic("--this line should have never been executed, congratulations--")
4039
}
4140
}
4241
```
4342

44-
Then to create a container you first have to initialize an instance of a factory
45-
that will handle the creation and initialization for a container.
46-
47-
```go
48-
factory, err := libcontainer.New("/var/lib/container")
49-
if err != nil {
50-
logrus.Fatal(err)
51-
return
52-
}
53-
```
54-
55-
Once you have an instance of the factory created we can create a configuration
43+
Then to create a container you first have to create a configuration
5644
struct describing how the container is to be created. A sample would look similar to this:
5745

5846
```go
@@ -243,10 +231,11 @@ config := &configs.Config{
243231
}
244232
```
245233

246-
Once you have the configuration populated you can create a container:
234+
Once you have the configuration populated you can create a container
235+
with a specified ID under a specified state directory:
247236

248237
```go
249-
container, err := factory.Create("container-id", config)
238+
container, err := libcontainer.Create("/run/containers", "container-id", config)
250239
if err != nil {
251240
logrus.Fatal(err)
252241
return

libcontainer/cgroups/manager/new.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ func NewWithPaths(config *configs.Cgroup, paths map[string]string) (cgroups.Mana
5555
return fs.NewManager(config, paths)
5656
}
5757

58-
// getUnifiedPath is an implementation detail of libcontainer factory.
59-
// Historically, it saves cgroup paths as per-subsystem path map (as returned
60-
// by cm.GetPaths(""), but with v2 we only have one single unified path
61-
// (with "" as a key).
58+
// getUnifiedPath is an implementation detail of libcontainer.
59+
// Historically, libcontainer.Create saves cgroup paths as per-subsystem path
60+
// map (as returned by cm.GetPaths(""), but with v2 we only have one single
61+
// unified path (with "" as a key).
6262
//
6363
// This function converts from that map to string (using "" as a key),
6464
// and also checks that the map itself is sane.

libcontainer/factory.go

-30
This file was deleted.

libcontainer/factory_linux.go

+33-63
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"strconv"
1111

1212
securejoin "github.com/cyphar/filepath-securejoin"
13-
"github.com/moby/sys/mountinfo"
1413
"golang.org/x/sys/unix"
1514

1615
"github.com/opencontainers/runc/libcontainer/cgroups/manager"
@@ -28,60 +27,30 @@ const (
2827

2928
var idRegex = regexp.MustCompile(`^[\w+-\.]+$`)
3029

31-
// TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs.
32-
func TmpfsRoot(l *LinuxFactory) error {
33-
mounted, err := mountinfo.Mounted(l.Root)
34-
if err != nil {
35-
return err
36-
}
37-
if !mounted {
38-
if err := mount("tmpfs", l.Root, "", "tmpfs", 0, ""); err != nil {
39-
return err
40-
}
41-
}
42-
return nil
43-
}
44-
45-
// New returns a linux based container factory based in the root directory and
46-
// configures the factory with the provided option funcs.
47-
func New(root string, options ...func(*LinuxFactory) error) (Factory, error) {
48-
if root != "" {
49-
if err := os.MkdirAll(root, 0o700); err != nil {
50-
return nil, err
51-
}
52-
}
53-
l := &LinuxFactory{
54-
Root: root,
55-
}
56-
57-
for _, opt := range options {
58-
if opt == nil {
59-
continue
60-
}
61-
if err := opt(l); err != nil {
62-
return nil, err
63-
}
64-
}
65-
return l, nil
66-
}
67-
68-
// LinuxFactory implements the default factory interface for linux based systems.
69-
type LinuxFactory struct {
70-
// Root directory for the factory to store state.
71-
Root string
72-
}
73-
74-
func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) {
75-
if l.Root == "" {
30+
// Create creates a new container with the given id inside a given state
31+
// directory (root), and returns a Container object.
32+
//
33+
// The root is a state directory which many containers can share. It can be
34+
// used later to get the list of containers, or to get information about a
35+
// particular container (see Load).
36+
//
37+
// The id must not be empty and consist of only the following characters:
38+
// ASCII letters, digits, underscore, plus, minus, period. The id must be
39+
// unique and non-existent for the given root path.
40+
func Create(root, id string, config *configs.Config) (Container, error) {
41+
if root == "" {
7642
return nil, errors.New("root not set")
7743
}
78-
if err := l.validateID(id); err != nil {
44+
if err := validateID(id); err != nil {
7945
return nil, err
8046
}
8147
if err := validate.Validate(config); err != nil {
8248
return nil, err
8349
}
84-
containerRoot, err := securejoin.SecureJoin(l.Root, id)
50+
if err := os.MkdirAll(root, 0o700); err != nil {
51+
return nil, err
52+
}
53+
containerRoot, err := securejoin.SecureJoin(root, id)
8554
if err != nil {
8655
return nil, err
8756
}
@@ -125,7 +94,8 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
12594
return nil, errors.New("container's cgroup unexpectedly frozen")
12695
}
12796

128-
if err := os.MkdirAll(containerRoot, 0o711); err != nil {
97+
// Parent directory is already created above, so Mkdir is enough.
98+
if err := os.Mkdir(containerRoot, 0o711); err != nil {
12999
return nil, err
130100
}
131101
c := &linuxContainer{
@@ -139,19 +109,22 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
139109
return c, nil
140110
}
141111

142-
func (l *LinuxFactory) Load(id string) (Container, error) {
143-
if l.Root == "" {
112+
// Load takes a path to the state directory (root) and an id of an existing
113+
// container, and returns a Container object reconstructed from the saved
114+
// state. This presents a read only view of the container.
115+
func Load(root, id string) (Container, error) {
116+
if root == "" {
144117
return nil, errors.New("root not set")
145118
}
146119
// when load, we need to check id is valid or not.
147-
if err := l.validateID(id); err != nil {
120+
if err := validateID(id); err != nil {
148121
return nil, err
149122
}
150-
containerRoot, err := securejoin.SecureJoin(l.Root, id)
123+
containerRoot, err := securejoin.SecureJoin(root, id)
151124
if err != nil {
152125
return nil, err
153126
}
154-
state, err := l.loadState(containerRoot)
127+
state, err := loadState(containerRoot)
155128
if err != nil {
156129
return nil, err
157130
}
@@ -181,13 +154,10 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
181154
return c, nil
182155
}
183156

184-
func (l *LinuxFactory) Type() string {
185-
return "libcontainer"
186-
}
187-
188-
// StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state
189-
// This is a low level implementation detail of the reexec and should not be consumed externally
190-
func (l *LinuxFactory) StartInitialization() (err error) {
157+
// StartInitialization loads a container by opening the pipe fd from the parent
158+
// to read the configuration and state. This is a low level implementation
159+
// detail of the reexec and should not be consumed externally.
160+
func StartInitialization() (err error) {
191161
// Get the INITPIPE.
192162
envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE")
193163
pipefd, err := strconv.Atoi(envInitPipe)
@@ -269,7 +239,7 @@ func (l *LinuxFactory) StartInitialization() (err error) {
269239
return i.Init()
270240
}
271241

272-
func (l *LinuxFactory) loadState(root string) (*State, error) {
242+
func loadState(root string) (*State, error) {
273243
stateFilePath, err := securejoin.SecureJoin(root, stateFilename)
274244
if err != nil {
275245
return nil, err
@@ -289,7 +259,7 @@ func (l *LinuxFactory) loadState(root string) (*State, error) {
289259
return state, nil
290260
}
291261

292-
func (l *LinuxFactory) validateID(id string) error {
262+
func validateID(id string) error {
293263
if !idRegex.MatchString(id) || string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) {
294264
return ErrInvalidID
295265
}

libcontainer/factory_linux_test.go

+3-82
Original file line numberDiff line numberDiff line change
@@ -7,89 +7,14 @@ import (
77
"reflect"
88
"testing"
99

10-
"github.com/moby/sys/mountinfo"
1110
"github.com/opencontainers/runc/libcontainer/configs"
1211
"github.com/opencontainers/runc/libcontainer/utils"
1312
"github.com/opencontainers/runtime-spec/specs-go"
14-
15-
"golang.org/x/sys/unix"
1613
)
1714

18-
func TestFactoryNew(t *testing.T) {
19-
root := t.TempDir()
20-
factory, err := New(root)
21-
if err != nil {
22-
t.Fatal(err)
23-
}
24-
if factory == nil {
25-
t.Fatal("factory should not be nil")
26-
}
27-
lfactory, ok := factory.(*LinuxFactory)
28-
if !ok {
29-
t.Fatal("expected linux factory returned on linux based systems")
30-
}
31-
if lfactory.Root != root {
32-
t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root)
33-
}
34-
35-
if factory.Type() != "libcontainer" {
36-
t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer")
37-
}
38-
}
39-
40-
func TestFactoryNewTmpfs(t *testing.T) {
41-
root := t.TempDir()
42-
factory, err := New(root, TmpfsRoot)
43-
if err != nil {
44-
t.Fatal(err)
45-
}
46-
if factory == nil {
47-
t.Fatal("factory should not be nil")
48-
}
49-
lfactory, ok := factory.(*LinuxFactory)
50-
if !ok {
51-
t.Fatal("expected linux factory returned on linux based systems")
52-
}
53-
if lfactory.Root != root {
54-
t.Fatalf("expected factory root to be %q but received %q", root, lfactory.Root)
55-
}
56-
57-
if factory.Type() != "libcontainer" {
58-
t.Fatalf("unexpected factory type: %q, expected %q", factory.Type(), "libcontainer")
59-
}
60-
mounted, err := mountinfo.Mounted(lfactory.Root)
61-
if err != nil {
62-
t.Fatal(err)
63-
}
64-
if !mounted {
65-
t.Fatalf("Factory Root is not mounted")
66-
}
67-
mounts, err := mountinfo.GetMounts(mountinfo.SingleEntryFilter(lfactory.Root))
68-
if err != nil {
69-
t.Fatal(err)
70-
}
71-
if len(mounts) != 1 {
72-
t.Fatalf("Factory Root is not listed in mounts list")
73-
}
74-
m := mounts[0]
75-
if m.FSType != "tmpfs" {
76-
t.Fatalf("FSType of root: %s, expected %s", m.FSType, "tmpfs")
77-
}
78-
if m.Source != "tmpfs" {
79-
t.Fatalf("Source of root: %s, expected %s", m.Source, "tmpfs")
80-
}
81-
err = unix.Unmount(root, unix.MNT_DETACH)
82-
if err != nil {
83-
t.Error("failed to unmount root:", err)
84-
}
85-
}
86-
8715
func TestFactoryLoadNotExists(t *testing.T) {
88-
factory, err := New(t.TempDir())
89-
if err != nil {
90-
t.Fatal(err)
91-
}
92-
_, err = factory.Load("nocontainer")
16+
stateDir := t.TempDir()
17+
_, err := Load(stateDir, "nocontainer")
9318
if err == nil {
9419
t.Fatal("expected nil error loading non-existing container")
9520
}
@@ -135,11 +60,7 @@ func TestFactoryLoadContainer(t *testing.T) {
13560
if err := marshal(filepath.Join(root, id, stateFilename), expectedState); err != nil {
13661
t.Fatal(err)
13762
}
138-
factory, err := New(root)
139-
if err != nil {
140-
t.Fatal(err)
141-
}
142-
container, err := factory.Load(id)
63+
container, err := Load(root, id)
14364
if err != nil {
14465
t.Fatal(err)
14566
}

libcontainer/integration/checkpoint_test.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,9 @@ func testCheckpoint(t *testing.T, userns bool) {
6262
}
6363

6464
config := newTemplateConfig(t, &tParam{userns: userns})
65-
factory, err := libcontainer.New(t.TempDir())
66-
ok(t, err)
65+
stateDir := t.TempDir()
6766

68-
container, err := factory.Create("test", config)
67+
container, err := libcontainer.Create(stateDir, "test", config)
6968
ok(t, err)
7069
defer destroyContainer(container)
7170

@@ -143,7 +142,7 @@ func testCheckpoint(t *testing.T, userns bool) {
143142
ok(t, err)
144143

145144
// reload the container
146-
container, err = factory.Load("test")
145+
container, err = libcontainer.Load(stateDir, "test")
147146
ok(t, err)
148147

149148
restoreStdinR, restoreStdinW, err := os.Pipe()

libcontainer/integration/init_test.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,7 @@ func init() {
1919
}
2020
runtime.GOMAXPROCS(1)
2121
runtime.LockOSThread()
22-
factory, err := libcontainer.New("")
23-
if err != nil {
24-
logrus.Fatalf("unable to initialize for container: %s", err)
25-
}
26-
if err := factory.StartInitialization(); err != nil {
22+
if err := libcontainer.StartInitialization(); err != nil {
2723
logrus.Fatal(err)
2824
}
2925
}

0 commit comments

Comments
 (0)