mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Fixing Image struct to no longer use Graph.
Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
parent
46cbfcb168
commit
9001ea26e7
20 changed files with 104 additions and 88 deletions
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/docker/docker/cliconfig"
|
"github.com/docker/docker/cliconfig"
|
||||||
"github.com/docker/docker/daemon"
|
"github.com/docker/docker/daemon"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/chrootarchive"
|
"github.com/docker/docker/pkg/chrootarchive"
|
||||||
"github.com/docker/docker/pkg/httputils"
|
"github.com/docker/docker/pkg/httputils"
|
||||||
|
@ -486,7 +487,7 @@ func ContainsWildcards(name string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) pullImage(name string) (*graph.Image, error) {
|
func (b *Builder) pullImage(name string) (*image.Image, error) {
|
||||||
remote, tag := parsers.ParseRepositoryTag(name)
|
remote, tag := parsers.ParseRepositoryTag(name)
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = "latest"
|
tag = "latest"
|
||||||
|
@ -524,7 +525,7 @@ func (b *Builder) pullImage(name string) (*graph.Image, error) {
|
||||||
return image, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) processImageFrom(img *graph.Image) error {
|
func (b *Builder) processImageFrom(img *image.Image) error {
|
||||||
b.image = img.ID
|
b.image = img.ID
|
||||||
|
|
||||||
if img.Config != nil {
|
if img.Config != nil {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ type ContainerCommitConfig struct {
|
||||||
|
|
||||||
// Commit creates a new filesystem image from the current state of a container.
|
// Commit creates a new filesystem image from the current state of a container.
|
||||||
// The image can optionally be tagged into a repository
|
// The image can optionally be tagged into a repository
|
||||||
func (daemon *Daemon) Commit(container *Container, c *ContainerCommitConfig) (*graph.Image, error) {
|
func (daemon *Daemon) Commit(container *Container, c *ContainerCommitConfig) (*image.Image, error) {
|
||||||
if c.Pause && !container.IsPaused() {
|
if c.Pause && !container.IsPaused() {
|
||||||
container.Pause()
|
container.Pause()
|
||||||
defer container.Unpause()
|
defer container.Unpause()
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"github.com/docker/docker/daemon/logger"
|
"github.com/docker/docker/daemon/logger"
|
||||||
"github.com/docker/docker/daemon/logger/jsonfilelog"
|
"github.com/docker/docker/daemon/logger/jsonfilelog"
|
||||||
"github.com/docker/docker/daemon/network"
|
"github.com/docker/docker/daemon/network"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/broadcastwriter"
|
"github.com/docker/docker/pkg/broadcastwriter"
|
||||||
"github.com/docker/docker/pkg/fileutils"
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
|
@ -584,7 +584,7 @@ func (container *Container) Changes() ([]archive.Change, error) {
|
||||||
return container.changes()
|
return container.changes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) GetImage() (*graph.Image, error) {
|
func (container *Container) GetImage() (*image.Image, error) {
|
||||||
if container.daemon == nil {
|
if container.daemon == nil {
|
||||||
return nil, fmt.Errorf("Can't get image of unregistered container")
|
return nil, fmt.Errorf("Can't get image of unregistered container")
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/docker/docker/daemon/graphdriver/windows"
|
"github.com/docker/docker/daemon/graphdriver/windows"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/microsoft/hcsshim"
|
"github.com/microsoft/hcsshim"
|
||||||
)
|
)
|
||||||
|
@ -114,7 +114,7 @@ func populateCommand(c *Container, env []string) error {
|
||||||
// enable VFS to continue operating for development purposes.
|
// enable VFS to continue operating for development purposes.
|
||||||
if wd, ok := c.daemon.driver.(*windows.WindowsGraphDriver); ok {
|
if wd, ok := c.daemon.driver.(*windows.WindowsGraphDriver); ok {
|
||||||
var err error
|
var err error
|
||||||
var img *graph.Image
|
var img *image.Image
|
||||||
var ids []string
|
var ids []string
|
||||||
|
|
||||||
if img, err = c.daemon.graph.Get(c.ImageID); err != nil {
|
if img, err = c.daemon.graph.Get(c.ImageID); err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
|
@ -46,7 +47,7 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
|
||||||
var (
|
var (
|
||||||
container *Container
|
container *Container
|
||||||
warnings []string
|
warnings []string
|
||||||
img *graph.Image
|
img *image.Image
|
||||||
imgID string
|
imgID string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/docker/docker/daemon/logger"
|
"github.com/docker/docker/daemon/logger"
|
||||||
"github.com/docker/docker/daemon/network"
|
"github.com/docker/docker/daemon/network"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/broadcastwriter"
|
"github.com/docker/docker/pkg/broadcastwriter"
|
||||||
"github.com/docker/docker/pkg/fileutils"
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
"github.com/docker/docker/pkg/graphdb"
|
"github.com/docker/docker/pkg/graphdb"
|
||||||
|
@ -336,7 +337,7 @@ func (daemon *Daemon) restore() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *graph.Image) error {
|
func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) error {
|
||||||
if img != nil && img.Config != nil {
|
if img != nil && img.Config != nil {
|
||||||
if err := runconfig.Merge(config, img.Config); err != nil {
|
if err := runconfig.Merge(config, img.Config); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -882,7 +883,7 @@ func (daemon *Daemon) ContainerGraph() *graphdb.Database {
|
||||||
return daemon.containerGraph
|
return daemon.containerGraph
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*graph.Image, error) {
|
func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) {
|
||||||
// Retrieve all images
|
// Retrieve all images
|
||||||
images := daemon.Graph().Map()
|
images := daemon.Graph().Map()
|
||||||
|
|
||||||
|
@ -896,7 +897,7 @@ func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*g
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop on the children of the given image and check the config
|
// Loop on the children of the given image and check the config
|
||||||
var match *graph.Image
|
var match *image.Image
|
||||||
for elem := range imageMap[imgID] {
|
for elem := range imageMap[imgID] {
|
||||||
img, ok := images[elem]
|
img, ok := images[elem]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
|
@ -159,7 +160,7 @@ func (daemon *Daemon) canDeleteImage(imgID string, force bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := daemon.graph.WalkHistory(parent, func(p graph.Image) error {
|
if err := daemon.graph.WalkHistory(parent, func(p image.Image) error {
|
||||||
if imgID == p.ID {
|
if imgID == p.ID {
|
||||||
if container.IsRunning() {
|
if container.IsRunning() {
|
||||||
if force {
|
if force {
|
||||||
|
|
|
@ -82,22 +82,6 @@ type Graph struct {
|
||||||
retained *retainedLayers
|
retained *retainedLayers
|
||||||
}
|
}
|
||||||
|
|
||||||
type Image struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Parent string `json:"parent,omitempty"`
|
|
||||||
Comment string `json:"comment,omitempty"`
|
|
||||||
Created time.Time `json:"created"`
|
|
||||||
Container string `json:"container,omitempty"`
|
|
||||||
ContainerConfig runconfig.Config `json:"container_config,omitempty"`
|
|
||||||
DockerVersion string `json:"docker_version,omitempty"`
|
|
||||||
Author string `json:"author,omitempty"`
|
|
||||||
Config *runconfig.Config `json:"config,omitempty"`
|
|
||||||
Architecture string `json:"architecture,omitempty"`
|
|
||||||
OS string `json:"os,omitempty"`
|
|
||||||
Size int64
|
|
||||||
graph Graph
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrDigestNotSet is used when request the digest for a layer
|
// ErrDigestNotSet is used when request the digest for a layer
|
||||||
// but the layer has no digest value or content to compute the
|
// but the layer has no digest value or content to compute the
|
||||||
|
@ -174,7 +158,7 @@ func (graph *Graph) Exists(id string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the image with the given id, or an error if the image doesn't exist.
|
// Get returns the image with the given id, or an error if the image doesn't exist.
|
||||||
func (graph *Graph) Get(name string) (*Image, error) {
|
func (graph *Graph) Get(name string) (*image.Image, error) {
|
||||||
id, err := graph.idIndex.Get(name)
|
id, err := graph.idIndex.Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not find image: %v", err)
|
return nil, fmt.Errorf("could not find image: %v", err)
|
||||||
|
@ -202,8 +186,8 @@ func (graph *Graph) Get(name string) (*Image, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new image and registers it in the graph.
|
// Create creates a new image and registers it in the graph.
|
||||||
func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*Image, error) {
|
func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*image.Image, error) {
|
||||||
img := &Image{
|
img := &image.Image{
|
||||||
ID: stringid.GenerateRandomID(),
|
ID: stringid.GenerateRandomID(),
|
||||||
Comment: comment,
|
Comment: comment,
|
||||||
Created: time.Now().UTC(),
|
Created: time.Now().UTC(),
|
||||||
|
@ -227,7 +211,7 @@ func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, contain
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register imports a pre-existing image into the graph.
|
// Register imports a pre-existing image into the graph.
|
||||||
func (graph *Graph) Register(img *Image, layerData archive.ArchiveReader) (err error) {
|
func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader) (err error) {
|
||||||
|
|
||||||
if err := image.ValidateID(img.ID); err != nil {
|
if err := image.ValidateID(img.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -380,9 +364,9 @@ func (graph *Graph) Delete(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map returns a list of all images in the graph, addressable by ID.
|
// Map returns a list of all images in the graph, addressable by ID.
|
||||||
func (graph *Graph) Map() map[string]*Image {
|
func (graph *Graph) Map() map[string]*image.Image {
|
||||||
images := make(map[string]*Image)
|
images := make(map[string]*image.Image)
|
||||||
graph.walkAll(func(image *Image) {
|
graph.walkAll(func(image *image.Image) {
|
||||||
images[image.ID] = image
|
images[image.ID] = image
|
||||||
})
|
})
|
||||||
return images
|
return images
|
||||||
|
@ -390,7 +374,7 @@ func (graph *Graph) Map() map[string]*Image {
|
||||||
|
|
||||||
// walkAll iterates over each image in the graph, and passes it to a handler.
|
// walkAll iterates over each image in the graph, and passes it to a handler.
|
||||||
// The walking order is undetermined.
|
// The walking order is undetermined.
|
||||||
func (graph *Graph) walkAll(handler func(*Image)) {
|
func (graph *Graph) walkAll(handler func(*image.Image)) {
|
||||||
graph.idIndex.Iterate(func(id string) {
|
graph.idIndex.Iterate(func(id string) {
|
||||||
if img, err := graph.Get(id); err != nil {
|
if img, err := graph.Get(id); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -404,9 +388,9 @@ func (graph *Graph) walkAll(handler func(*Image)) {
|
||||||
// If an image of id ID has 3 children images, then the value for key ID
|
// If an image of id ID has 3 children images, then the value for key ID
|
||||||
// will be a list of 3 images.
|
// will be a list of 3 images.
|
||||||
// If an image has no children, it will not have an entry in the table.
|
// If an image has no children, it will not have an entry in the table.
|
||||||
func (graph *Graph) ByParent() map[string][]*Image {
|
func (graph *Graph) ByParent() map[string][]*image.Image {
|
||||||
byParent := make(map[string][]*Image)
|
byParent := make(map[string][]*image.Image)
|
||||||
graph.walkAll(func(img *Image) {
|
graph.walkAll(func(img *image.Image) {
|
||||||
parent, err := graph.Get(img.Parent)
|
parent, err := graph.Get(img.Parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -414,7 +398,7 @@ func (graph *Graph) ByParent() map[string][]*Image {
|
||||||
if children, exists := byParent[parent.ID]; exists {
|
if children, exists := byParent[parent.ID]; exists {
|
||||||
byParent[parent.ID] = append(children, img)
|
byParent[parent.ID] = append(children, img)
|
||||||
} else {
|
} else {
|
||||||
byParent[parent.ID] = []*Image{img}
|
byParent[parent.ID] = []*image.Image{img}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return byParent
|
return byParent
|
||||||
|
@ -433,10 +417,10 @@ func (graph *Graph) Release(sessionID string, layerIDs ...string) {
|
||||||
|
|
||||||
// Heads returns all heads in the graph, keyed by id.
|
// Heads returns all heads in the graph, keyed by id.
|
||||||
// A head is an image which is not the parent of another image in the graph.
|
// A head is an image which is not the parent of another image in the graph.
|
||||||
func (graph *Graph) Heads() map[string]*Image {
|
func (graph *Graph) Heads() map[string]*image.Image {
|
||||||
heads := make(map[string]*Image)
|
heads := make(map[string]*image.Image)
|
||||||
byParent := graph.ByParent()
|
byParent := graph.ByParent()
|
||||||
graph.walkAll(func(image *Image) {
|
graph.walkAll(func(image *image.Image) {
|
||||||
// If it's not in the byParent lookup table, then
|
// If it's not in the byParent lookup table, then
|
||||||
// it's not a parent -> so it's a head!
|
// it's not a parent -> so it's a head!
|
||||||
if _, exists := byParent[image.ID]; !exists {
|
if _, exists := byParent[image.ID]; !exists {
|
||||||
|
@ -451,7 +435,7 @@ func (graph *Graph) imageRoot(id string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadImage fetches the image with the given id from the graph.
|
// loadImage fetches the image with the given id from the graph.
|
||||||
func (graph *Graph) loadImage(id string) (*Image, error) {
|
func (graph *Graph) loadImage(id string) (*image.Image, error) {
|
||||||
root := graph.imageRoot(id)
|
root := graph.imageRoot(id)
|
||||||
|
|
||||||
// Open the JSON file to decode by streaming
|
// Open the JSON file to decode by streaming
|
||||||
|
@ -461,7 +445,7 @@ func (graph *Graph) loadImage(id string) (*Image, error) {
|
||||||
}
|
}
|
||||||
defer jsonSource.Close()
|
defer jsonSource.Close()
|
||||||
|
|
||||||
img := &Image{}
|
img := &image.Image{}
|
||||||
dec := json.NewDecoder(jsonSource)
|
dec := json.NewDecoder(jsonSource)
|
||||||
|
|
||||||
// Decode the JSON data
|
// Decode the JSON data
|
||||||
|
@ -538,14 +522,3 @@ func (graph *Graph) RawJSON(id string) ([]byte, error) {
|
||||||
func jsonPath(root string) string {
|
func jsonPath(root string) string {
|
||||||
return filepath.Join(root, "json")
|
return filepath.Join(root, "json")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build an Image object from raw json data
|
|
||||||
func NewImgJSON(src []byte) (*Image, error) {
|
|
||||||
ret := &Image{}
|
|
||||||
|
|
||||||
// FIXME: Is there a cleaner way to "purify" the input json?
|
|
||||||
if err := json.Unmarshal(src, ret); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ func TestInterruptedRegister(t *testing.T) {
|
||||||
graph, _ := tempGraph(t)
|
graph, _ := tempGraph(t)
|
||||||
defer nukeGraph(graph)
|
defer nukeGraph(graph)
|
||||||
badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data
|
badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data
|
||||||
image := &Image{
|
image := &image.Image{
|
||||||
ID: stringid.GenerateRandomID(),
|
ID: stringid.GenerateRandomID(),
|
||||||
Comment: "testing",
|
Comment: "testing",
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
|
@ -125,7 +125,7 @@ func TestRegister(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
image := &Image{
|
image := &image.Image{
|
||||||
ID: stringid.GenerateRandomID(),
|
ID: stringid.GenerateRandomID(),
|
||||||
Comment: "testing",
|
Comment: "testing",
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
|
@ -228,19 +228,19 @@ func TestByParent(t *testing.T) {
|
||||||
|
|
||||||
graph, _ := tempGraph(t)
|
graph, _ := tempGraph(t)
|
||||||
defer nukeGraph(graph)
|
defer nukeGraph(graph)
|
||||||
parentImage := &Image{
|
parentImage := &image.Image{
|
||||||
ID: stringid.GenerateRandomID(),
|
ID: stringid.GenerateRandomID(),
|
||||||
Comment: "parent",
|
Comment: "parent",
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
Parent: "",
|
Parent: "",
|
||||||
}
|
}
|
||||||
childImage1 := &Image{
|
childImage1 := &image.Image{
|
||||||
ID: stringid.GenerateRandomID(),
|
ID: stringid.GenerateRandomID(),
|
||||||
Comment: "child1",
|
Comment: "child1",
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
Parent: parentImage.ID,
|
Parent: parentImage.ID,
|
||||||
}
|
}
|
||||||
childImage2 := &Image{
|
childImage2 := &image.Image{
|
||||||
ID: stringid.GenerateRandomID(),
|
ID: stringid.GenerateRandomID(),
|
||||||
Comment: "child2",
|
Comment: "child2",
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
|
@ -257,7 +257,7 @@ func TestByParent(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestImage(graph *Graph, t *testing.T) *Image {
|
func createTestImage(graph *Graph, t *testing.T) *image.Image {
|
||||||
archive, err := fakeTar()
|
archive, err := fakeTar()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
)
|
)
|
||||||
|
@ -72,7 +73,7 @@ func SetupInitLayer(initLayer string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRootFilesystemInDriver(graph *Graph, img *Image, layerData archive.ArchiveReader) error {
|
func createRootFilesystemInDriver(graph *Graph, img *image.Image, layerData archive.ArchiveReader) error {
|
||||||
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
||||||
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
||||||
}
|
}
|
||||||
|
@ -86,7 +87,7 @@ func (graph *Graph) restoreBaseImages() ([]string, error) {
|
||||||
// storeImage stores file system layer data for the given image to the
|
// storeImage stores file system layer data for the given image to the
|
||||||
// graph's storage driver. Image metadata is stored in a file
|
// graph's storage driver. Image metadata is stored in a file
|
||||||
// at the specified root directory.
|
// at the specified root directory.
|
||||||
func (graph *Graph) storeImage(img *Image, layerData archive.ArchiveReader, root string) (err error) {
|
func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader, root string) (err error) {
|
||||||
// Store the layer. If layerData is not nil, unpack it into the new layer
|
// Store the layer. If layerData is not nil, unpack it into the new layer
|
||||||
if layerData != nil {
|
if layerData != nil {
|
||||||
if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
|
if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
|
||||||
|
@ -109,6 +110,6 @@ func (graph *Graph) storeImage(img *Image, layerData archive.ArchiveReader, root
|
||||||
}
|
}
|
||||||
|
|
||||||
// TarLayer returns a tar archive of the image's filesystem layer.
|
// TarLayer returns a tar archive of the image's filesystem layer.
|
||||||
func (graph *Graph) TarLayer(img *Image) (arch archive.Archive, err error) {
|
func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
|
||||||
return graph.driver.Diff(img.ID, img.Parent)
|
return graph.driver.Diff(img.ID, img.Parent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/daemon/graphdriver/windows"
|
"github.com/docker/docker/daemon/graphdriver/windows"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ func SetupInitLayer(initLayer string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRootFilesystemInDriver(graph *Graph, img *Image, layerData archive.ArchiveReader) error {
|
func createRootFilesystemInDriver(graph *Graph, img *image.Image, layerData archive.ArchiveReader) error {
|
||||||
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
||||||
if img.Container != "" && layerData == nil {
|
if img.Container != "" && layerData == nil {
|
||||||
logrus.Debugf("Copying from container %s.", img.Container)
|
logrus.Debugf("Copying from container %s.", img.Container)
|
||||||
|
@ -59,7 +60,7 @@ func (graph *Graph) restoreBaseImages() ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParentLayerIds returns a list of all parent image IDs for the given image.
|
// ParentLayerIds returns a list of all parent image IDs for the given image.
|
||||||
func (graph *Graph) ParentLayerIds(img *Image) (ids []string, err error) {
|
func (graph *Graph) ParentLayerIds(img *image.Image) (ids []string, err error) {
|
||||||
for i := img; i != nil && err == nil; i, err = graph.GetParent(i) {
|
for i := img; i != nil && err == nil; i, err = graph.GetParent(i) {
|
||||||
ids = append(ids, i.ID)
|
ids = append(ids, i.ID)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ func (graph *Graph) ParentLayerIds(img *Image) (ids []string, err error) {
|
||||||
// storeImage stores file system layer data for the given image to the
|
// storeImage stores file system layer data for the given image to the
|
||||||
// graph's storage driver. Image metadata is stored in a file
|
// graph's storage driver. Image metadata is stored in a file
|
||||||
// at the specified root directory.
|
// at the specified root directory.
|
||||||
func (graph *Graph) storeImage(img *Image, layerData archive.ArchiveReader, root string) (err error) {
|
func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader, root string) (err error) {
|
||||||
|
|
||||||
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
||||||
// Store the layer. If layerData is not nil and this isn't a base image,
|
// Store the layer. If layerData is not nil and this isn't a base image,
|
||||||
|
@ -135,7 +136,7 @@ func (graph *Graph) storeImage(img *Image, layerData archive.ArchiveReader, root
|
||||||
}
|
}
|
||||||
|
|
||||||
// TarLayer returns a tar archive of the image's filesystem layer.
|
// TarLayer returns a tar archive of the image's filesystem layer.
|
||||||
func (graph *Graph) TarLayer(img *Image) (arch archive.Archive, err error) {
|
func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
|
||||||
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
||||||
var ids []string
|
var ids []string
|
||||||
if img.Parent != "" {
|
if img.Parent != "" {
|
||||||
|
|
|
@ -5,12 +5,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WalkHistory calls the handler function for each image in the
|
// WalkHistory calls the handler function for each image in the
|
||||||
// provided images lineage starting from immediate parent.
|
// provided images lineage starting from immediate parent.
|
||||||
func (graph *Graph) WalkHistory(img *Image, handler func(Image) error) (err error) {
|
func (graph *Graph) WalkHistory(img *image.Image, handler func(image.Image) error) (err error) {
|
||||||
currentImg := img
|
currentImg := img
|
||||||
for currentImg != nil {
|
for currentImg != nil {
|
||||||
if handler != nil {
|
if handler != nil {
|
||||||
|
@ -28,7 +29,7 @@ func (graph *Graph) WalkHistory(img *Image, handler func(Image) error) (err erro
|
||||||
|
|
||||||
// depth returns the number of parents for a
|
// depth returns the number of parents for a
|
||||||
// current image
|
// current image
|
||||||
func (graph *Graph) depth(img *Image) (int, error) {
|
func (graph *Graph) depth(img *image.Image) (int, error) {
|
||||||
var (
|
var (
|
||||||
count = 0
|
count = 0
|
||||||
parent = img
|
parent = img
|
||||||
|
@ -53,7 +54,7 @@ const MaxImageDepth = 127
|
||||||
// CheckDepth returns an error if the depth of an image, as returned
|
// CheckDepth returns an error if the depth of an image, as returned
|
||||||
// by ImageDepth, is too large to support creating a container from it
|
// by ImageDepth, is too large to support creating a container from it
|
||||||
// on this daemon.
|
// on this daemon.
|
||||||
func (graph *Graph) CheckDepth(img *Image) error {
|
func (graph *Graph) CheckDepth(img *image.Image) error {
|
||||||
// We add 2 layers to the depth because the container's rw and
|
// We add 2 layers to the depth because the container's rw and
|
||||||
// init layer add to the restriction
|
// init layer add to the restriction
|
||||||
depth, err := graph.depth(img)
|
depth, err := graph.depth(img)
|
||||||
|
@ -85,7 +86,7 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||||
|
|
||||||
history := []*types.ImageHistory{}
|
history := []*types.ImageHistory{}
|
||||||
|
|
||||||
err = s.graph.WalkHistory(foundImage, func(img Image) error {
|
err = s.graph.WalkHistory(foundImage, func(img image.Image) error {
|
||||||
history = append(history, &types.ImageHistory{
|
history = append(history, &types.ImageHistory{
|
||||||
ID: img.ID,
|
ID: img.ID,
|
||||||
Created: img.Created.Unix(),
|
Created: img.Created.Unix(),
|
||||||
|
@ -100,14 +101,14 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||||
return history, err
|
return history, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (graph *Graph) GetParent(img *Image) (*Image, error) {
|
func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
|
||||||
if img.Parent == "" {
|
if img.Parent == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return graph.Get(img.Parent)
|
return graph.Get(img.Parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (graph *Graph) GetParentsSize(img *Image, size int64) int64 {
|
func (graph *Graph) GetParentsSize(img *image.Image, size int64) int64 {
|
||||||
parentImage, err := graph.GetParent(img)
|
parentImage, err := graph.GetParent(img)
|
||||||
if err != nil || parentImage == nil {
|
if err != nil || parentImage == nil {
|
||||||
return size
|
return size
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers/filters"
|
"github.com/docker/docker/pkg/parsers/filters"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
@ -31,7 +32,7 @@ func (r ByCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
||||||
|
|
||||||
func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
var (
|
var (
|
||||||
allImages map[string]*Image
|
allImages map[string]*image.Image
|
||||||
err error
|
err error
|
||||||
filtTagged = true
|
filtTagged = true
|
||||||
filtLabel = false
|
filtLabel = false
|
||||||
|
|
|
@ -95,7 +95,7 @@ func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
|
||||||
logrus.Debugf("Error reading embedded tar: %v", err)
|
logrus.Debugf("Error reading embedded tar: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
img, err := NewImgJSON(imageJson)
|
img, err := image.NewImgJSON(imageJson)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Error unmarshalling json: %v", err)
|
logrus.Debugf("Error unmarshalling json: %v", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/distribution/registry/client/transport"
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/progressreader"
|
"github.com/docker/docker/pkg/progressreader"
|
||||||
"github.com/docker/docker/pkg/streamformatter"
|
"github.com/docker/docker/pkg/streamformatter"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
|
@ -257,7 +258,7 @@ func (p *v1Puller) pullImage(imgID, endpoint string, token []string) (bool, erro
|
||||||
imgJSON []byte
|
imgJSON []byte
|
||||||
imgSize int
|
imgSize int
|
||||||
err error
|
err error
|
||||||
img *Image
|
img *image.Image
|
||||||
)
|
)
|
||||||
retries := 5
|
retries := 5
|
||||||
for j := 1; j <= retries; j++ {
|
for j := 1; j <= retries; j++ {
|
||||||
|
@ -269,7 +270,7 @@ func (p *v1Puller) pullImage(imgID, endpoint string, token []string) (bool, erro
|
||||||
time.Sleep(time.Duration(j) * 500 * time.Millisecond)
|
time.Sleep(time.Duration(j) * 500 * time.Millisecond)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
img, err = NewImgJSON(imgJSON)
|
img, err = image.NewImgJSON(imgJSON)
|
||||||
layersDownloaded = true
|
layersDownloaded = true
|
||||||
if err != nil && j == retries {
|
if err != nil && j == retries {
|
||||||
out.Write(p.sf.FormatProgress(stringid.TruncateID(id), "Error pulling dependent layers", nil))
|
out.Write(p.sf.FormatProgress(stringid.TruncateID(id), "Error pulling dependent layers", nil))
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/progressreader"
|
"github.com/docker/docker/pkg/progressreader"
|
||||||
"github.com/docker/docker/pkg/streamformatter"
|
"github.com/docker/docker/pkg/streamformatter"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
|
@ -94,7 +95,7 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) {
|
||||||
|
|
||||||
// downloadInfo is used to pass information from download to extractor
|
// downloadInfo is used to pass information from download to extractor
|
||||||
type downloadInfo struct {
|
type downloadInfo struct {
|
||||||
img *Image
|
img *image.Image
|
||||||
tmpFile *os.File
|
tmpFile *os.File
|
||||||
digest digest.Digest
|
digest digest.Digest
|
||||||
layer distribution.ReadSeekCloser
|
layer distribution.ReadSeekCloser
|
||||||
|
@ -208,7 +209,7 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (bool, error) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for i := len(manifest.FSLayers) - 1; i >= 0; i-- {
|
for i := len(manifest.FSLayers) - 1; i >= 0; i-- {
|
||||||
img, err := NewImgJSON([]byte(manifest.History[i].V1Compatibility))
|
img, err := image.NewImgJSON([]byte(manifest.History[i].V1Compatibility))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("error getting image v1 json: %v", err)
|
logrus.Debugf("error getting image v1 json: %v", err)
|
||||||
return false, err
|
return false, err
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/distribution/manifest"
|
"github.com/docker/distribution/manifest"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/progressreader"
|
"github.com/docker/docker/pkg/progressreader"
|
||||||
"github.com/docker/docker/pkg/streamformatter"
|
"github.com/docker/docker/pkg/streamformatter"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
|
@ -190,7 +191,7 @@ func (p *v2Pusher) pushV2Tag(tag string) error {
|
||||||
return p.repo.Manifests().Put(signed)
|
return p.repo.Manifests().Put(signed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *v2Pusher) pushV2Image(bs distribution.BlobService, img *Image) (digest.Digest, error) {
|
func (p *v2Pusher) pushV2Image(bs distribution.BlobService, img *image.Image) (digest.Digest, error) {
|
||||||
out := p.config.OutStream
|
out := p.config.OutStream
|
||||||
|
|
||||||
out.Write(p.sf.FormatProgress(stringid.TruncateID(img.ID), "Buffering to Disk", nil))
|
out.Write(p.sf.FormatProgress(stringid.TruncateID(img.ID), "Buffering to Disk", nil))
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/daemon/events"
|
"github.com/docker/docker/daemon/events"
|
||||||
"github.com/docker/docker/graph/tags"
|
"github.com/docker/docker/graph/tags"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
|
@ -120,7 +121,7 @@ func (store *TagStore) reload() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) LookupImage(name string) (*Image, error) {
|
func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||||
// FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
|
// FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
|
||||||
// (so we can pass all errors here)
|
// (so we can pass all errors here)
|
||||||
repoName, ref := parsers.ParseRepositoryTag(name)
|
repoName, ref := parsers.ParseRepositoryTag(name)
|
||||||
|
@ -129,7 +130,7 @@ func (store *TagStore) LookupImage(name string) (*Image, error) {
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
img *Image
|
img *image.Image
|
||||||
)
|
)
|
||||||
|
|
||||||
img, err = store.GetImage(repoName, ref)
|
img, err = store.GetImage(repoName, ref)
|
||||||
|
@ -331,7 +332,7 @@ func (store *TagStore) Get(repoName string) (Repository, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) GetImage(repoName, refOrID string) (*Image, error) {
|
func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error) {
|
||||||
repo, err := store.Get(repoName)
|
repo, err := store.Get(repoName)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/docker/docker/daemon/events"
|
"github.com/docker/docker/daemon/events"
|
||||||
"github.com/docker/docker/daemon/graphdriver"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
_ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests
|
_ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests
|
||||||
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/trust"
|
"github.com/docker/docker/trust"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
@ -79,7 +80,7 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
img := &Image{ID: testOfficialImageID}
|
img := &image.Image{ID: testOfficialImageID}
|
||||||
if err := graph.Register(img, officialArchive); err != nil {
|
if err := graph.Register(img, officialArchive); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -90,7 +91,7 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
img = &Image{ID: testPrivateImageID}
|
img = &image.Image{ID: testPrivateImageID}
|
||||||
if err := graph.Register(img, privateArchive); err != nil {
|
if err := graph.Register(img, privateArchive); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,42 @@
|
||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
|
var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Parent string `json:"parent,omitempty"`
|
||||||
|
Comment string `json:"comment,omitempty"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
Container string `json:"container,omitempty"`
|
||||||
|
ContainerConfig runconfig.Config `json:"container_config,omitempty"`
|
||||||
|
DockerVersion string `json:"docker_version,omitempty"`
|
||||||
|
Author string `json:"author,omitempty"`
|
||||||
|
Config *runconfig.Config `json:"config,omitempty"`
|
||||||
|
Architecture string `json:"architecture,omitempty"`
|
||||||
|
OS string `json:"os,omitempty"`
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build an Image object from raw json data
|
||||||
|
func NewImgJSON(src []byte) (*Image, error) {
|
||||||
|
ret := &Image{}
|
||||||
|
|
||||||
|
// FIXME: Is there a cleaner way to "purify" the input json?
|
||||||
|
if err := json.Unmarshal(src, ret); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Check wheather id is a valid image ID or not
|
// Check wheather id is a valid image ID or not
|
||||||
func ValidateID(id string) error {
|
func ValidateID(id string) error {
|
||||||
if ok := validHex.MatchString(id); !ok {
|
if ok := validHex.MatchString(id); !ok {
|
||||||
|
|
Loading…
Reference in a new issue