Merge pull request #434 from AkihiroSuda/terminology

snapshot: fix terminology inconsistency
This commit is contained in:
Stephen Day 2017-01-19 19:33:34 -08:00 committed by GitHub
commit 7101c7a9e2
9 changed files with 102 additions and 98 deletions

View file

@ -21,7 +21,7 @@ minimal API simplifies behavior without sacrificing power. This makes the
surface area for driver implementations smaller, ensuring that behavior is more
consistent between implementations.
These differ from the concept of the graphdriver in that the LayerManipulator
These differ from the concept of the graphdriver in that the _Snapshot Manager_
has no knowledge of images or containers. Users simply prepare and commit
directories. We also avoid the integration between graph drivers and the tar
format used to represent the changesets.
@ -125,8 +125,8 @@ Per the terminology above, `tmpLocation` is known as the `target`. `layerPath`
is simply a tar file, representing a changset. We start by using
`SnapshotManager` to prepare the temporary location as a snapshot point:
lm := SnapshotManager()
mounts, err := lm.Prepare(tmpLocation, "")
sm := SnapshotManager()
mounts, err := sm.Prepare(tmpLocation, "")
if err != nil { ... }
Note that we provide "" as the `parent`, since we are applying the diff to an
@ -142,6 +142,8 @@ that applies the contents of the layer to target location and calculates the
DiffID of the unpacked layer (this is a requirement for docker
implementation):
layer, err := os.Open(layerPath)
if err != nil { ... }
digest, err := unpackLayer(tmpLocation, layer) // unpack into layer location
if err != nil { ... }
@ -156,7 +158,7 @@ the actual diff. For this example, we are just going to use the layer `digest`,
but in practice, this will probably be the `ChainID`:
diffPath := filepath.Join("/layers", digest) // name location for the uncompressed layer digest
if err := lm.Commit(diffPath, tmpLocation); err != nil { ... }
if err := sm.Commit(diffPath, tmpLocation); err != nil { ... }
The new layer has been imported as a _snapshot_ into the `SnapshotManager`
under the name `diffPath`. `diffPath`, which is a user opaque directory
@ -166,9 +168,9 @@ location, can then be used as a parent in later snapshots.
Making a layer depend on the above is identical to the process described
above except that the parent is provided as diffPath when calling
`Snapshot.Prepare`:
`SnapshotManager.Prepare`:
mounts, err := lm.Prepare(tmpLocation, parentDiffPath)
mounts, err := sm.Prepare(tmpLocation, parentDiffPath)
Because have a provided a `parent`, the resulting `tmpLocation`, after
mounting, will have the changes from above. Any new changes will be isolated to
@ -182,13 +184,13 @@ To run a container, we simply provide `SnapshotManager.Prepare` the `diff` of
the image we want to start the container from. After mounting, the prepared
path can be used directly as the container's filesystem:
mounts, err := lm.Prepare(containerRootFS, imageDiffPath)
mounts, err := sm.Prepare(containerRootFS, imageDiffPath)
The returned mounts can then be passed directly to the container runtime. If
one would like to create a new image from the filesystem,
SnapshotManipulator.Commit is called:
`SnapshotManager.Commit` is called:
if err := lm.Commit(newImageDiff, containerRootFS); err != nil { ... }
if err := sm.Commit(newImageDiff, containerRootFS); err != nil { ... }
Alternatively, for most container runs, Snapshot.Rollback will be
Alternatively, for most container runs, `SnapshotManager.Rollback` will be
called to signal `SnapshotManager` to abandon the changes.

View file

@ -19,8 +19,8 @@ func NewBtrfs(device, root string) (*Btrfs, error) {
return &Btrfs{device: device, root: root}, nil
}
func (lm *Btrfs) Prepare(key, parent string) ([]containerd.Mount, error) {
active := filepath.Join(lm.root, "active")
func (b *Btrfs) Prepare(key, parent string) ([]containerd.Mount, error) {
active := filepath.Join(b.root, "active")
if err := os.MkdirAll(active, 0755); err != nil {
return nil, err
}
@ -49,7 +49,7 @@ func (lm *Btrfs) Prepare(key, parent string) ([]containerd.Mount, error) {
return []containerd.Mount{
{
Type: "btrfs",
Source: lm.device, // device?
Source: b.device, // device?
// NOTE(stevvooe): While it would be nice to use to uuids for
// mounts, they don't work reliably if the uuids are missing.
Options: []string{fmt.Sprintf("subvolid=%d", info.ID)},
@ -57,8 +57,8 @@ func (lm *Btrfs) Prepare(key, parent string) ([]containerd.Mount, error) {
}, nil
}
func (lm *Btrfs) Commit(name, key string) error {
dir := filepath.Join(lm.root, "active", hash(key))
func (b *Btrfs) Commit(name, key string) error {
dir := filepath.Join(b.root, "active", hash(key))
fmt.Println("commit to", name)
if err := btrfs.SubvolSnapshot(name, dir, true); err != nil {

View file

@ -28,11 +28,11 @@ func TestBtrfs(t *testing.T) {
defer os.RemoveAll(root)
target := filepath.Join(root, "test")
sm, err := NewBtrfs(device.deviceName, root)
b, err := NewBtrfs(device.deviceName, root)
if err != nil {
t.Fatal(err)
}
mounts, err := sm.Prepare(target, "")
mounts, err := b.Prepare(target, "")
if err != nil {
t.Fatal(err)
}
@ -68,7 +68,7 @@ func TestBtrfs(t *testing.T) {
t.Fatal(err)
}
if err := sm.Commit(filepath.Join(root, "snapshots/committed"), filepath.Join(root, "test")); err != nil {
if err := b.Commit(filepath.Join(root, "snapshots/committed"), filepath.Join(root, "test")); err != nil {
t.Fatal(err)
}
defer func() {
@ -80,7 +80,7 @@ func TestBtrfs(t *testing.T) {
}()
target = filepath.Join(root, "test2")
mounts, err = sm.Prepare(target, filepath.Join(root, "snapshots/committed"))
mounts, err = b.Prepare(target, filepath.Join(root, "snapshots/committed"))
if err != nil {
t.Fatal(err)
}
@ -99,7 +99,7 @@ func TestBtrfs(t *testing.T) {
t.Fatal(err)
}
if err := sm.Commit(filepath.Join(root, "snapshots/committed2"), target); err != nil {
if err := b.Commit(filepath.Join(root, "snapshots/committed2"), target); err != nil {
t.Fatal(err)
}
defer func() {

View file

@ -31,8 +31,8 @@ import (
// We then use a Manager to prepare the temporary location as a
// snapshot point:
//
// lm := NewManager()
// mounts, err := lm.Prepare(tmpLocation, "")
// sm := NewManager()
// mounts, err := sm.Prepare(tmpLocation, "")
// if err != nil { ... }
//
// Note that we provide "" as the parent, since we are applying the diff to an
@ -48,6 +48,8 @@ import (
// DiffID of the unpacked layer (this is a requirement for docker
// implementation):
//
// layer, err := os.Open(layerPath)
// if err != nil { ... }
// digest, err := unpackLayer(tmpLocation, layer) // unpack into layer location
// if err != nil { ... }
//
@ -62,7 +64,7 @@ import (
// digest, but in practice, this will probably be the ChainID:
//
// diffPath := filepath.Join("/layers", digest) // name location for the uncompressed layer digest
// if err := lm.Commit(diffPath, tmpLocation); err != nil { ... }
// if err := sm.Commit(diffPath, tmpLocation); err != nil { ... }
//
// Now, we have a layer in the Manager that can be accessed with the
// opaque diffPath provided during commit.
@ -73,7 +75,7 @@ import (
// above except that the parent is provided as diffPath when calling
// Manager.Prepare:
//
// mounts, err := lm.Prepare(tmpLocation, parentDiffPath)
// mounts, err := sm.Prepare(tmpLocation, parentDiffPath)
//
// The diff will be captured at tmpLocation, as the layer is applied.
//
@ -83,13 +85,13 @@ import (
// of the image we want to start the container from. After mounting, the
// prepared path can be used directly as the container's filesystem:
//
// mounts, err := lm.Prepare(containerRootFS, imageDiffPath)
// mounts, err := sm.Prepare(containerRootFS, imageDiffPath)
//
// The returned mounts can then be passed directly to the container runtime. If
// one would like to create a new image from the filesystem,
// Manager.Commit is called:
//
// if err := lm.Commit(newImageDiff, containerRootFS); err != nil { ... }
// if err := sm.Commit(newImageDiff, containerRootFS); err != nil { ... }
//
// Alternatively, for most container runs, Manager.Rollback will be
// called to signal Manager to abandon the changes.
@ -97,7 +99,7 @@ import (
// TODO(stevvooe): Consider an alternate API that provides an active object to
// represent the lifecycle:
//
// work, err := lm.Prepare(dst, parent)
// work, err := sm.Prepare(dst, parent)
// mountAll(work.Mounts())
// work.Commit() || work.Rollback()
//
@ -144,7 +146,7 @@ func NewManager(root string) (*Manager, error) {
//
// Once the writes have completed, Manager.Commit or
// Manager.Rollback should be called on dst.
func (lm *Manager) Prepare(dst, parent string) ([]containerd.Mount, error) {
func (sm *Manager) Prepare(dst, parent string) ([]containerd.Mount, error) {
// we want to build up lowerdir, upperdir and workdir options for the
// overlay mount.
//
@ -157,25 +159,25 @@ func (lm *Manager) Prepare(dst, parent string) ([]containerd.Mount, error) {
// workdir needs to be there but it is not really clear why.
var opts []string
upperdir, err := ioutil.TempDir(lm.root, "diff-")
upperdir, err := ioutil.TempDir(sm.root, "diff-")
if err != nil {
return nil, err
}
opts = append(opts, "upperdir="+upperdir)
workdir, err := ioutil.TempDir(lm.root, "work-")
workdir, err := ioutil.TempDir(sm.root, "work-")
if err != nil {
return nil, err
}
opts = append(opts, "workdir="+workdir)
empty := filepath.Join(lm.root, "empty")
empty := filepath.Join(sm.root, "empty")
if err := os.MkdirAll(empty, 0777); err != nil {
return nil, err
}
// TODO(stevvooe): Write this metadata to disk to make it useful.
lm.active[dst] = activeLayer{
sm.active[dst] = activeLayer{
parent: parent,
upperdir: upperdir,
workdir: workdir,
@ -184,7 +186,7 @@ func (lm *Manager) Prepare(dst, parent string) ([]containerd.Mount, error) {
var parents []string
for parent != "" {
parents = append(parents, parent)
parent = lm.Parent(parent)
parent = sm.Parent(parent)
}
if len(parents) == 0 {
@ -210,18 +212,18 @@ func (lm *Manager) Prepare(dst, parent string) ([]containerd.Mount, error) {
//
// Calling Commit on dst will result in an error. Calling Rollback on dst
// should be done to cleanup resources.
func (lm *Manager) View(dst, parent string) ([]containerd.Mount, error) {
func (sm *Manager) View(dst, parent string) ([]containerd.Mount, error) {
panic("not implemented")
}
// Commit captures the changes between dst and its parent into the path
// provided by diff. The path diff can then be used with the layer
// manipulator's other methods to access the diff content.
// provided by diff. The path diff can then be used with the snapshot
// manager's other methods to access the diff content.
//
// The contents of diff are opaque to the caller and may be specific to the
// implementation of the layer backend.
func (lm *Manager) Commit(diff, dst string) error {
active, ok := lm.active[dst]
func (sm *Manager) Commit(diff, dst string) error {
active, ok := sm.active[dst]
if !ok {
return fmt.Errorf("%q must be an active layer", dst)
}
@ -237,8 +239,8 @@ func (lm *Manager) Commit(diff, dst string) error {
return err
}
lm.parents[diff] = active.parent
delete(lm.active, dst) // remove from active, again, consider not doing this to support multiple commits.
sm.parents[diff] = active.parent
delete(sm.active, dst) // remove from active, again, consider not doing this to support multiple commits.
// note that allowing multiple commits would require copy for overlay.
return nil
@ -246,8 +248,8 @@ func (lm *Manager) Commit(diff, dst string) error {
// Rollback can be called after prepare if the caller would like to abandon the
// changeset.
func (lm *Manager) Rollback(dst string) error {
active, ok := lm.active[dst]
func (sm *Manager) Rollback(dst string) error {
active, ok := sm.active[dst]
if !ok {
return fmt.Errorf("%q must be an active layer", dst)
}
@ -256,13 +258,13 @@ func (lm *Manager) Rollback(dst string) error {
err = os.RemoveAll(active.upperdir)
err = os.RemoveAll(active.workdir)
delete(lm.active, dst)
delete(sm.active, dst)
return err
}
// Parent returns the parent of the layer at diff.
func (lm *Manager) Parent(diff string) string {
return lm.parents[diff]
func (sm *Manager) Parent(diff string) string {
return sm.parents[diff]
}
type ChangeKind int
@ -301,6 +303,6 @@ type Change struct {
// see this patten used in several tar'ing methods in pkg/archive.
// Changes returns the list of changes from the diff's parent.
func (lm *Manager) Changes(diff string) ([]Change, error) {
func (sm *Manager) Changes(diff string) ([]Change, error) {
panic("not implemented")
}

View file

@ -14,7 +14,7 @@ import (
// examples we've discussed thus far. It does perform mounts, so you must run
// as root.
func TestSnapshotManagerBasic(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "test-layman-")
tmpDir, err := ioutil.TempDir("", "test-sm-")
if err != nil {
t.Fatal(err)
}
@ -28,7 +28,7 @@ func TestSnapshotManagerBasic(t *testing.T) {
root := filepath.Join(tmpDir, "root")
lm, err := NewManager(root)
sm, err := NewManager(root)
if err != nil {
t.Fatal(err)
}
@ -38,7 +38,7 @@ func TestSnapshotManagerBasic(t *testing.T) {
t.Fatal(err)
}
mounts, err := lm.Prepare(preparing, "")
mounts, err := sm.Prepare(preparing, "")
if err != nil {
t.Fatal(err)
}
@ -58,14 +58,14 @@ func TestSnapshotManagerBasic(t *testing.T) {
os.MkdirAll(preparing+"/a/b/c", 0755)
committed := filepath.Join(lm.root, "committed")
committed := filepath.Join(sm.root, "committed")
if err := lm.Commit(committed, preparing); err != nil {
if err := sm.Commit(committed, preparing); err != nil {
t.Fatal(err)
}
if lm.Parent(preparing) != "" {
t.Fatalf("parent of new layer should be empty, got lm.Parent(%q) == %q", preparing, lm.Parent(preparing))
if sm.Parent(preparing) != "" {
t.Fatalf("parent of new layer should be empty, got sm.Parent(%q) == %q", preparing, sm.Parent(preparing))
}
next := filepath.Join(tmpDir, "nextlayer")
@ -73,7 +73,7 @@ func TestSnapshotManagerBasic(t *testing.T) {
t.Fatal(err)
}
mounts, err = lm.Prepare(next, committed)
mounts, err = sm.Prepare(next, committed)
if err != nil {
t.Fatal(err)
}
@ -92,12 +92,12 @@ func TestSnapshotManagerBasic(t *testing.T) {
}
os.RemoveAll(next + "/a/b")
nextCommitted := filepath.Join(lm.root, "committed-next")
if err := lm.Commit(nextCommitted, next); err != nil {
nextCommitted := filepath.Join(sm.root, "committed-next")
if err := sm.Commit(nextCommitted, next); err != nil {
t.Fatal(err)
}
if lm.Parent(nextCommitted) != committed {
t.Fatalf("parent of new layer should be %q, got lm.Parent(%q) == %q (%#v)", committed, next, lm.Parent(next), lm.parents)
if sm.Parent(nextCommitted) != committed {
t.Fatalf("parent of new layer should be %q, got sm.Parent(%q) == %q (%#v)", committed, next, sm.Parent(next), sm.parents)
}
}

View file

@ -43,8 +43,8 @@ func NewNaive(root string) (*Naive, error) {
//
// For the naive driver, the data is checked out directly into dst and no
// mounts are returned.
func (lm *Naive) Prepare(dst, parent string) ([]containerd.Mount, error) {
metadataRoot, err := ioutil.TempDir(lm.root, "active-")
func (n *Naive) Prepare(dst, parent string) ([]containerd.Mount, error) {
metadataRoot, err := ioutil.TempDir(n.root, "active-")
if err != nil {
return nil, errors.Wrap(err, "failed to created transaction dir")
}
@ -57,7 +57,7 @@ func (lm *Naive) Prepare(dst, parent string) ([]containerd.Mount, error) {
}
if parent != "" {
if _, ok := lm.parents[parent]; !ok {
if _, ok := n.parents[parent]; !ok {
return nil, errors.Wrap(err, "specified parent does not exist")
}
@ -71,7 +71,7 @@ func (lm *Naive) Prepare(dst, parent string) ([]containerd.Mount, error) {
}
}
lm.active[dst] = activeNaiveSnapshot{
n.active[dst] = activeNaiveSnapshot{
parent: parent,
metadata: metadataRoot,
}
@ -80,8 +80,8 @@ func (lm *Naive) Prepare(dst, parent string) ([]containerd.Mount, error) {
}
// Commit just moves the metadata directory to the diff location.
func (lm *Naive) Commit(diff, dst string) error {
active, ok := lm.active[dst]
func (n *Naive) Commit(diff, dst string) error {
active, ok := n.active[dst]
if !ok {
return errors.Errorf("%v is not an active transaction", dst)
}
@ -96,22 +96,22 @@ func (lm *Naive) Commit(diff, dst string) error {
return errors.Wrap(err, "failed to rename metadata into diff")
}
lm.parents[diff] = active.parent
delete(lm.active, dst)
n.parents[diff] = active.parent
delete(n.active, dst)
return nil
}
func (lm *Naive) Rollback(dst string) error {
active, ok := lm.active[dst]
func (n *Naive) Rollback(dst string) error {
active, ok := n.active[dst]
if !ok {
return fmt.Errorf("%q must be an active snapshot", dst)
}
delete(lm.active, dst)
delete(n.active, dst)
return os.RemoveAll(active.metadata)
}
func (lm *Naive) Parent(diff string) string {
return lm.parents[diff]
func (n *Naive) Parent(diff string) string {
return n.parents[diff]
}

View file

@ -10,7 +10,7 @@ import (
)
func TestSnapshotNaiveBasic(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "test-layman-")
tmpDir, err := ioutil.TempDir("", "test-naive-")
if err != nil {
t.Fatal(err)
}
@ -19,7 +19,7 @@ func TestSnapshotNaiveBasic(t *testing.T) {
t.Log(tmpDir)
root := filepath.Join(tmpDir, "root")
lm, err := NewNaive(root)
n, err := NewNaive(root)
if err != nil {
t.Fatal(err)
}
@ -29,7 +29,7 @@ func TestSnapshotNaiveBasic(t *testing.T) {
t.Fatal(err)
}
mounts, err := lm.Prepare(preparing, "")
mounts, err := n.Prepare(preparing, "")
if err != nil {
t.Fatal(err)
}
@ -46,14 +46,14 @@ func TestSnapshotNaiveBasic(t *testing.T) {
// defer os.Remove(filepath.Join(tmpDir, "foo"))
committed := filepath.Join(lm.root, "committed")
committed := filepath.Join(n.root, "committed")
if err := lm.Commit(committed, preparing); err != nil {
if err := n.Commit(committed, preparing); err != nil {
t.Fatal(err)
}
if lm.Parent(preparing) != "" {
t.Fatalf("parent of new layer should be empty, got lm.Parent(%q) == %q", preparing, lm.Parent(preparing))
if n.Parent(preparing) != "" {
t.Fatalf("parent of new layer should be empty, got n.Parent(%q) == %q", preparing, n.Parent(preparing))
}
next := filepath.Join(tmpDir, "nextlayer")
@ -61,7 +61,7 @@ func TestSnapshotNaiveBasic(t *testing.T) {
t.Fatal(err)
}
mounts, err = lm.Prepare(next, committed)
mounts, err = n.Prepare(next, committed)
if err != nil {
t.Fatal(err)
}
@ -79,12 +79,12 @@ func TestSnapshotNaiveBasic(t *testing.T) {
}
os.RemoveAll(next + "/a/b")
nextCommitted := filepath.Join(lm.root, "committed-next")
if err := lm.Commit(nextCommitted, next); err != nil {
nextCommitted := filepath.Join(n.root, "committed-next")
if err := n.Commit(nextCommitted, next); err != nil {
t.Fatal(err)
}
if lm.Parent(nextCommitted) != committed {
t.Fatalf("parent of new layer should be %q, got lm.Parent(%q) == %q (%#v)", committed, next, lm.Parent(next), lm.parents)
if n.Parent(nextCommitted) != committed {
t.Fatalf("parent of new layer should be %q, got n.Parent(%q) == %q (%#v)", committed, next, n.Parent(next), n.parents)
}
}

View file

@ -12,7 +12,7 @@ import (
"github.com/docker/containerd"
)
func NewOverlayfs(root string) (*Overlayfs, error) {
func NewOverlay(root string) (*Overlay, error) {
if err := os.MkdirAll(root, 0700); err != nil {
return nil, err
}
@ -24,18 +24,18 @@ func NewOverlayfs(root string) (*Overlayfs, error) {
return nil, err
}
}
return &Overlayfs{
return &Overlay{
root: root,
cache: newCache(),
}, nil
}
type Overlayfs struct {
type Overlay struct {
root string
cache *cache
}
func (o *Overlayfs) Prepare(key string, parentName string) ([]containerd.Mount, error) {
func (o *Overlay) Prepare(key string, parentName string) ([]containerd.Mount, error) {
if err := validKey(key); err != nil {
return nil, err
}
@ -51,12 +51,12 @@ func (o *Overlayfs) Prepare(key string, parentName string) ([]containerd.Mount,
return active.mounts(o.cache)
}
func (o *Overlayfs) Commit(name, key string) error {
func (o *Overlay) Commit(name, key string) error {
active := o.getActive(key)
return active.commit(name)
}
func (o *Overlayfs) newActiveDir(key string) (*activeDir, error) {
func (o *Overlay) newActiveDir(key string) (*activeDir, error) {
var (
hash = hash(key)
path = filepath.Join(o.root, "active", hash)
@ -77,7 +77,7 @@ func (o *Overlayfs) newActiveDir(key string) (*activeDir, error) {
return a, nil
}
func (o *Overlayfs) getActive(key string) *activeDir {
func (o *Overlay) getActive(key string) *activeDir {
return &activeDir{
path: filepath.Join(o.root, "active", hash(key)),
snapshotsDir: filepath.Join(o.root, "snapshots"),

View file

@ -10,13 +10,13 @@ import (
"github.com/docker/containerd"
)
func TestOverlayfs(t *testing.T) {
func TestOverlay(t *testing.T) {
root, err := ioutil.TempDir("", "overlay")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
o, err := NewOverlayfs(root)
o, err := NewOverlay(root)
if err != nil {
t.Error(err)
return
@ -45,13 +45,13 @@ func TestOverlayfs(t *testing.T) {
}
}
func TestOverlayfsCommit(t *testing.T) {
func TestOverlayCommit(t *testing.T) {
root, err := ioutil.TempDir("", "overlay")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
o, err := NewOverlayfs(root)
o, err := NewOverlay(root)
if err != nil {
t.Error(err)
return
@ -73,13 +73,13 @@ func TestOverlayfsCommit(t *testing.T) {
}
}
func TestOverlayfsOverlayMount(t *testing.T) {
func TestOverlayOverlayMount(t *testing.T) {
root, err := ioutil.TempDir("", "overlay")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
o, err := NewOverlayfs(root)
o, err := NewOverlay(root)
if err != nil {
t.Error(err)
return
@ -125,7 +125,7 @@ func TestOverlayfsOverlayMount(t *testing.T) {
}
}
func TestOverlayfsOverlayRead(t *testing.T) {
func TestOverlayOverlayRead(t *testing.T) {
if os.Getuid() != 0 {
t.Skip("not running as root")
}
@ -134,7 +134,7 @@ func TestOverlayfsOverlayRead(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll(root)
o, err := NewOverlayfs(root)
o, err := NewOverlay(root)
if err != nil {
t.Error(err)
return