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:
parent
60b0631abf
commit
67eec260b5
|
|
@ -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.
|
||||
|
|
@ -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")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -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")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
(
|
||||
export BINARY_SHORT_NAME='cowman'
|
||||
export SOURCE_PATH='./cowman'
|
||||
source "${MAKEDIR}/.binary"
|
||||
)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
(
|
||||
export BINARY_SHORT_NAME='graphtool'
|
||||
export SOURCE_PATH='./graphtool'
|
||||
source "${MAKEDIR}/.binary"
|
||||
)
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue