aboutsummaryrefslogtreecommitdiff
path: root/libpod/container_commit.go
blob: e136f96a49c07a2210de10e909a1f7ad8754f39e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package libpod

import (
	"context"
	"strings"

	is "github.com/containers/image/storage"
	"github.com/pkg/errors"
	"github.com/projectatomic/libpod/libpod/buildah"
	"github.com/projectatomic/libpod/libpod/image"
	"github.com/sirupsen/logrus"
)

// ContainerCommitOptions is a struct used to commit a container to an image
// It uses buildah's CommitOptions as a base. Long-term we might wish to
// add these to the buildah struct once buildah is more integrated with
//libpod
type ContainerCommitOptions struct {
	buildah.CommitOptions
	Pause   bool
	Author  string
	Message string
	Changes []string
}

// Commit commits the changes between a container and its image, creating a new
// image
func (c *Container) Commit(ctx context.Context, destImage string, options ContainerCommitOptions) (*image.Image, error) {
	if !c.batched {
		c.lock.Lock()
		defer c.lock.Unlock()

		if err := c.syncContainer(); err != nil {
			return nil, err
		}
	}

	if c.state.State == ContainerStateRunning && options.Pause {
		if err := c.runtime.ociRuntime.pauseContainer(c); err != nil {
			return nil, errors.Wrapf(err, "error pausing container %q", c.ID())
		}
		defer func() {
			if err := c.runtime.ociRuntime.unpauseContainer(c); err != nil {
				logrus.Errorf("error unpausing container %q: %v", c.ID(), err)
			}
		}()
	}

	sc := image.GetSystemContext(options.SignaturePolicyPath, "", false)
	builderOptions := buildah.ImportOptions{
		Container:           c.ID(),
		SignaturePolicyPath: options.SignaturePolicyPath,
	}
	commitOptions := buildah.CommitOptions{
		SignaturePolicyPath: options.SignaturePolicyPath,
		ReportWriter:        options.ReportWriter,
		SystemContext:       sc,
	}
	importBuilder, err := buildah.ImportBuilder(ctx, c.runtime.store, builderOptions)
	if err != nil {
		return nil, err
	}

	if options.Author != "" {
		importBuilder.SetMaintainer(options.Author)
	}
	if options.Message != "" {
		importBuilder.SetComment(options.Message)
	}

	// Process user changes
	for _, change := range options.Changes {
		splitChange := strings.Split(change, "=")
		switch strings.ToUpper(splitChange[0]) {
		case "CMD":
			importBuilder.SetCmd(splitChange[1:])
		case "ENTRYPOINT":
			importBuilder.SetEntrypoint(splitChange[1:])
		case "ENV":
			importBuilder.SetEnv(splitChange[1], splitChange[2])
		case "EXPOSE":
			importBuilder.SetPort(splitChange[1])
		case "LABEL":
			importBuilder.SetLabel(splitChange[1], splitChange[2])
		case "STOPSIGNAL":
			// No Set StopSignal
		case "USER":
			importBuilder.SetUser(splitChange[1])
		case "VOLUME":
			importBuilder.AddVolume(splitChange[1])
		case "WORKDIR":
			importBuilder.SetWorkDir(splitChange[1])
		}
	}
	imageRef, err := is.Transport.ParseStoreReference(c.runtime.store, destImage)
	if err != nil {
		return nil, err
	}

	if err = importBuilder.Commit(ctx, imageRef, commitOptions); err != nil {
		return nil, err
	}
	return c.runtime.imageRuntime.NewFromLocal(imageRef.DockerReference().String())
}