diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2019-01-11 05:54:16 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-11 05:54:16 -0800 |
commit | 9368c24be6f289d21a0065df24471268ead59664 (patch) | |
tree | ee9aec7d2e4a04a4310dbd54730c9aaa7a2dfe46 /libpod | |
parent | b3eb23d671425775673f86bd02b9c89ef781f590 (diff) | |
parent | c8e3dd8a9ce7ba7948a5db88608a57de07599c7b (diff) | |
download | podman-9368c24be6f289d21a0065df24471268ead59664.tar.gz podman-9368c24be6f289d21a0065df24471268ead59664.tar.bz2 podman-9368c24be6f289d21a0065df24471268ead59664.zip |
Merge pull request #2113 from baude/remoteimages
remote-client support for images
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/adapter/images_remote.go | 17 | ||||
-rw-r--r-- | libpod/adapter/runtime.go | 29 | ||||
-rw-r--r-- | libpod/adapter/runtime_remote.go | 151 | ||||
-rw-r--r-- | libpod/image/filters.go | 83 | ||||
-rw-r--r-- | libpod/image/image.go | 6 | ||||
-rw-r--r-- | libpod/image/parts.go | 36 | ||||
-rw-r--r-- | libpod/image/parts_test.go | 4 | ||||
-rw-r--r-- | libpod/image/pull.go | 4 | ||||
-rw-r--r-- | libpod/image/utils.go | 6 |
9 files changed, 226 insertions, 110 deletions
diff --git a/libpod/adapter/images_remote.go b/libpod/adapter/images_remote.go new file mode 100644 index 000000000..77b0629a7 --- /dev/null +++ b/libpod/adapter/images_remote.go @@ -0,0 +1,17 @@ +// +build remoteclient + +package adapter + +import ( + "github.com/containers/libpod/libpod" +) + +// Images returns information for the host system and its components +func (r RemoteRuntime) Images() ([]libpod.InfoData, error) { + conn, err := r.Connect() + if err != nil { + return nil, err + } + _ = conn + return nil, nil +} diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go index b6db51071..13141f886 100644 --- a/libpod/adapter/runtime.go +++ b/libpod/adapter/runtime.go @@ -5,6 +5,7 @@ package adapter import ( "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" "github.com/urfave/cli" ) @@ -14,6 +15,11 @@ type LocalRuntime struct { Remote bool } +// ContainerImage ... +type ContainerImage struct { + *image.Image +} + // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it func GetRuntime(c *cli.Context) (*LocalRuntime, error) { runtime, err := libpodruntime.GetRuntime(c) @@ -24,3 +30,26 @@ func GetRuntime(c *cli.Context) (*LocalRuntime, error) { Runtime: runtime, }, nil } + +// GetImages returns a slice of images in containerimages +func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) { + var containerImages []*ContainerImage + images, err := r.Runtime.ImageRuntime().GetImages() + if err != nil { + return nil, err + } + for _, i := range images { + containerImages = append(containerImages, &ContainerImage{i}) + } + return containerImages, nil + +} + +// NewImageFromLocal returns a containerimage representation of a image from local storage +func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { + img, err := r.Runtime.ImageRuntime().NewFromLocal(name) + if err != nil { + return nil, err + } + return &ContainerImage{img}, nil +} diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go index 715728d21..2f22dd36b 100644 --- a/libpod/adapter/runtime_remote.go +++ b/libpod/adapter/runtime_remote.go @@ -2,23 +2,43 @@ package adapter -import "github.com/urfave/cli" +import ( + "context" + "fmt" + "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod/image" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli" + "github.com/varlink/go/varlink" + "strings" + "time" +) + +// ImageRuntime is wrapper for image runtime +type RemoteImageRuntime struct{} // RemoteRuntime describes a wrapper runtime struct -type RemoteRuntime struct{} +type RemoteRuntime struct { +} // LocalRuntime describes a typical libpod runtime type LocalRuntime struct { Runtime *RemoteRuntime Remote bool + Conn *varlink.Connection } // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it func GetRuntime(c *cli.Context) (*LocalRuntime, error) { runtime := RemoteRuntime{} + conn, err := runtime.Connect() + if err != nil { + return nil, err + } return &LocalRuntime{ Runtime: &runtime, Remote: true, + Conn: conn, }, nil } @@ -26,3 +46,130 @@ func GetRuntime(c *cli.Context) (*LocalRuntime, error) { func (r RemoteRuntime) Shutdown(force bool) error { return nil } + +// ContainerImage +type ContainerImage struct { + remoteImage +} + +type remoteImage struct { + ID string + Labels map[string]string + RepoTags []string + RepoDigests []string + Parent string + Size int64 + Tag string + Repository string + Created time.Time + InputName string + Names []string + Digest digest.Digest + isParent bool +} + +// GetImages returns a slice of containerimages over a varlink connection +func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) { + var newImages []*ContainerImage + images, err := iopodman.ListImages().Call(r.Conn) + if err != nil { + return nil, err + } + for _, i := range images { + name := i.Id + if len(i.RepoTags) > 1 { + name = i.RepoTags[0] + } + newImage, err := imageInListToContainerImage(i, name) + if err != nil { + return nil, err + } + newImages = append(newImages, newImage) + } + return newImages, nil +} + +func imageInListToContainerImage(i iopodman.ImageInList, name string) (*ContainerImage, error) { + imageParts, err := image.DecomposeString(name) + if err != nil { + return nil, err + } + created, err := splitStringDate(i.Created) + if err != nil { + return nil, err + } + ri := remoteImage{ + InputName: name, + ID: i.Id, + Labels: i.Labels, + RepoTags: i.RepoTags, + RepoDigests: i.RepoTags, + Parent: i.ParentId, + Size: i.Size, + Created: created, + Tag: imageParts.Tag, + Repository: imageParts.Registry, + Names: i.RepoTags, + isParent: i.IsParent, + } + return &ContainerImage{ri}, nil +} + +// NewImageFromLocal returns a container image representation of a image over varlink +func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { + img, err := iopodman.GetImage().Call(r.Conn, name) + if err != nil { + return nil, err + } + return imageInListToContainerImage(img, name) + +} + +func splitStringDate(d string) (time.Time, error) { + fields := strings.Fields(d) + t := fmt.Sprintf("%sT%sZ", fields[0], fields[1]) + return time.ParseInLocation(time.RFC3339Nano, t, time.UTC) +} + +// IsParent goes through the layers in the store and checks if i.TopLayer is +// the parent of any other layer in store. Double check that image with that +// layer exists as well. +func (ci *ContainerImage) IsParent() (bool, error) { + return ci.remoteImage.isParent, nil +} + +// ID returns the image ID as a string +func (ci *ContainerImage) ID() string { + return ci.remoteImage.ID +} + +// Names returns a string array of names associated with the image +func (ci *ContainerImage) Names() []string { + return ci.remoteImage.Names +} + +// Created returns the time the image was created +func (ci *ContainerImage) Created() time.Time { + return ci.remoteImage.Created +} + +// Size returns the size of the image +func (ci *ContainerImage) Size(ctx context.Context) (*uint64, error) { + usize := uint64(ci.remoteImage.Size) + return &usize, nil +} + +// Digest returns the image's digest +func (ci *ContainerImage) Digest() digest.Digest { + return ci.remoteImage.Digest +} + +// Labels returns a map of the image's labels +func (ci *ContainerImage) Labels(ctx context.Context) (map[string]string, error) { + return ci.remoteImage.Labels, nil +} + +// Dangling returns a bool if the image is "dangling" +func (ci *ContainerImage) Dangling() bool { + return len(ci.Names()) == 0 +} diff --git a/libpod/image/filters.go b/libpod/image/filters.go deleted file mode 100644 index d0c3adfb5..000000000 --- a/libpod/image/filters.go +++ /dev/null @@ -1,83 +0,0 @@ -package image - -import ( - "context" - "strings" - "time" - - "github.com/containers/libpod/pkg/inspect" -) - -// ResultFilter is a mock function for image filtering -type ResultFilter func(*Image) bool - -// Filter is a function to determine whether an image is included in -// command output. Images to be outputted are tested using the function. A true -// return will include the image, a false return will exclude it. -type Filter func(*Image, *inspect.ImageData) bool - -// CreatedBeforeFilter allows you to filter on images created before -// the given time.Time -func CreatedBeforeFilter(createTime time.Time) ResultFilter { - return func(i *Image) bool { - return i.Created().Before(createTime) - } -} - -// CreatedAfterFilter allows you to filter on images created after -// the given time.Time -func CreatedAfterFilter(createTime time.Time) ResultFilter { - return func(i *Image) bool { - return i.Created().After(createTime) - } -} - -// DanglingFilter allows you to filter images for dangling images -func DanglingFilter() ResultFilter { - return func(i *Image) bool { - return i.Dangling() - } -} - -// LabelFilter allows you to filter by images labels key and/or value -func LabelFilter(ctx context.Context, labelfilter string) ResultFilter { - // We need to handle both label=key and label=key=value - return func(i *Image) bool { - var value string - splitFilter := strings.Split(labelfilter, "=") - key := splitFilter[0] - if len(splitFilter) > 1 { - value = splitFilter[1] - } - labels, err := i.Labels(ctx) - if err != nil { - return false - } - if len(strings.TrimSpace(labels[key])) > 0 && len(strings.TrimSpace(value)) == 0 { - return true - } - return labels[key] == value - } -} - -// OutputImageFilter allows you to filter by an a specific image name -func OutputImageFilter(userImage *Image) ResultFilter { - return func(i *Image) bool { - return userImage.ID() == i.ID() - } -} - -// FilterImages filters images using a set of predefined filter funcs -func FilterImages(images []*Image, filters []ResultFilter) []*Image { - var filteredImages []*Image - for _, image := range images { - include := true - for _, filter := range filters { - include = include && filter(image) - } - if include { - filteredImages = append(filteredImages, image) - } - } - return filteredImages -} diff --git a/libpod/image/image.go b/libpod/image/image.go index 2e12adb70..dda753385 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -460,7 +460,7 @@ func normalizeTag(tag string) (string, error) { } // If the input does not have a tag, we need to add one (latest) if !decomposedTag.isTagged { - tag = fmt.Sprintf("%s:%s", tag, decomposedTag.tag) + tag = fmt.Sprintf("%s:%s", tag, decomposedTag.Tag) } // If the input doesn't specify a registry, set the registry to localhost if !decomposedTag.hasRegistry { @@ -937,7 +937,7 @@ func (i *Image) MatchRepoTag(input string) (string, error) { if err != nil { return "", err } - if dcRepoName.registry == dcImage.registry && dcImage.registry != "" { + if dcRepoName.Registry == dcImage.Registry && dcImage.Registry != "" { count++ } if dcRepoName.name == dcImage.name && dcImage.name != "" { @@ -945,7 +945,7 @@ func (i *Image) MatchRepoTag(input string) (string, error) { } else if splitString(dcRepoName.name) == splitString(dcImage.name) { count++ } - if dcRepoName.tag == dcImage.tag { + if dcRepoName.Tag == dcImage.Tag { count++ } results[count] = append(results[count], repoName) diff --git a/libpod/image/parts.go b/libpod/image/parts.go index 9adf26fb9..b2a69f26c 100644 --- a/libpod/image/parts.go +++ b/libpod/image/parts.go @@ -7,12 +7,12 @@ import ( "github.com/containers/image/docker/reference" ) -// imageParts describes the parts of an image's name -type imageParts struct { +// Parts describes the parts of an image's name +type Parts struct { transport string - registry string + Registry string name string - tag string + Tag string isTagged bool hasRegistry bool } @@ -34,10 +34,16 @@ func GetImageBaseName(input string) (string, error) { return splitImageName[len(splitImageName)-1], nil } +// DecomposeString decomposes a string name into imageParts description. This +// is a wrapper for decompose +func DecomposeString(input string) (Parts, error) { + return decompose(input) +} + // decompose breaks an input name into an imageParts description -func decompose(input string) (imageParts, error) { +func decompose(input string) (Parts, error) { var ( - parts imageParts + parts Parts hasRegistry bool tag string ) @@ -56,7 +62,7 @@ func decompose(input string) (imageParts, error) { } registry := reference.Domain(imgRef.(reference.Named)) imageName := reference.Path(imgRef.(reference.Named)) - // Is this a registry or a repo? + // Is this a Registry or a repo? if isRegistry(registry) { hasRegistry = true } else { @@ -65,27 +71,27 @@ func decompose(input string) (imageParts, error) { registry = "" } } - return imageParts{ - registry: registry, + return Parts{ + Registry: registry, hasRegistry: hasRegistry, name: imageName, - tag: tag, + Tag: tag, isTagged: isTagged, transport: DefaultTransport, }, nil } // assemble concatenates an image's parts into a string -func (ip *imageParts) assemble() string { - spec := fmt.Sprintf("%s:%s", ip.name, ip.tag) +func (ip *Parts) assemble() string { + spec := fmt.Sprintf("%s:%s", ip.name, ip.Tag) - if ip.registry != "" { - spec = fmt.Sprintf("%s/%s", ip.registry, spec) + if ip.Registry != "" { + spec = fmt.Sprintf("%s/%s", ip.Registry, spec) } return spec } // assemble concatenates an image's parts with transport into a string -func (ip *imageParts) assembleWithTransport() string { +func (ip *Parts) assembleWithTransport() string { return fmt.Sprintf("%s%s", ip.transport, ip.assemble()) } diff --git a/libpod/image/parts_test.go b/libpod/image/parts_test.go index 518538f0b..1e01c85d3 100644 --- a/libpod/image/parts_test.go +++ b/libpod/image/parts_test.go @@ -55,9 +55,9 @@ func TestDecompose(t *testing.T) { } else { assert.NoError(t, err, c.input) assert.Equal(t, c.transport, parts.transport, c.input) - assert.Equal(t, c.registry, parts.registry, c.input) + assert.Equal(t, c.registry, parts.Registry, c.input) assert.Equal(t, c.name, parts.name, c.input) - assert.Equal(t, c.tag, parts.tag, c.input) + assert.Equal(t, c.tag, parts.Tag, c.input) assert.Equal(t, c.isTagged, parts.isTagged, c.input) assert.Equal(t, c.hasRegistry, parts.hasRegistry, c.input) assert.Equal(t, c.assembled, parts.assemble(), c.input) diff --git a/libpod/image/pull.go b/libpod/image/pull.go index 09935fe7c..203e94310 100644 --- a/libpod/image/pull.go +++ b/libpod/image/pull.go @@ -76,7 +76,7 @@ func (ir *Runtime) getPullRefPair(srcRef types.ImageReference, destName string) decomposedDest, err := decompose(destName) if err == nil && !decomposedDest.hasRegistry { // If the image doesn't have a registry, set it as the default repo - decomposedDest.registry = DefaultLocalRegistry + decomposedDest.Registry = DefaultLocalRegistry decomposedDest.hasRegistry = true destName = decomposedDest.assemble() } @@ -317,7 +317,7 @@ func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(inputName string) (*pullG } var refPairs []pullRefPair for _, registry := range searchRegistries { - decomposedImage.registry = registry + decomposedImage.Registry = registry imageName := decomposedImage.assembleWithTransport() if hasShaInInputName(inputName) { imageName = fmt.Sprintf("%s%s/%s", decomposedImage.transport, registry, inputName) diff --git a/libpod/image/utils.go b/libpod/image/utils.go index b944de1bb..135b47008 100644 --- a/libpod/image/utils.go +++ b/libpod/image/utils.go @@ -16,7 +16,7 @@ import ( // findImageInRepotags takes an imageParts struct and searches images' repotags for // a match on name:tag -func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) { +func findImageInRepotags(search Parts, images []*Image) (*storage.Image, error) { var results []*storage.Image for _, image := range images { for _, name := range image.Names() { @@ -25,12 +25,12 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er if err != nil { continue } - if d.name == search.name && d.tag == search.tag { + if d.name == search.name && d.Tag == search.Tag { results = append(results, image.image) continue } // account for registry:/somedir/image - if strings.HasSuffix(d.name, search.name) && d.tag == search.tag { + if strings.HasSuffix(d.name, search.name) && d.Tag == search.Tag { results = append(results, image.image) continue } |