Convert graphtool into cowman

Rename to cowman (copy-on-write manage, or something), dropping
functions beyond managing raw layers.  Since we no longer use the
dockerd layer store, just call them layers.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2016-07-07 14:34:50 -04:00
parent 60b0631abf
commit 67eec260b5
34 changed files with 373 additions and 1574 deletions

3
cmd/cowman/README.md Normal file
View File

@ -0,0 +1,3 @@
This is cowman which provides a mostly direct interface to the graph drivers,
providing ways to create, remove, mount, and unmount layers, as well as
comparing them and applying diffs to them.

47
cmd/cowman/create.go Normal file
View File

@ -0,0 +1,47 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
var (
MountLabel = ""
Name = ""
CreateRO = false
)
func create(flags *mflag.FlagSet, action string, m Mall, args []string) int {
parent := ""
if len(args) > 0 {
parent = args[0]
}
layer, err := m.Create(parent, Name, MountLabel, !CreateRO)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
if layer.Name != "" {
fmt.Printf("%s\t%s\n", layer.ID, layer.Name)
} else {
fmt.Printf("%s\n", layer.ID)
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"create"},
optionsHelp: "[options [...]] [parentLayerNameOrID]",
usage: "Create a new layer",
maxArgs: 1,
action: create,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.StringVar(&MountLabel, []string{"-label", "l"}, "", "Mount Label")
flags.StringVar(&Name, []string{"-name", "n"}, "", "Layer name")
flags.BoolVar(&CreateRO, []string{"-readonly", "r"}, false, "Mark as read-only")
},
})
}

View File

