move driver and image metadata to libkpod

Signed-off-by: Ryan Cole <rcyoalne@gmail.com>
This commit is contained in:
Ryan Cole 2017-07-21 16:43:30 -04:00
parent a95bbe9608
commit 95e17b4a73
10 changed files with 81 additions and 903 deletions

View file

@ -1,29 +1,19 @@
package main
import (
"encoding/json"
"io"
"strings"
"time"
cp "github.com/containers/image/copy"
"github.com/containers/image/signature"
is "github.com/containers/image/storage"
"github.com/containers/image/types"
"github.com/containers/storage"
"github.com/kubernetes-incubator/cri-o/libkpod/image"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
type imageMetadata struct {
Tag string `json:"tag"`
CreatedTime time.Time `json:"created-time"`
ID string `json:"id"`
Blobs []types.BlobInfo `json:"blob-list"`
Layers map[string][]string `json:"layers"`
SignatureSizes []string `json:"signature-sizes"`
}
// DockerRegistryOptions encapsulates settings that affect how we connect or
// authenticate to a remote registry.
type dockerRegistryOptions struct {
@ -77,16 +67,6 @@ func getStore(c *cli.Context) (storage.Store, error) {
return store, nil
}
func parseMetadata(image storage.Image) (imageMetadata, error) {
var im imageMetadata
dec := json.NewDecoder(strings.NewReader(image.Metadata))
if err := dec.Decode(&im); err != nil {
return imageMetadata{}, err
}
return im, nil
}
func findImage(store storage.Store, image string) (*storage.Image, error) {
var img *storage.Image
ref, err := is.Transport.ParseStoreReference(store, image)
@ -239,41 +219,25 @@ func isValidBool(str string) bool {
return isTrue(str) || isFalse(str)
}
func getDriverName(store storage.Store) (string, error) {
driver, err := store.GraphDriver()
if err != nil {
return "", err
}
return driver.String(), nil
}
func getDriverMetadata(store storage.Store, layerID string) (map[string]string, error) {
driver, err := store.GraphDriver()
if err != nil {
return nil, err
}
return driver.Metadata(layerID)
}
func getImageSize(image storage.Image, store storage.Store) (int64, error) {
func getImageSize(img storage.Image, store storage.Store) (int64, error) {
is.Transport.SetStore(store)
storeRef, err := is.Transport.ParseStoreReference(store, "@"+image.ID)
storeRef, err := is.Transport.ParseStoreReference(store, "@"+img.ID)
if err != nil {
return -1, err
}
img, err := storeRef.NewImage(nil)
imgRef, err := storeRef.NewImage(nil)
if err != nil {
return -1, err
}
imgSize, err := img.Size()
imgSize, err := imgRef.Size()
if err != nil {
return -1, err
}
return imgSize, nil
}
func getImageTopLayer(image storage.Image) (string, error) {
metadata, err := parseMetadata(image)
func getImageTopLayer(img storage.Image) (string, error) {
metadata, err := image.ParseMetadata(img)
if err != nil {
return "", err
}

View file

@ -30,30 +30,6 @@ func TestGetStore(t *testing.T) {
}
}
func TestParseMetadata(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
} else if len(images) == 0 {
t.Fatalf("no images with metadata to parse")
}
_, err = parseMetadata(images[0])
if err != nil {
t.Error(err)
}
}
func TestGetSize(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)

View file

@ -9,6 +9,7 @@ import (
"github.com/containers/storage"
"github.com/kubernetes-incubator/cri-o/cmd/kpod/docker"
"github.com/kubernetes-incubator/cri-o/libkpod/driver"
"github.com/kubernetes-incubator/cri-o/oci"
"github.com/kubernetes-incubator/cri-o/pkg/annotations"
"github.com/kubernetes-incubator/cri-o/server"
@ -71,7 +72,7 @@ func getContainerData(store storage.Store, name string, size bool) (*containerDa
return nil, err
}
driverName, err := getDriverName(store)
driverName, err := driver.GetDriverName(store)
if err != nil {
return nil, err
}
@ -79,7 +80,7 @@ func getContainerData(store storage.Store, name string, size bool) (*containerDa
if err != nil {
return nil, err
}
driverMetadata, err := getDriverMetadata(store, topLayer)
driverMetadata, err := driver.GetDriverMetadata(store, topLayer)
if err != nil {
return nil, err
}

View file

@ -5,6 +5,8 @@ import (
"time"
"github.com/containers/storage"
"github.com/kubernetes-incubator/cri-o/libkpod/driver"
"github.com/kubernetes-incubator/cri-o/libkpod/image"
digest "github.com/opencontainers/go-digest"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@ -94,7 +96,7 @@ func getImageData(store storage.Store, name string) (*imageData, error) {
}
}
driverName, err := getDriverName(store)
driverName, err := driver.GetDriverName(store)
if err != nil {
return nil, err
}
@ -103,7 +105,7 @@ func getImageData(store storage.Store, name string) (*imageData, error) {
if err != nil {
return nil, err
}
driverMetadata, err := getDriverMetadata(store, topLayerID)
driverMetadata, err := driver.GetDriverMetadata(store, topLayerID)
if err != nil {
return nil, err
}
@ -150,7 +152,7 @@ func getImageData(store storage.Store, name string) (*imageData, error) {
}
func getDigests(img storage.Image) ([]digest.Digest, error) {
metadata, err := parseMetadata(img)
metadata, err := image.ParseMetadata(img)
if err != nil {
return nil, err
}

View file

@ -8,6 +8,7 @@ import (
is "github.com/containers/image/storage"
"github.com/containers/storage"
"github.com/kubernetes-incubator/cri-o/libkpod/image"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
@ -190,8 +191,8 @@ func outputHeader(truncate, digests bool) {
}
func outputImages(images []storage.Image, format string, store storage.Store, filters *filterParams, argName string, hasTemplate, truncate, digests, quiet bool) error {
for _, image := range images {
imageMetadata, err := parseMetadata(image)
for _, img := range images {
imageMetadata, err := image.ParseMetadata(img)
if err != nil {
fmt.Println(err)
}
@ -200,27 +201,27 @@ func outputImages(images []storage.Image, format string, store storage.Store, fi
if len(imageMetadata.Blobs) > 0 {
digest = string(imageMetadata.Blobs[0].Digest)
}
size, _ := getImageSize(image, store)
size, _ := getImageSize(img, store)
names := []string{""}
if len(image.Names) > 0 {
names = image.Names
if len(img.Names) > 0 {
names = img.Names
} else {
// images without names should be printed with "<none>" as the image name
names = append(names, "<none>")
}
for _, name := range names {
if !matchesFilter(image, store, name, filters) || !matchesReference(name, argName) {
if !matchesFilter(img, store, name, filters) || !matchesReference(name, argName) {
continue
}
if quiet {
fmt.Printf("%-64s\n", image.ID)
fmt.Printf("%-64s\n", img.ID)
// We only want to print each id once
break
}
params := imageOutputParams{
ID: image.ID,
ID: img.ID,
Name: name,
Digest: digest,
CreatedAt: createdTime,

View file

@ -1,678 +0,0 @@
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
"testing"
is "github.com/containers/image/storage"
"github.com/containers/storage"
)
func TestTemplateOutputBlankTemplate(t *testing.T) {
params := imageOutputParams{
ID: "0123456789abcdef",
Name: "test/image:latest",
Digest: "sha256:012345789abcdef012345789abcdef012345789abcdef012345789abcdef",
CreatedAt: "Jan 01 2016 10:45",
Size: "97 KB",
}
err := outputUsingTemplate("", params)
//Output: Words
if err != nil {
t.Error(err)
}
}
func TestTemplateOutputValidTemplate(t *testing.T) {
params := imageOutputParams{
ID: "0123456789abcdef",
Name: "test/image:latest",
Digest: "sha256:012345789abcdef012345789abcdef012345789abcdef012345789abcdef",
CreatedAt: "Jan 01 2016 10:45",
Size: "97 KB",
}
templateString := "{{.ID}}"
output, err := captureOutputWithError(func() error {
return outputUsingTemplate(templateString, params)
})
if err != nil {
t.Error(err)
} else if strings.TrimSpace(output) != strings.TrimSpace(params.ID) {
t.Errorf("Error with template output:\nExpected: %s\nReceived: %s\n", params.ID, output)
}
}
func TestFormatStringOutput(t *testing.T) {
params := imageOutputParams{
ID: "012345789abcdef",
Name: "test/image:latest",
Digest: "sha256:012345789abcdef012345789abcdef012345789abcdef012345789abcdef",
CreatedAt: "Jan 01 2016 10:45",
Size: "97 KB",
}
output := captureOutput(func() {
outputUsingFormatString(true, true, params)
})
expectedOutput := fmt.Sprintf("%-12.12s %-40s %-64s %-22s %s\n", params.ID, params.Name, params.Digest, params.CreatedAt, params.Size)
if output != expectedOutput {
t.Errorf("Error outputting using format string:\n\texpected: %s\n\treceived: %s\n", expectedOutput, output)
}
}
func TestSizeFormatting(t *testing.T) {
size := formattedSize(0)
if size != "0 B" {
t.Errorf("Error formatting size: expected '%s' got '%s'", "0 B", size)
}
size = formattedSize(1024)
if size != "1 KB" {
t.Errorf("Error formatting size: expected '%s' got '%s'", "1 KB", size)
}
size = formattedSize(1024 * 1024 * 1024 * 1024 * 1024)
if size != "1024 TB" {
t.Errorf("Error formatting size: expected '%s' got '%s'", "1024 TB", size)
}
}
func TestOutputHeader(t *testing.T) {
output := captureOutput(func() {
outputHeader(true, false)
})
expectedOutput := fmt.Sprintf("%-12s %-40s %-22s %s\n", "IMAGE ID", "IMAGE NAME", "CREATED AT", "SIZE")
if output != expectedOutput {
t.Errorf("Error outputting header:\n\texpected: %s\n\treceived: %s\n", expectedOutput, output)
}
output = captureOutput(func() {
outputHeader(true, true)
})
expectedOutput = fmt.Sprintf("%-12s %-40s %-64s %-22s %s\n", "IMAGE ID", "IMAGE NAME", "DIGEST", "CREATED AT", "SIZE")
if output != expectedOutput {
t.Errorf("Error outputting header:\n\texpected: %s\n\treceived: %s\n", expectedOutput, output)
}
output = captureOutput(func() {
outputHeader(false, false)
})
expectedOutput = fmt.Sprintf("%-64s %-40s %-22s %s\n", "IMAGE ID", "IMAGE NAME", "CREATED AT", "SIZE")
if output != expectedOutput {
t.Errorf("Error outputting header:\n\texpected: %s\n\treceived: %s\n", expectedOutput, output)
}
}
func TestMatchWithTag(t *testing.T) {
isMatch := matchesReference("docker.io/kubernetes/pause:latest", "pause:latest")
if !isMatch {
t.Error("expected match, got not match")
}
isMatch = matchesReference("docker.io/kubernetes/pause:latest", "kubernetes/pause:latest")
if !isMatch {
t.Error("expected match, got no match")
}
}
func TestNoMatchesReferenceWithTag(t *testing.T) {
isMatch := matchesReference("docker.io/kubernetes/pause:latest", "redis:latest")
if isMatch {
t.Error("expected no match, got match")
}
isMatch = matchesReference("docker.io/kubernetes/pause:latest", "kubernetes/redis:latest")
if isMatch {
t.Error("expected no match, got match")
}
}
func TestMatchesReferenceWithoutTag(t *testing.T) {
isMatch := matchesReference("docker.io/kubernetes/pause:latest", "pause")
if !isMatch {
t.Error("expected match, got not match")
}
isMatch = matchesReference("docker.io/kubernetes/pause:latest", "kubernetes/pause")
if !isMatch {
t.Error("expected match, got no match")
}
}
func TestNoMatchesReferenceWithoutTag(t *testing.T) {
isMatch := matchesReference("docker.io/kubernetes/pause:latest", "redis")
if isMatch {
t.Error("expected no match, got match")
}
isMatch = matchesReference("docker.io/kubernetes/pause:latest", "kubernetes/redis")
if isMatch {
t.Error("expected no match, got match")
}
}
func TestOutputImagesQuietTruncated(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Tests quiet and truncated output
output, err := captureOutputWithError(func() error {
return outputImages(images[:1], "", store, nil, "", false, true, false, true)
})
expectedOutput := fmt.Sprintf("%-64s\n", images[0].ID)
if err != nil {
t.Error("quiet/truncated output produces error")
} else if strings.TrimSpace(output) != strings.TrimSpace(expectedOutput) {
t.Errorf("quiet/truncated output does not match expected value\nExpected: %s\nReceived: %s\n", expectedOutput, output)
}
}
func TestOutputImagesQuietNotTruncated(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Tests quiet and non-truncated output
output, err := captureOutputWithError(func() error {
return outputImages(images[:1], "", store, nil, "", false, false, false, true)
})
expectedOutput := fmt.Sprintf("%-64s\n", images[0].ID)
if err != nil {
t.Error("quiet/non-truncated output produces error")
} else if strings.TrimSpace(output) != strings.TrimSpace(expectedOutput) {
t.Errorf("quiet/non-truncated output does not match expected value\nExpected: %s\nReceived: %s\n", expectedOutput, output)
}
}
func TestOutputImagesFormatString(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Tests output with format template
output, err := captureOutputWithError(func() error {
return outputImages(images[:1], "{{.ID}}", store, nil, "", true, true, false, false)
})
expectedOutput := fmt.Sprintf("%s", images[0].ID)
if err != nil {
t.Error("format string output produces error")
} else if strings.TrimSpace(output) != strings.TrimSpace(expectedOutput) {
t.Errorf("format string output does not match expected value\nExpected: %s\nReceived: %s\n", expectedOutput, output)
}
}
func TestOutputImagesFormatTemplate(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Tests quiet and non-truncated output
output, err := captureOutputWithError(func() error {
return outputImages(images[:1], "", store, nil, "", false, false, false, true)
})
expectedOutput := fmt.Sprintf("%-64s\n", images[0].ID)
if err != nil {
t.Error("format template output produces error")
} else if strings.TrimSpace(output) != strings.TrimSpace(expectedOutput) {
t.Errorf("format template output does not match expected value\nExpected: %s\nReceived: %s\n", expectedOutput, output)
}
}
func TestOutputImagesArgNoMatch(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Tests output with an arg name that does not match. Args ending in ":" cannot match
// because all images in the repository must have a tag, and here the tag is an
// empty string
output, err := captureOutputWithError(func() error {
return outputImages(images[:1], "", store, nil, "foo:", false, true, false, false)
})
expectedOutput := fmt.Sprintf("")
if err != nil {
t.Error("arg no match output produces error")
} else if strings.TrimSpace(output) != strings.TrimSpace(expectedOutput) {
t.Error("arg no match output should be empty")
}
}
func TestOutputMultipleImages(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Tests quiet and truncated output
output, err := captureOutputWithError(func() error {
return outputImages(images[:2], "", store, nil, "", false, true, false, true)
})
expectedOutput := fmt.Sprintf("%-64s\n%-64s\n", images[0].ID, images[1].ID)
if err != nil {
t.Error("multi-image output produces error")
} else if strings.TrimSpace(output) != strings.TrimSpace(expectedOutput) {
t.Errorf("multi-image output does not match expected value\nExpected: %s\nReceived: %s\n", expectedOutput, output)
}
}
func TestParseFilterAllParams(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
label := "dangling=true,label=a=b,before=busybox:latest,since=busybox:latest,reference=abcdef"
params, err := parseFilter(images, label)
if err != nil {
t.Fatalf("error parsing filter")
}
expectedParams := &filterParams{dangling: "true", label: "a=b", beforeImage: "busybox:latest", sinceImage: "busybox:latest", referencePattern: "abcdef"}
if *params != *expectedParams {
t.Errorf("filter did not return expected result\n\tExpected: %v\n\tReceived: %v", expectedParams, params)
}
}
func TestParseFilterInvalidDangling(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
label := "dangling=NO,label=a=b,before=busybox:latest,since=busybox:latest,reference=abcdef"
_, err = parseFilter(images, label)
if err == nil || err.Error() != "invalid filter: 'dangling=[NO]'" {
t.Fatalf("expected error parsing filter")
}
}
func TestParseFilterInvalidBefore(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
label := "dangling=false,label=a=b,before=:,since=busybox:latest,reference=abcdef"
_, err = parseFilter(images, label)
if err == nil || !strings.Contains(err.Error(), "no such id") {
t.Fatalf("expected error parsing filter")
}
}
func TestParseFilterInvalidSince(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
label := "dangling=false,label=a=b,before=busybox:latest,since=:,reference=abcdef"
_, err = parseFilter(images, label)
if err == nil || !strings.Contains(err.Error(), "no such id") {
t.Fatalf("expected error parsing filter")
}
}
func TestParseFilterInvalidFilter(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
label := "foo=bar"
_, err = parseFilter(images, label)
if err == nil || err.Error() != "invalid filter: 'foo'" {
t.Fatalf("expected error parsing filter")
}
}
func TestImageExistsTrue(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:katest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
if !imageExists(images, "busybox:latest") {
t.Errorf("expected image %s to exist", "busybox:latest")
}
}
func TestImageExistsFalse(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
if imageExists(images, ":") {
t.Errorf("image %s should not exist", ":")
}
}
func TestMatchesDangingTrue(t *testing.T) {
if !matchesDangling("<none>", "true") {
t.Error("matchesDangling() should return true with dangling=true and name=<none>")
}
if !matchesDangling("hello", "false") {
t.Error("matchesDangling() should return true with dangling=false and name='hello'")
}
}
func TestMatchesDangingFalse(t *testing.T) {
if matchesDangling("hello", "true") {
t.Error("matchesDangling() should return false with dangling=true and name=hello")
}
if matchesDangling("<none>", "false") {
t.Error("matchesDangling() should return false with dangling=false and name=<none>")
}
}
func TestMatchesLabelTrue(t *testing.T) {
//TODO: How do I implement this?
}
func TestMatchesLabelFalse(t *testing.T) {
// TODO: How do I implement this?
}
func TestMatchesBeforeImageTrue(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// by default, params.seenImage is false
params := new(filterParams)
params.seenImage = false
params.beforeImage = "foo:bar"
if !matchesBeforeImage(images[0], ":", params) {
t.Error("should have matched beforeImage")
}
}
func TestMatchesBeforeImageFalse(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// by default, params.seenImage is false
params := new(filterParams)
params.seenImage = true
params.beforeImage = "foo:bar"
// Should return false because the image has been seen
if matchesBeforeImage(images[0], ":", params) {
t.Error("should not have matched beforeImage")
}
params.seenImage = false
if matchesBeforeImage(images[0], "foo:bar", params) {
t.Error("image should have been filtered out")
}
}
func TestMatchesSinceeImageTrue(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// by default, params.seenImage is false
params := new(filterParams)
params.seenImage = true
params.sinceImage = "foo:bar"
if !matchesSinceImage(images[0], ":", params) {
t.Error("should have matched SinceImage")
}
}
func TestMatchesSinceImageFalse(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
store, err := storage.GetStore(storage.DefaultStoreOptions)
if err != nil {
t.Fatal(err)
} else if store != nil {
is.Transport.SetStore(store)
}
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
// by default, params.seenImage is false
params := new(filterParams)
params.seenImage = false
params.sinceImage = "foo:bar"
// Should return false because the image has been seen
if matchesSinceImage(images[0], ":", params) {
t.Error("should not have matched sinceImage")
}
if matchesSinceImage(images[0], "foo:bar", params) {
t.Error("image should have been filtered out")
}
}
func captureOutputWithError(f func() error) (string, error) {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
err := f()
w.Close()
os.Stdout = old
var buf bytes.Buffer
io.Copy(&buf, r)
return buf.String(), err
}
// Captures output so that it can be compared to expected values
func captureOutput(f func()) string {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
f()
w.Close()
os.Stdout = old
var buf bytes.Buffer
io.Copy(&buf, r)
return buf.String()
}

View file

@ -1,145 +0,0 @@
package main
import (
"strings"
"testing"
is "github.com/containers/image/storage"
"github.com/containers/storage"
)
func TestProperImageRefTrue(t *testing.T) {
// Pull an image so we know we have it
err := pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove")
}
// This should match a url path
imgRef, err := properImageRef("docker://busybox:latest")
if err != nil {
t.Errorf("could not match image: %v", err)
} else if imgRef == nil {
t.Error("Returned nil Image Reference")
}
}
func TestProperImageRefFalse(t *testing.T) {
// Pull an image so we know we have it
err := pullTestImage("busybox:latest")
if err != nil {
t.Fatal("could not pull image to remove")
}
// This should match a url path
imgRef, _ := properImageRef("docker://:")
if imgRef != nil {
t.Error("should not have found an Image Reference")
}
}
func TestStorageImageRefTrue(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
options := storage.DefaultStoreOptions
store, err := storage.GetStore(options)
if store != nil {
is.Transport.SetStore(store)
}
if err != nil {
t.Fatalf("could not get store: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
imgRef, err := storageImageRef(store, "busybox")
if err != nil {
t.Errorf("could not match image: %v", err)
} else if imgRef == nil {
t.Error("Returned nil Image Reference")
}
}
func TestStorageImageRefFalse(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
options := storage.DefaultStoreOptions
store, err := storage.GetStore(options)
if store != nil {
is.Transport.SetStore(store)
}
if err != nil {
t.Fatalf("could not get store: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
imgRef, _ := storageImageRef(store, "")
if imgRef != nil {
t.Error("should not have found an Image Reference")
}
}
func TestStorageImageIDTrue(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
options := storage.DefaultStoreOptions
store, err := storage.GetStore(options)
if store != nil {
is.Transport.SetStore(store)
}
if err != nil {
t.Fatalf("could not get store: %v", err)
}
// Pull an image so we know we have it
err = pullTestImage("busybox:latest")
if err != nil {
t.Fatalf("could not pull image to remove: %v", err)
}
//Somehow I have to get the id of the image I just pulled
images, err := store.Images()
if err != nil {
t.Fatalf("Error reading images: %v", err)
}
id, err := captureOutputWithError(func() error {
return outputImages(images, "", store, nil, "busybox:latest", false, false, false, true)
})
if err != nil {
t.Fatalf("Error getting id of image: %v", err)
}
id = strings.TrimSpace(id)
imgRef, err := storageImageID(store, id)
if err != nil {
t.Errorf("could not match image: %v", err)
} else if imgRef == nil {
t.Error("Returned nil Image Reference")
}
}
func TestStorageImageIDFalse(t *testing.T) {
// Make sure the tests are running as root
failTestIfNotRoot(t)
options := storage.DefaultStoreOptions
store, err := storage.GetStore(options)
if store != nil {
is.Transport.SetStore(store)
}
if err != nil {
t.Fatalf("could not get store: %v", err)
}
// Pull an image so we know we have it
id := ""
imgRef, _ := storageImageID(store, id)
if imgRef != nil {
t.Error("should not have returned Image Reference")
}
}

24
libkpod/driver/driver.go Normal file
View file

@ -0,0 +1,24 @@
package driver
import cstorage "github.com/containers/storage"
type DriverData struct {
Name string
Data map[string]string
}
func GetDriverName(store cstorage.Store) (string, error) {
driver, err := store.GraphDriver()
if err != nil {
return "", err
}
return driver.String(), nil
}
func GetDriverMetadata(store cstorage.Store, layerID string) (map[string]string, error) {
driver, err := store.GraphDriver()
if err != nil {
return nil, err
}
return driver.Metadata(layerID)
}

1
libkpod/image/image.go Normal file
View file

@ -0,0 +1 @@
package image

32
libkpod/image/metadata.go Normal file
View file

@ -0,0 +1,32 @@
package image
import (
"encoding/json"
"strings"
"time"
"github.com/containers/image/types"
"github.com/containers/storage"
)
// Metadata stores all of the metadata for an image
type Metadata struct {
Tag string `json:"tag"`
CreatedTime time.Time `json:"created-time"`
ID string `json:"id"`
Blobs []types.BlobInfo `json:"blob-list"`
Layers map[string][]string `json:"layers"`
SignatureSizes []string `json:"signature-sizes"`
}
// ParseMetadata takes an image, parses the json stored in it's metadata
// field, and converts it to a Metadata struct
func ParseMetadata(image storage.Image) (Metadata, error) {
var m Metadata
dec := json.NewDecoder(strings.NewReader(image.Metadata))
if err := dec.Decode(&m); err != nil {
return Metadata{}, err
}
return m, nil
}