@ -7,12 +7,12 @@ import (
"github.com/docker/docker/pkg/mflag"
)
func rawDelete(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func deleteLayer(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
return 1
}
for _, what := range args {
err := m.RawDelete(what)
err := m.Delete(what)
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", what, err)
return 1
@ -23,10 +23,10 @@ func rawDelete(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func init() {
commands = append(commands, command{
names: []string{"rawdelete"},
optionsHelp: "[rawLayerNameOrID [...]]",
usage: "Delete a raw layer",
names: []string{"delete"},
optionsHelp: "[LayerNameOrID [...]]",
usage: "Delete a layer",
minArgs: 1,
action: rawDelete,
action: deleteLayer,
})
}

View File

@ -9,7 +9,7 @@ import (
"github.com/docker/docker/pkg/mflag"
)
func rawChanges(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func changes(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
return 1
}
@ -18,7 +18,7 @@ func rawChanges(flags *mflag.FlagSet, action string, m Mall, args []string) int
if len(args) >= 2 {
from = args[1]
}
changes, err := m.RawChanges(to, from)
changes, err := m.Changes(to, from)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
@ -38,7 +38,7 @@ func rawChanges(flags *mflag.FlagSet, action string, m Mall, args []string) int
return 0
}
func rawDiff(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func diff(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 2 {
return 1
}
@ -47,7 +47,7 @@ func rawDiff(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) >= 2 {
from = args[1]
}
reader, err := m.RawDiff(to, from)
reader, err := m.Diff(to, from)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
@ -60,11 +60,11 @@ func rawDiff(flags *mflag.FlagSet, action string, m Mall, args []string) int {
return 0
}
func rawApplyDiff(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func applyDiff(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
return 1
}
_, err := m.RawApplyDiff(args[0], os.Stdin)
_, err := m.ApplyDiff(args[0], os.Stdin)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
@ -72,7 +72,7 @@ func rawApplyDiff(flags *mflag.FlagSet, action string, m Mall, args []string) in
return 0
}
func rawDiffSize(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func diffSize(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
return 1
}
@ -81,7 +81,7 @@ func rawDiffSize(flags *mflag.FlagSet, action string, m Mall, args []string) int
if len(args) >= 2 {
from = args[1]
}
n, err := m.RawDiffSize(to, from)
n, err := m.DiffSize(to, from)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
@ -92,35 +92,35 @@ func rawDiffSize(flags *mflag.FlagSet, action string, m Mall, args []string) int
func init() {
commands = append(commands, command{
names: []string{"rawchanges"},
usage: "Compare two raw layers",
optionsHelp: "[options [...]] layerNameOrID [referenceRawLayerNameOrID]",
names: []string{"changes"},
usage: "Compare two layers",
optionsHelp: "[options [...]] layerNameOrID [referenceLayerNameOrID]",
minArgs: 1,
maxArgs: 2,
action: rawChanges,
action: changes,
})
commands = append(commands, command{
names: []string{"rawdiffsize"},
usage: "Compare two raw layers",
optionsHelp: "[options [...]] layerNameOrID [referenceRawLayerNameOrID]",
names: []string{"diffsize"},
usage: "Compare two layers",
optionsHelp: "[options [...]] layerNameOrID [referenceLayerNameOrID]",
minArgs: 1,
maxArgs: 2,
action: rawDiffSize,
action: diffSize,
})
commands = append(commands, command{
names: []string{"rawdiff"},
usage: "Compare two raw layers",
optionsHelp: "[options [...]] layerNameOrID [referenceRawLayerNameOrID]",
names: []string{"diff"},
usage: "Compare two layers",
optionsHelp: "[options [...]] layerNameOrID [referenceLayerNameOrID]",
minArgs: 1,
maxArgs: 2,
action: rawDiff,
action: diff,
})
commands = append(commands, command{
names: []string{"rawapplydiff"},
optionsHelp: "[options [...]] layerNameOrID [referenceRawLayerNameOrID]",
usage: "Apply a diff to a raw layer",
names: []string{"applydiff"},
optionsHelp: "[options [...]] layerNameOrID [referenceLayerNameOrID]",
usage: "Apply a diff to a layer",
minArgs: 1,
maxArgs: 1,
action: rawApplyDiff,
action: applyDiff,
})
}

View File

@ -7,13 +7,13 @@ import (
"github.com/docker/docker/pkg/mflag"
)
func rawExists(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func exist(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
return 1
}
allExist := true
for _, what := range args {
exists := m.RawExists(what)
exists := m.Exists(what)
fmt.Fprintf(os.Stderr, "%s: %v\n", what, exists)
allExist = allExist && exists
}
@ -25,10 +25,10 @@ func rawExists(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func init() {
commands = append(commands, command{
names: []string{"rawexists"},
optionsHelp: "[rawLayerNameOrID [...]]",
usage: "Check if a raw layer exists",
names: []string{"exists"},
optionsHelp: "[LayerNameOrID [...]]",
usage: "Check if a layer exists",
minArgs: 1,
action: rawExists,
action: exist,
})
}

View File

@ -7,17 +7,17 @@ import (
"github.com/docker/docker/pkg/mflag"
)
var listRawLayersTree = false
var listLayersTree = false
func rawlayers(flags *mflag.FlagSet, action string, m Mall, args []string) int {
layers, err := m.RawLayers()
func layers(flags *mflag.FlagSet, action string, m Mall, args []string) int {
layers, err := m.Layers()
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
nodes := []TreeNode{}
for _, layer := range layers {
if listRawLayersTree {
if listLayersTree {
node := TreeNode{
left: string(layer.Parent),
right: string(layer.ID),
@ -40,7 +40,7 @@ func rawlayers(flags *mflag.FlagSet, action string, m Mall, args []string) int {
}
}
}
if listRawLayersTree {
if listLayersTree {
PrintTree(nodes)
}
return 0
@ -48,13 +48,13 @@ func rawlayers(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func init() {
commands = append(commands, command{
names: []string{"rawlayers"},
names: []string{"layers"},
optionsHelp: "[options [...]]",
usage: "List raw layers",
action: rawlayers,
usage: "List layers",
action: layers,
maxArgs: 0,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&listRawLayersTree, []string{"-tree", "t"}, listRawLayersTree, "Use a tree")
flags.BoolVar(&listLayersTree, []string{"-tree", "t"}, listLayersTree, "Use a tree")
},
})
}

View File

@ -30,7 +30,7 @@ func main() {
return
}
graphRoot := "/var/lib/graphtool"
graphRoot := "/var/lib/cowman"
graphDriver := os.Getenv("DOCKER_GRAPHDRIVER")
graphOptions := strings.Split(os.Getenv("DOCKER_STORAGE_OPTS"), ",")
if len(graphOptions) == 1 && graphOptions[0] == "" {
@ -47,9 +47,9 @@ func main() {
return flags
}
flags := makeFlags("graphtool", mflag.ContinueOnError)
flags := makeFlags("cowman", mflag.ContinueOnError)
flags.Usage = func() {
fmt.Printf("Usage: graphtool command [options [...]]\n\n")
fmt.Printf("Usage: cowman command [options [...]]\n\n")
fmt.Printf("Commands:\n\n")
for _, command := range commands {
fmt.Printf(" %-14s%s\n", command.names[0], command.usage)
@ -84,7 +84,7 @@ func main() {
command.addFlags(flags, &command)
}
flags.Usage = func() {
fmt.Printf("Usage: graphtool %s %s\n\n", cmd, command.optionsHelp)
fmt.Printf("Usage: cowman %s %s\n\n", cmd, command.optionsHelp)
fmt.Printf("%s\n", command.usage)
fmt.Printf("\nOptions:\n")
flags.PrintDefaults()
@ -123,7 +123,7 @@ func main() {
os.Exit(1)
}
}
if gmutex, err := fsync.Get(filepath.Join(graphRoot, "graphtool.lock")); err != nil {
if gmutex, err := fsync.Get(filepath.Join(graphRoot, "cowman.lock")); err != nil {
fmt.Printf("error obtaining lock: %v\n", err)
os.Exit(1)
} else {

198
cmd/cowman/mall.go Normal file
View File

@ -0,0 +1,198 @@
package main
import (
"errors"
"os"
"path/filepath"
"github.com/docker/docker/daemon/graphdriver"
_ "github.com/docker/docker/daemon/graphdriver/register"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stringid"
)
var (
LoadError = errors.New("error loading storage metadata")
InvalidImageName = errors.New("invalid name for new image")
)
type Mall interface {
GetGraphDriverName() string
GetGraphDriver() (graphdriver.Driver, error)
GetLayerStore() (LayerStore, error)
Create(parent, name, mountLabel string, writeable bool) (*Layer, error)
Exists(id string) bool
Status() ([][2]string, error)
Delete(id string) error
Wipe() error
Mount(id, mountLabel string) (string, error)
Unmount(id string) error
Changes(from, to string) ([]archive.Change, error)
DiffSize(from, to string) (int64, error)
Diff(from, to string) (archive.Reader, error)
ApplyDiff(to string, diff archive.Reader) (int64, error)
Layers() ([]Layer, error)
}
type mall struct {
graphRoot string
graphDriverName string
graphOptions []string
loaded bool
graphDriver graphdriver.Driver
LayerStore LayerStore
}
func MakeMall(graphRoot, graphDriverName string, graphOptions []string) Mall {
return &mall{
graphRoot: graphRoot,
graphDriverName: graphDriverName,
graphOptions: graphOptions,
}
}
func (m *mall) GetGraphDriverName() string {
return m.graphDriverName
}
func (m *mall) load() error {
driver, err := graphdriver.New(m.graphRoot, m.graphDriverName, m.graphOptions, nil, nil)
if err != nil {
return err
}
rlpath := filepath.Join(m.graphRoot, "layers")
if err := os.MkdirAll(rlpath, 0700); err != nil {
return err
}
rls, err := newLayerStore(rlpath, driver)
if err != nil {
return err
}
m.LayerStore = rls
m.loaded = true
return nil
}
func (m *mall) GetGraphDriver() (graphdriver.Driver, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.graphDriver != nil {
return m.graphDriver, nil
}
return nil, LoadError
}
func (m *mall) GetLayerStore() (LayerStore, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.LayerStore != nil {
return m.LayerStore, nil
}
return nil, LoadError
}
func (m *mall) Create(parent, name, mountLabel string, writeable bool) (*Layer, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return nil, err
}
id := stringid.GenerateRandomID()
return rlstore.Create(id, parent, name, mountLabel, nil, writeable)
}
func (m *mall) Exists(id string) bool {
rlstore, err := m.GetLayerStore()
if err != nil {
return false
}
return rlstore.Exists(id)
}
func (m *mall) Delete(id string) error {
rlstore, err := m.GetLayerStore()
if err != nil {
return err
}
return rlstore.Delete(id)
}
func (m *mall) Wipe() error {
rlstore, err := m.GetLayerStore()
if err != nil {
return err
}
return rlstore.Wipe()
}
func (m *mall) Status() ([][2]string, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return nil, err
}
return rlstore.Status()
}
func (m *mall) Mount(id, mountLabel string) (string, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return "", err
}
return rlstore.Mount(id, mountLabel)
}
func (m *mall) Unmount(id string) error {
rlstore, err := m.GetLayerStore()
if err != nil {
return err
}
return rlstore.Unmount(id)
}
func (m *mall) Changes(from, to string) ([]archive.Change, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return nil, err
}
return rlstore.Changes(from, to)
}
func (m *mall) DiffSize(from, to string) (int64, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return -1, err
}
return rlstore.DiffSize(from, to)
}
func (m *mall) Diff(from, to string) (archive.Reader, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return nil, err
}
return rlstore.Diff(from, to)
}
func (m *mall) ApplyDiff(to string, diff archive.Reader) (int64, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return -1, err
}
return rlstore.ApplyDiff(to, diff)
}
func (m *mall) Layers() ([]Layer, error) {
rlstore, err := m.GetLayerStore()
if err != nil {
return nil, err
}
return rlstore.Layers()
}

View File

@ -9,7 +9,7 @@ import (
func mount(flags *mflag.FlagSet, action string, m Mall, args []string) int {
for _, arg := range args {
result, err := m.Mount(arg)
result, err := m.Mount(arg, MountLabel)
if err != nil {
fmt.Fprintf(os.Stderr, "%s while mounting %s\n", err, arg)
return 1
@ -32,15 +32,18 @@ func unmount(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func init() {
commands = append(commands, command{
names: []string{"mount"},
optionsHelp: "petNameOrContainerName",
usage: "Mount a read-write layer",
optionsHelp: "[options [...]] LayerNameOrID",
usage: "Mount a layer",
minArgs: 1,
action: mount,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.StringVar(&MountLabel, []string{"-label", "l"}, "", "Mount Label")
},
})
commands = append(commands, command{
names: []string{"unmount", "umount"},
optionsHelp: "petNameOrContainerName",
usage: "Unmount a read-write layer",
optionsHelp: "LayerNameOrID",
usage: "Unmount a layer",
minArgs: 1,
action: unmount,
})

View File

@ -17,7 +17,7 @@ var (
ErrLayerUnknown = errors.New("layer not known")
)
type RawLayer struct {
type Layer struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Parent string `json:"parent,omitempty"`
@ -25,18 +25,18 @@ type RawLayer struct {
MountPoint string `json:"mountpoint,omitempty"`
}
type rawLayerStore struct {
type layerStore struct {
driver graphdriver.Driver
dir string
layers []RawLayer
byid map[string]*RawLayer
byname map[string]*RawLayer
byparent map[string][]*RawLayer
bymount map[string]*RawLayer
layers []Layer
byid map[string]*Layer
byname map[string]*Layer
byparent map[string][]*Layer
bymount map[string]*Layer
}
type RawLayerStore interface {
Create(id, parent, name, lastMountPoint string, options map[string]string, writeable bool) (*RawLayer, error)
type LayerStore interface {
Create(id, parent, name, lastMountPoint string, options map[string]string, writeable bool) (*Layer, error)
Exists(id string) bool
Status() ([][2]string, error)
Delete(id string) error
@ -48,24 +48,24 @@ type RawLayerStore interface {
Diff(from, to string) (archive.Reader, error)
ApplyDiff(to string, diff archive.Reader) (int64, error)
Lookup(name string) (string, error)
Layers() ([]RawLayer, error)
Layers() ([]Layer, error)
}
func (r *rawLayerStore) Layers() ([]RawLayer, error) {
func (r *layerStore) Layers() ([]Layer, error) {
return r.layers, nil
}
func (r *rawLayerStore) Load() error {
func (r *layerStore) Load() error {
rpath := filepath.Join(r.dir, "layers.json")
data, err := ioutil.ReadFile(rpath)
if err != nil && !os.IsNotExist(err) {
return err
} else {
layers := []RawLayer{}
ids := make(map[string]*RawLayer)
names := make(map[string]*RawLayer)
mounts := make(map[string]*RawLayer)
parents := make(map[string][]*RawLayer)
layers := []Layer{}
ids := make(map[string]*Layer)
names := make(map[string]*Layer)
mounts := make(map[string]*Layer)
parents := make(map[string][]*Layer)
if err = json.Unmarshal(data, &layers); len(data) == 0 || err == nil {
for n, layer := range layers {
ids[layer.ID] = &layers[n]
@ -78,7 +78,7 @@ func (r *rawLayerStore) Load() error {
if pslice, ok := parents[layer.Parent]; ok {
parents[layer.Parent] = append(pslice, &layers[n])
} else {
parents[layer.Parent] = []*RawLayer{&layers[n]}
parents[layer.Parent] = []*Layer{&layers[n]}
}
}
}
@ -91,7 +91,7 @@ func (r *rawLayerStore) Load() error {
return nil
}
func (r *rawLayerStore) Save() error {
func (r *layerStore) Save() error {
rpath := filepath.Join(r.dir, "layers.json")
jdata, err := json.Marshal(&r.layers)
if err != nil {
@ -100,17 +100,17 @@ func (r *rawLayerStore) Save() error {
return ioutils.AtomicWriteFile(rpath, jdata, 0600)
}
func newRawLayerStore(dir string, driver graphdriver.Driver) (RawLayerStore, error) {
func newLayerStore(dir string, driver graphdriver.Driver) (LayerStore, error) {
if err := os.MkdirAll(dir, 0700); err != nil {
return nil, err
}
rlstore := rawLayerStore{
rlstore := layerStore{
driver: driver,
dir: dir,
byid: make(map[string]*RawLayer),
bymount: make(map[string]*RawLayer),
byname: make(map[string]*RawLayer),
byparent: make(map[string][]*RawLayer),
byid: make(map[string]*Layer),
bymount: make(map[string]*Layer),
byname: make(map[string]*Layer),
byparent: make(map[string][]*Layer),
}
if err := rlstore.Load(); err != nil {
return nil, err
@ -118,11 +118,11 @@ func newRawLayerStore(dir string, driver graphdriver.Driver) (RawLayerStore, err
return &rlstore, nil
}
func (r *rawLayerStore) Status() ([][2]string, error) {
func (r *layerStore) Status() ([][2]string, error) {
return r.driver.Status(), nil
}
func (r *rawLayerStore) Create(id, parent, name, mountLabel string, options map[string]string, writeable bool) (layer *RawLayer, err error) {
func (r *layerStore) Create(id, parent, name, mountLabel string, options map[string]string, writeable bool) (layer *Layer, err error) {
if layer, ok := r.byname[parent]; ok {
parent = layer.ID
}
@ -132,7 +132,7 @@ func (r *rawLayerStore) Create(id, parent, name, mountLabel string, options map[
err = r.driver.Create(id, parent, mountLabel, options)
}
if err == nil {
newLayer := RawLayer{
newLayer := Layer{
ID: id,
Parent: parent,
Name: name,
@ -148,14 +148,14 @@ func (r *rawLayerStore) Create(id, parent, name, mountLabel string, options map[
pslice = append(pslice, layer)
r.byparent[parent] = pslice
} else {
r.byparent[parent] = []*RawLayer{layer}
r.byparent[parent] = []*Layer{layer}
}
err = r.Save()
}
return layer, err
}
func (r *rawLayerStore) Mount(id, mountLabel string) (string, error) {
func (r *layerStore) Mount(id, mountLabel string) (string, error) {
if layer, ok := r.byname[id]; ok {
id = layer.ID
}
@ -178,7 +178,7 @@ func (r *rawLayerStore) Mount(id, mountLabel string) (string, error) {
return mountpoint, err
}
func (r *rawLayerStore) Unmount(id string) error {
func (r *layerStore) Unmount(id string) error {
if layer, ok := r.bymount[id]; ok {
id = layer.ID
}
@ -198,7 +198,7 @@ func (r *rawLayerStore) Unmount(id string) error {
return err
}
func (r *rawLayerStore) Delete(id string) error {
func (r *layerStore) Delete(id string) error {
if layer, ok := r.byname[id]; ok {
id = layer.ID
}
@ -207,7 +207,7 @@ func (r *rawLayerStore) Delete(id string) error {
if err == nil {
if layer, ok := r.byid[id]; ok {
pslice := r.byparent[layer.Parent]
newPslice := []*RawLayer{}
newPslice := []*Layer{}
for _, candidate := range pslice {
if candidate.ID != id {
newPslice = append(newPslice, candidate)
@ -224,7 +224,7 @@ func (r *rawLayerStore) Delete(id string) error {
if layer.MountPoint != "" {
delete(r.bymount, layer.MountPoint)
}
newLayers := []RawLayer{}
newLayers := []Layer{}
for _, candidate := range r.layers {
if candidate.ID != id {
newLayers = append(newLayers, candidate)
@ -239,7 +239,7 @@ func (r *rawLayerStore) Delete(id string) error {
return err
}
func (r *rawLayerStore) Lookup(name string) (id string, err error) {
func (r *layerStore) Lookup(name string) (id string, err error) {
layer, ok := r.byname[name]
if !ok {
return "", ErrLayerUnknown
@ -247,14 +247,14 @@ func (r *rawLayerStore) Lookup(name string) (id string, err error) {
return layer.ID, nil
}
func (r *rawLayerStore) Exists(id string) bool {
func (r *layerStore) Exists(id string) bool {
if layer, ok := r.byname[id]; ok {
id = layer.ID
}
return r.driver.Exists(id)
}
func (r *rawLayerStore) Wipe() error {
func (r *layerStore) Wipe() error {
ids := []string{}
for id, _ := range r.byid {
ids = append(ids, id)
@ -267,7 +267,7 @@ func (r *rawLayerStore) Wipe() error {
return nil
}
func (r *rawLayerStore) Changes(to, from string) ([]archive.Change, error) {
func (r *layerStore) Changes(to, from string) ([]archive.Change, error) {
if layer, ok := r.byname[from]; ok {
from = layer.ID
}
@ -285,7 +285,7 @@ func (r *rawLayerStore) Changes(to, from string) ([]archive.Change, error) {
return r.driver.Changes(to, from)
}
func (r *rawLayerStore) Diff(to, from string) (archive.Reader, error) {
func (r *layerStore) Diff(to, from string) (archive.Reader, error) {
if layer, ok := r.byname[from]; ok {
from = layer.ID
}
@ -303,7 +303,7 @@ func (r *rawLayerStore) Diff(to, from string) (archive.Reader, error) {
return r.driver.Diff(to, from)
}
func (r *rawLayerStore) DiffSize(to, from string) (size int64, err error) {
func (r *layerStore) DiffSize(to, from string) (size int64, err error) {
if layer, ok := r.byname[from]; ok {
from = layer.ID
}
@ -321,7 +321,7 @@ func (r *rawLayerStore) DiffSize(to, from string) (size int64, err error) {
return r.driver.DiffSize(to, from)
}
func (r *rawLayerStore) ApplyDiff(to string, diff archive.Reader) (size int64, err error) {
func (r *layerStore) ApplyDiff(to string, diff archive.Reader) (size int64, err error) {
if layer, ok := r.byname[to]; ok {
to = layer.ID
}

View File

@ -7,8 +7,8 @@ import (
"github.com/docker/docker/pkg/mflag"
)
func rawStatus(flags *mflag.FlagSet, action string, m Mall, args []string) int {
status, err := m.RawStatus()
func status(flags *mflag.FlagSet, action string, m Mall, args []string) int {
status, err := m.Status()
if err != nil {
fmt.Fprintf(os.Stderr, "status: %v\n", err)
return 1
@ -21,9 +21,9 @@ func rawStatus(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func init() {
commands = append(commands, command{
names: []string{"rawstatus"},
usage: "Check if a raw layer exists",
names: []string{"status"},
usage: "Check on graph driver status",
minArgs: 0,
action: rawStatus,
action: status,
})
}

View File

@ -7,8 +7,8 @@ import (
"github.com/docker/docker/pkg/mflag"
)
func rawWipe(flags *mflag.FlagSet, action string, m Mall, args []string) int {
err := m.RawWipe()
func wipe(flags *mflag.FlagSet, action string, m Mall, args []string) int {
err := m.Wipe()
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", err)
return 1
@ -18,9 +18,9 @@ func rawWipe(flags *mflag.FlagSet, action string, m Mall, args []string) int {
func init() {
commands = append(commands, command{
names: []string{"rawwipe"},
usage: "Wipe all raw layers",
names: []string{"wipe"},
usage: "Wipe all layers",
minArgs: 0,
action: rawWipe,
action: wipe,
})
}

View File

@ -1,7 +0,0 @@
This is graphtool, a tool which can handle creating, removing, mounting, and
unmounting of read-write layers for modification by the host, and which can
handle importing and exporting docker images.
For lower level cases, we also provide a more direct interface to the graph
drivers, providing ways to create, remove, mount, and unmount layers, as well
as comparing them and applying diffs to them.

View File

@ -1,41 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
func commit(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
fmt.Fprintf(os.Stderr, "No pet read-write layer name or ID specified.\n")
return 1
}
petRef := args[0]
imageName := ""
if len(args) > 1 {
imageName = args[1]
}
id, err := m.CommitPet(petRef, imageName)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
if imageName != "" {
fmt.Printf("%s\t%s\n", id, imageName)
} else {
fmt.Printf("%s\n", id)
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"commit"},
optionsHelp: "petNameOrID [imageName]",
usage: "Create a new image from a pet read-write layer",
minArgs: 1,
action: commit,
})
}

View File

@ -1,51 +0,0 @@
package main
import (
"fmt"
"os"
"strings"
"github.com/docker/docker/container"
"github.com/docker/docker/pkg/mflag"
)
var listAllContainers = false
func containerMatch(c *container.Container, id string) bool {
return id == "" || id == c.Name || "/"+id == c.Name || len(id) >= 12 && strings.HasPrefix(c.ID, id)
}
func containers(flags *mflag.FlagSet, action string, m Mall, args []string) int {
name := ""
if len(args) > 0 {
name = args[0]
}
driver := m.GetGraphDriverName()
containers, err := m.Containers()
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
for _, container := range containers {
if containerMatch(container, name) {
if listAllContainers || (container.Driver == driver) {
fmt.Printf("%s\t%s\n", container.ID, container.Name[1:])
}
}
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"containers"},
optionsHelp: "[options [...]]",
usage: "List containers",
maxArgs: 1,
action: containers,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&listAllContainers, []string{"-all", "a"}, listAllContainers, "List all containers")
},
})
}

View File

@ -1,46 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
var mountLabel = ""
func create(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
fmt.Fprintf(os.Stderr, "No image name or ID specified.\n")
return 1
}
imageRef := args[0]
petName := ""
if len(args) > 1 {
petName = args[1]
}
id, err := m.CreatePet(imageRef, petName, mountLabel)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
if petName != "" {
fmt.Printf("%s\t%s\n", id, petName)
} else {
fmt.Printf("%s\n", id)
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"create"},
optionsHelp: "imageID [name]",
usage: "Create a new pet read-write layer from an image",
minArgs: 1,
action: create,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.StringVar(&mountLabel, []string{"-label", "l"}, "", "Mount Label")
},
})
}

View File

@ -1,30 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
func deletepet(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
fmt.Fprintf(os.Stderr, "No pet filesystem specified.\n")
return 1
}
if err := m.DeletePet(args[0]); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"delete", "release"},
optionsHelp: "layerName",
usage: "Delete (release) a pet read-write layer",
minArgs: 1,
action: deletepet,
})
}

View File

@ -1,30 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
func deleteimage(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) < 1 {
fmt.Fprintf(os.Stderr, "No image name or reference specified.\n")
return 1
}
if err := m.DeleteImage(args); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"delete-image"},
optionsHelp: "imageRef",
usage: "Delete an image",
minArgs: 1,
action: deleteimage,
})
}

View File

@ -1,86 +0,0 @@
package main
import (
"fmt"
"os"
"strings"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/reference"
)
func imageMatch(i *image.Image, match string, references []reference.Named) bool {
if match == "" || match == i.ImageID() || len(match) >= 12 && strings.HasPrefix(i.ImageID(), match) {
return true
}
if match != "" {
for _, name := range references {
if strings.HasPrefix(name.FullName(), match) {
return true
}
if strings.HasPrefix(name.Name(), match) {
return true
}
}
}
return false
}
var listAllImages = false
var listImagesTree = false
func images(flags *mflag.FlagSet, action string, m Mall, args []string) int {
name := ""
if len(args) > 0 {
name = args[0]
}
images, references, err := m.Images()
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
nodes := []TreeNode{}
for _, image := range images {
if listAllImages || imageMatch(image, name, references[image]) {
if listImagesTree {
node := TreeNode{
left: string(image.Parent),
right: string(image.ID()),
notes: []string{},
}
if node.left == "" {
node.left = "(base)"
}
for _, ref := range references[image] {
node.notes = append(node.notes, fmt.Sprintf("%s", ref.String()))
}
nodes = append(nodes, node)
} else {
fmt.Printf("%s\n", image.ImageID())
for _, ref := range references[image] {
fmt.Printf("\t%s\n", ref.String())
}
}
}
}
if listImagesTree {
PrintTree(nodes)
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"images"},
optionsHelp: "[options [...]]",
usage: "List images",
maxArgs: 1,
action: images,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&listAllImages, []string{"-all", "a"}, listAllImages, "List all images")
flags.BoolVar(&listImagesTree, []string{"-tree", "t"}, listImagesTree, "Use a tree")
},
})
}

View File

@ -1,49 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
var loadVerbose = false
func load(flags *mflag.FlagSet, action string, m Mall, args []string) int {
if len(args) > 0 {
for _, arg := range args {
f, err := os.Open(arg)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
m.LoadImage(os.Stdout, !loadVerbose, f)
f.Close()
}
} else {
m.LoadImage(os.Stdout, !loadVerbose, os.Stdin)
}
return 0
}
func save(flags *mflag.FlagSet, action string, m Mall, args []string) int {
m.SaveImage(os.Stdout, args)
return 0
}
func init() {
commands = append(commands, command{
names: []string{"load"},
usage: "Load images",
action: load,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&loadVerbose, []string{"-verbose"}, loadVerbose, "Verbose progress")
},
})
commands = append(commands, command{
names: []string{"save"},
optionsHelp: "imageID [...]",
usage: "Save images",
action: save,
})
}

View File

@ -1,9 +0,0 @@
package main
import (
"github.com/Sirupsen/logrus"
)
func logImageEvent(imageID, refName, action string) {
logrus.Debugf("{action: %q, image: %q, ref: %q}", action, imageID, refName)
}

View File

@ -1,728 +0,0 @@
package main
import (
"encoding/json"
"errors"
"io"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/graphdriver"
_ "github.com/docker/docker/daemon/graphdriver/register"
"github.com/docker/docker/image"
"github.com/docker/docker/image/tarexport"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/reference"
)
var (
LoadError = errors.New("error loading storage metadata")
DuplicatePetName = errors.New("name for pet layer already in use")
InvalidImageName = errors.New("invalid name for new image")
)
type Mall interface {
GetGraphDriverName() string
GetGraphDriver() (graphdriver.Driver, error)
GetLayerStore() (layer.Store, error)
GetImageStore() (image.Store, error)
GetReferenceStore() (reference.Store, error)
GetContainerStore() (container.Store, error)
GetPetStore() (PetStore, error)
GetRawLayerStore() (RawLayerStore, error)
GetImageExporter(func(string, string, string)) (image.Exporter, error)
Images() (map[image.ID]*image.Image, map[*image.Image][]reference.Named, error)
Containers() ([]*container.Container, error)
Pets() ([]Pet, error)
LoadImage(status io.Writer, quiet bool, images ...io.ReadCloser) error
SaveImage(stream io.Writer, refs []string) error
DeleteImage(refs []string) error
CreatePet(imageRef, petName, mountLabel string) (petID string, err error)
DeletePet(nameOrID string) error
CommitPet(petRef, imageName string) (image.ID, error)
Mount(nameOrID string) (path string, err error)
Unmount(nameOrID string) error
RawCreate(parent, name, mountLabel string, writeable bool) (*RawLayer, error)
RawExists(id string) bool
RawStatus() ([][2]string, error)
RawDelete(id string) error
RawWipe() error
RawMount(id, mountLabel string) (string, error)
RawUnmount(id string) error
RawChanges(from, to string) ([]archive.Change, error)
RawDiffSize(from, to string) (int64, error)
RawDiff(from, to string) (archive.Reader, error)
RawApplyDiff(to string, diff archive.Reader) (int64, error)
RawLayers() ([]RawLayer, error)
}
type mall struct {
graphRoot string
graphDriverName string
graphOptions []string
loaded bool
graphDriver graphdriver.Driver
layerStore layer.Store
imageStore image.Store
referenceStore reference.Store
containerStore container.Store
petStore PetStore
rawLayerStore RawLayerStore
imageExporter image.Exporter
}
func MakeMall(graphRoot, graphDriverName string, graphOptions []string) Mall {
return &mall{
graphRoot: graphRoot,
graphDriverName: graphDriverName,
graphOptions: graphOptions,
}
}
func (m *mall) GetGraphDriverName() string {
return m.graphDriverName
}
func (m *mall) load() error {
driver, err := graphdriver.New(m.graphRoot, m.graphDriverName, m.graphOptions, nil, nil)
if err != nil {
return err
}
rlpath := filepath.Join(m.graphRoot, "rawlayers")
if err := os.MkdirAll(rlpath, 0700); err != nil {
return err
}
rls, err := newRawLayerStore(rlpath, driver)
if err != nil {
return err
}
m.rawLayerStore = rls
mstore, err := layer.NewFSMetadataStore(filepath.Join(m.graphRoot, "image", m.graphDriverName, "layerdb"))
if err != nil {
return err
}
ls, err := layer.NewStoreFromGraphDriver(mstore, driver)
if err != nil {
return err
}
m.layerStore = ls
ipath := filepath.Join(m.graphRoot, "image", m.graphDriverName, "imagedb")
if err := os.MkdirAll(ipath, 0700); err != nil {
return err
}
isb, err := image.NewFSStoreBackend(ipath)
if err != nil {
return err
}
is, err := image.NewImageStore(isb, ls)
if err != nil {
return err
}
m.imageStore = is
rpath := filepath.Join(m.graphRoot, "image", m.graphDriverName, "repositories.json")
rs, err := reference.NewReferenceStore(rpath)
if err != nil {
return err
}
m.referenceStore = rs
cpath := filepath.Join(m.graphRoot, "containers")
if err := os.MkdirAll(cpath, 0700); err != nil {
return err
}
ids, err := ioutil.ReadDir(cpath)
if err != nil {
return err
}
cs := container.NewMemoryStore()
for _, file := range ids {
path := filepath.Join(cpath, file.Name())
c := container.NewBaseContainer(file.Name(), path)
err = c.FromDisk()
if err != nil {
return err
}
cs.Add(c.ID, c)
}
m.containerStore = cs
ppath := filepath.Join(m.graphRoot, "pets")
if err := os.MkdirAll(ppath, 0700); err != nil {
return err
}
ps, err := newPetStore(ppath, ls)
if err != nil {
return err
}
m.petStore = ps
iexporter := tarexport.NewTarExporter(is, ls, rs, &imageEventLogger{log: logImageEvent})
m.imageExporter = iexporter
m.loaded = true
return nil
}
func (m *mall) GetGraphDriver() (graphdriver.Driver, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.graphDriver != nil {
return m.graphDriver, nil
}
return nil, LoadError
}
func (m *mall) GetRawLayerStore() (RawLayerStore, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.rawLayerStore != nil {
return m.rawLayerStore, nil
}
return nil, LoadError
}
func (m *mall) GetLayerStore() (layer.Store, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.layerStore != nil {
return m.layerStore, nil
}
return nil, LoadError
}
func (m *mall) GetReferenceStore() (reference.Store, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.referenceStore != nil {
return m.referenceStore, nil
}
return nil, LoadError
}
func (m *mall) GetImageStore() (image.Store, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.imageStore != nil {
return m.imageStore, nil
}
return nil, LoadError
}
func (m *mall) GetContainerStore() (container.Store, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.containerStore != nil {
return m.containerStore, nil
}
return nil, LoadError
}
type imageEventLogger struct {
log func(imageID, refName, action string)
}
func (i *imageEventLogger) LogImageEvent(imageID, refName, action string) {
if i.log != nil {
i.log(imageID, refName, action)
}
}
func (m *mall) GetImageExporter(logImageEvent func(imageID, refName, action string)) (image.Exporter, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.imageExporter != nil {
return m.imageExporter, nil
}
return nil, LoadError
}
func (m *mall) GetPetStore() (PetStore, error) {
if !m.loaded {
if err := m.load(); err != nil {
return nil, err
}
}
if m.petStore != nil {
return m.petStore, nil
}
return nil, LoadError
}
func (m *mall) Containers() ([]*container.Container, error) {
cstore, err := m.GetContainerStore()
if err != nil {
return nil, err
}
return cstore.List(), nil
}
func (m *mall) Images() (map[image.ID]*image.Image, map[*image.Image][]reference.Named, error) {
istore, err := m.GetImageStore()
if err != nil {
return nil, nil, err
}
rstore, err := m.GetReferenceStore()
if err != nil {
return nil, nil, err
}
images := istore.Map()
refs := make(map[*image.Image][]reference.Named)
for id, image := range images {
refs[image] = rstore.References(id)
}
return images, refs, nil
}
func (m *mall) Pets() ([]Pet, error) {
pstore, err := m.GetPetStore()
if err != nil {
return nil, err
}
return pstore.List()
}
func (m *mall) LoadImage(status io.Writer, quiet bool, images ...io.ReadCloser) error {
e, err := m.GetImageExporter(logImageEvent)
if err != nil {
return err
}
for _, image := range images {
if err == nil {
err = e.Load(image, status, quiet)
}
image.Close()
}
return err
}
func (m *mall) SaveImage(stream io.Writer, refs []string) error {
e, err := m.GetImageExporter(logImageEvent)
if err != nil {
return err
}
return e.Save(refs, stream)
}
func (m *mall) resolveImage(imageRef string) (imageID image.ID, layerID layer.ChainID, imageName string, err error) {
var img *image.Image
istore, err := m.GetImageStore()
if err != nil {
return "", "", "", err
}
imageid, ref, err := reference.ParseIDOrReference(imageRef)
if err != nil {
logrus.Debugf("Error parsing ID or reference %q: %v", imageRef, err)
roid, err := digest.ParseDigest(imageRef)
if err != nil {
logrus.Debugf("Error parsing %q as digest: %v", imageRef, err)
return "", "", "", err
}
imageID = image.ID(roid)
logrus.Debugf("Resolved %q to ID %q.", imageRef, imageID)
img, err = istore.Get(imageID)
if err != nil {
return "", "", "", err
}
} else {
rstore, err := m.GetReferenceStore()
if err != nil {
return "", "", "", err
}
roid, err := digest.ParseDigest(imageid.String())
if err != nil {
associations := rstore.ReferencesByName(ref)
if len(associations) == 0 {
logrus.Debugf("No image with name %q.", ref.String())
} else {
logrus.Debugf("Resolved %q to name %q.", imageRef, ref)
for _, association := range associations {
logrus.Debugf("Attempting to use ID %q.", association.ImageID)
img, err = istore.Get(association.ImageID)
if err == nil {
imageName = association.Ref.FullName()
break
}
logrus.Debugf("No image with ID %s", association.ImageID)
}
}
} else {
logrus.Debugf("Resolved %q to ID %q.", imageRef, roid)
img, err = istore.Get(image.ID(roid))
}
if err != nil {
return "", "", "", err
}
}
if img == nil {
logrus.Debugf("No image matched %s", imageRef)
return "", "", "", reference.ErrDoesNotExist
}
rootfs := img.RootFS
if rootfs.Type != "layers" {
logrus.Debugf("Don't know how to deal with rootfs type %q, only layers.", rootfs.Type)
return "", "", "", layer.ErrNotSupported
}
if len(rootfs.DiffIDs) == 0 {
logrus.Debugf("No layers in this image, trying anyway.")
}
layerID = rootfs.ChainID()
imageID = img.ID()
return imageID, layerID, imageName, nil
}
func (m *mall) DeleteImage(refs []string) error {
istore, err := m.GetImageStore()
if err != nil {
return err
}
rstore, err := m.GetReferenceStore()
if err != nil {
return err
}
for _, ref := range refs {
imageID, _, _, err := m.resolveImage(ref)
if err != nil {
return err
}
metadata, err := istore.Delete(imageID)
if err != nil {
return err
}
layer.LogReleaseMetadata(metadata)
for _, ref := range rstore.References(imageID) {
deleted, err := rstore.Delete(ref)
if err != nil {
return err
}
if !deleted {
logrus.Errorf("Unable to remove reference %q to %s.", ref, imageID.String())
} else {
logrus.Debugf("Removed reference %q to %s.", ref, imageID.String())
}
}
}
return nil
}
func (m *mall) CreatePet(imageRef, petName, mountLabel string) (petID string, err error) {
lstore, err := m.GetLayerStore()
if err != nil {
return "", err
}
pstore, err := m.GetPetStore()
if err != nil {
return "", err
}
if petName != "" {
if _, err := pstore.Get(petName); err == nil {
return "", DuplicatePetName
}
}
imageID, layerID, imageName, err := m.resolveImage(imageRef)
if err != nil {
return "", err
}
rwlayerID := stringid.GenerateRandomID()
options := make(map[string]string)
rwlayer, err := lstore.CreateRWLayer(rwlayerID, layerID, mountLabel, nil, options)
if err != nil {
logrus.Debugf("Error creating new layer from %q: %v.", layerID, err)
return "", err
}
petID = stringid.GenerateRandomID()
pet, err := pstore.Add(petID, petName, imageID.String(), imageName, rwlayer, mountLabel)
if err != nil {
logrus.Debugf("Error registering new pet layer: %v.", err)
return "", err
}
return pet.ID(), nil
}
func (m *mall) DeletePet(nameOrID string) error {
pstore, err := m.GetPetStore()
if err != nil {
return err
}
p, err := pstore.Get(nameOrID)
if err != nil {
return err
}
err = pstore.Remove(p.ID(), p.Name())
if err != nil {
return err
}
return nil
}
func (m *mall) getRWLayer(nameOrID string) (layer layer.RWLayer, mountLabel string, err error) {
pstore, err := m.GetPetStore()
if err != nil {
return nil, "", err
}
cstore, err := m.GetContainerStore()
if err != nil {
return nil, "", err
}
layerStore, err := m.GetLayerStore()
if err != nil {
return nil, "", err
}
pets, err := pstore.List()
if err != nil {
return nil, "", err
}
for _, pet := range pets {
if petMatch(pet, nameOrID) {
return pet.Layer(), pet.MountLabel(), nil
}
}
for _, container := range cstore.List() {
if containerMatch(container, nameOrID) {
layer, err = layerStore.GetRWLayer(container.ID)
if err != nil {
return nil, "", err
}
return layer, container.GetMountLabel(), nil
}
}
layer, err = layerStore.GetRWLayer(nameOrID)
if err != nil {
return nil, "", err
}
if layer == nil {
return nil, "", noMatchingContainerError
}
return layer, "", nil
}
func (m *mall) CommitPet(petRef, imageName string) (id image.ID, err error) {
lstore, err := m.GetLayerStore()
if err != nil {
return "", err
}
istore, err := m.GetImageStore()
if err != nil {
return "", err
}
rstore, err := m.GetReferenceStore()
if err != nil {
return "", err
}
pstore, err := m.GetPetStore()
if err != nil {
return "", err
}
pet, err := pstore.Get(petRef)
if err != nil {
return "", err
}
imageID, _, _, err := m.resolveImage(pet.ImageID())
if err != nil {
return "", err
}
img, err := istore.Get(imageID)
if err != nil {
return "", err
}
tarstream, err := pet.Layer().TarStream()
if err != nil {
return "", err
}
rootfs := img.RootFS
history := image.History{
Created: time.Now(),
}
rolayer, err := lstore.Register(tarstream, rootfs.ChainID())
if err != nil {
return "", err
}
if diffID := rolayer.DiffID(); diffID != layer.DigestSHA256EmptyTar {
rootfs.Append(diffID)
history.EmptyLayer = false
}
newImage := &image.Image{
Parent: img.ID(),
RootFS: rootfs,
}
newImage.Created = time.Now()
newImage.Container = pet.ID()
newImage.Architecture = img.Architecture
newImage.OSVersion = img.OSVersion
newImage.OSFeatures = img.OSFeatures
newImage.History = append(img.History, history)
config, err := json.Marshal(newImage)
if err != nil {
return "", err
}
newImageID, err := istore.Create(config)
if err != nil {
return "", err
}
err = istore.SetParent(newImageID, img.ID())
if err != nil {
return "", err
}
if imageName != "" {
_, ref, err := reference.ParseIDOrReference(imageName)
if err != nil {
return newImageID, err
}
if ref == nil {
return newImageID, InvalidImageName
}
err = rstore.AddTag(ref, newImageID, true)
if err != nil {
return newImageID, err
}
}
return newImageID, nil
}
func (m *mall) Mount(nameOrID string) (path string, err error) {
layer, label, err := m.getRWLayer(nameOrID)
if err != nil {
return "", err
}
return layer.Mount(label)
}
func (m *mall) Unmount(nameOrID string) error {
layer, _, err := m.getRWLayer(nameOrID)
if err != nil {
return err
}
return layer.Unmount()
}
func (m *mall) RawCreate(parent, name, mountLabel string, writeable bool) (*RawLayer, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return nil, err
}
id := stringid.GenerateRandomID()
return rlstore.Create(id, parent, name, mountLabel, nil, writeable)
}
func (m *mall) RawExists(id string) bool {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return false
}
return rlstore.Exists(id)
}
func (m *mall) RawDelete(id string) error {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return err
}
return rlstore.Delete(id)
}
func (m *mall) RawWipe() error {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return err
}
return rlstore.Wipe()
}
func (m *mall) RawStatus() ([][2]string, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return nil, err
}
return rlstore.Status()
}
func (m *mall) RawMount(id, mountLabel string) (string, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return "", err
}
return rlstore.Mount(id, mountLabel)
}
func (m *mall) RawUnmount(id string) error {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return err
}
return rlstore.Unmount(id)
}
func (m *mall) RawChanges(from, to string) ([]archive.Change, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return nil, err
}
return rlstore.Changes(from, to)
}
func (m *mall) RawDiffSize(from, to string) (int64, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return -1, err
}
return rlstore.DiffSize(from, to)
}
func (m *mall) RawDiff(from, to string) (archive.Reader, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return nil, err
}
return rlstore.Diff(from, to)
}
func (m *mall) RawApplyDiff(to string, diff archive.Reader) (int64, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return -1, err
}
return rlstore.ApplyDiff(to, diff)
}
func (m *mall) RawLayers() ([]RawLayer, error) {
rlstore, err := m.GetRawLayerStore()
if err != nil {
return nil, err
}
return rlstore.Layers()
}

View File

@ -1,51 +0,0 @@
package main
import (
"fmt"
"os"
"strings"
"github.com/docker/docker/pkg/mflag"
)
var listAllPets = false
func petMatch(p Pet, id string) bool {
return id == "" || id == p.Name() || len(id) >= 12 && strings.HasPrefix(p.ID(), id)
}
func pets(flags *mflag.FlagSet, action string, m Mall, args []string) int {
name := ""
if len(args) > 0 {
name = args[0]
}
pets, err := m.Pets()
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
for _, pet := range pets {
if petMatch(pet, name) || listAllPets {
if pet.Name() != "" {
fmt.Printf("%s\t%s\n", pet.ID(), pet.Name())
} else {
fmt.Printf("%s\n", pet.ID())
}
}
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"pets"},
usage: "List pets",
optionsHelp: "[options [...]]",
maxArgs: 1,
action: pets,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&listAllPets, []string{"-all", "a"}, listAllPets, "List all pets")
},
})
}

View File

@ -1,227 +0,0 @@
package main
import (
"encoding/json"
"errors"
"io/ioutil"
"os"
"path/filepath"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/ioutils"
)
var (
NoSuchPetError = errors.New("no such pet found")
NoLayerNameError = errors.New("pet has no layer")
)
type pet struct {
petFile string
PetID string `json:"id"`
PetName string `json:"name,omitempty"`
PetMountLabel string `json:"mountlabel,omitempty"`
PetImageID string `json:"imageid"`
PetImageName string `json:"imagename,omitempty"`
PetLayerName string `json:"layer"`
petLayer layer.RWLayer
}
type Pet interface {
ID() string
ImageID() string
Name() string
MountLabel() string
Layer() layer.RWLayer
}
type petStore struct {
dir string
ls layer.Store
byid map[string]*pet
byname map[string]*pet
}
type PetStore interface {
Add(ID, name, imageID, imageName string, layer layer.RWLayer, mountLabel string) (Pet, error)
Remove(ID, name string) error
Get(IDorName string) (Pet, error)
Load() error
Save() error
List() ([]Pet, error)
}
func (p *petStore) loadPet(path string) (*pet, error) {
tmp := &pet{}
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
err = json.NewDecoder(file).Decode(tmp)
if err != nil {
return nil, err
}
if tmp.PetLayerName == "" {
return nil, NoLayerNameError
}
tmp.petLayer, err = p.ls.GetRWLayer(tmp.PetLayerName)
if err != nil {
return nil, err
}
tmp.petFile = path
if err != nil {
return nil, err
}
return tmp, nil
}
func (p *petStore) savePet(pet *pet) error {
f, err := ioutils.NewAtomicFileWriter(pet.petFile, 0600)
if err != nil {
return err
}
defer f.Close()
return json.NewEncoder(f).Encode(*pet)
}
func (p *pet) ID() string {
return p.PetID
}
func (p *pet) Name() string {
return p.PetName
}
func (p *pet) ImageID() string {
return p.PetImageID
}
func (p *pet) ImageName() string {
return p.PetImageName
}
func (p *pet) MountLabel() string {
return p.PetMountLabel
}
func (p *pet) Layer() layer.RWLayer {
return p.petLayer
}
func (p *petStore) Load() error {
ids, err := ioutil.ReadDir(p.dir)
if err != nil {
return err
}
unseen := map[string]string{}
for id, _ := range p.byid {
unseen[id] = id
}
for _, file := range ids {
path := filepath.Join(p.dir, file.Name())
pet, err := p.loadPet(path)
if err != nil {
return err
}
p.byid[pet.PetID] = pet
if pet.PetName != "" {
p.byname[pet.PetName] = pet
}
delete(unseen, pet.PetID)
}
for id, _ := range unseen {
p.Remove(id, "")
}
return nil
}
func (p *petStore) Save() error {
for _, pet := range p.byid {
err := p.savePet(pet)
if err != nil {
return err
}
}
return nil
}
func (p *petStore) Add(ID, name, imageID, imageName string, layer layer.RWLayer, mountLabel string) (Pet, error) {
path := filepath.Join(p.dir, ID)
pet := pet{
petFile: path,
PetID: ID,
PetName: name,
PetImageID: imageID,
PetImageName: imageName,
PetLayerName: layer.Name(),
petLayer: layer,
PetMountLabel: mountLabel,
}
err := p.savePet(&pet)
if err != nil {
return nil, err
}
p.byid[pet.PetID] = &pet
if pet.PetName != "" {
p.byname[pet.PetName] = &pet
}
return &pet, err
}
func (p *petStore) Remove(ID, name string) error {
var pet *pet
if ID != "" {
pet = p.byid[ID]
}
if pet == nil && name != "" {
pet = p.byname[name]
}
if pet == nil {
return NoSuchPetError
}
metadata, err := p.ls.ReleaseRWLayer(pet.petLayer)
if err != nil {
return err
}
layer.LogReleaseMetadata(metadata)
err = os.Remove(pet.petFile)
if err != nil {
return err
}
delete(p.byid, pet.PetID)
if pet.Name() != "" {
delete(p.byname, pet.PetName)
}
return nil
}
func (p *petStore) Get(IDorName string) (Pet, error) {
pet, ok := p.byid[IDorName]
if !ok {
pet = p.byname[IDorName]
}
if pet != nil {
return pet, nil
}
return nil, NoSuchPetError
}
func (p *petStore) List() ([]Pet, error) {
pets := []Pet{}
for _, pet := range p.byid {
pets = append(pets, pet)
}
return pets, nil
}
func newPetStore(dir string, ls layer.Store) (PetStore, error) {
if err := os.MkdirAll(dir, 0700); err != nil {
return nil, err
}
p := petStore{dir: dir, ls: ls, byid: make(map[string]*pet), byname: make(map[string]*pet)}
if err := p.Load(); err != nil {
return nil, err
}
return &p, nil
}

View File

@ -1,47 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
var (
rawMountLabel = ""
rawName = ""
rawCreateRO = false
)
func rawCreate(flags *mflag.FlagSet, action string, m Mall, args []string) int {
parent := ""
if len(args) > 0 {
parent = args[0]
}
layer, err := m.RawCreate(parent, rawName, rawMountLabel, !rawCreateRO)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return 1
}
if layer.Name != "" {
fmt.Printf("%s\t%s\n", layer.ID, layer.Name)
} else {
fmt.Printf("%s\n", layer.ID)
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"rawcreate"},
optionsHelp: "[options [...]] [parentRawLayerNameOrID]",
usage: "Create a new raw layer",
maxArgs: 1,
action: rawCreate,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.StringVar(&rawMountLabel, []string{"-label", "l"}, "", "Mount Label")
flags.StringVar(&rawName, []string{"-name", "n"}, "", "Layer name")
flags.StringVar(&rawName, []string{"-readonly", "r"}, "", "Mark as read-only")
},
})
}

View File

@ -1,50 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/docker/docker/pkg/mflag"
)
func rawMount(flags *mflag.FlagSet, action string, m Mall, args []string) int {
for _, arg := range args {
result, err := m.RawMount(arg, rawMountLabel)
if err != nil {
fmt.Fprintf(os.Stderr, "%s while mounting %s\n", err, arg)
return 1
}
fmt.Printf("%s\n", result)
}
return 0
}
func rawUnmount(flags *mflag.FlagSet, action string, m Mall, args []string) int {
for _, arg := range args {
if err := m.RawUnmount(arg); err != nil {
fmt.Fprintf(os.Stderr, "%s while unmounting %s\n", err, arg)
return 1
}
}
return 0
}
func init() {
commands = append(commands, command{
names: []string{"rawmount"},
optionsHelp: "[options [...]] rawLayerNameOrID",
usage: "Mount a raw layer",
minArgs: 1,
action: rawMount,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.StringVar(&rawMountLabel, []string{"-label", "l"}, "", "Mount Label")
},
})
commands = append(commands, command{
names: []string{"rawunmount", "rawumount"},
optionsHelp: "rawLayerNameOrID",
usage: "Unmount a raw layer",
minArgs: 1,
action: rawUnmount,
})
}

View File

@ -14,7 +14,7 @@ rm -rf "$DEST"
. hack/make/binary-daemon
)
(
DEST="${DEST}-graphtool"
ABS_DEST="${ABS_DEST}-graphtool"
. hack/make/binary-graphtool
DEST="${DEST}-cowman"
ABS_DEST="${ABS_DEST}-cowman"
. hack/make/binary-cowman
)

8
hack/make/binary-cowman Normal file
View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e
(
export BINARY_SHORT_NAME='cowman'
export SOURCE_PATH='./cowman'
source "${MAKEDIR}/.binary"
)

View File

@ -1,8 +0,0 @@
#!/bin/bash
set -e
(
export BINARY_SHORT_NAME='graphtool'
export SOURCE_PATH='./graphtool'
source "${MAKEDIR}/.binary"
)

View File

@ -13,7 +13,7 @@ set -e
. hack/make/dynbinary-daemon
)
(
DEST="${DEST}-graphtool"
ABS_DEST="${ABS_DEST}-graphtool"
. hack/make/dynbinary-graphtool
DEST="${DEST}-cowman"
ABS_DEST="${ABS_DEST}-cowman"
. hack/make/dynbinary-cowman
)

View File

@ -2,8 +2,8 @@
set -e
(
export BINARY_SHORT_NAME='graphtool'
export SOURCE_PATH='./cmd/graphtool'
export BINARY_SHORT_NAME='cowman'
export SOURCE_PATH='./cmd/cowman'
export IAMSTATIC='false'
export LDFLAGS_STATIC_DOCKER=''
export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary