diff --git a/cmd/kpod/common.go b/cmd/kpod/common.go index 75eebc18..b5d841aa 100644 --- a/cmd/kpod/common.go +++ b/cmd/kpod/common.go @@ -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 } diff --git a/cmd/kpod/common_test.go b/cmd/kpod/common_test.go index 3ec33658..08e23176 100644 --- a/cmd/kpod/common_test.go +++ b/cmd/kpod/common_test.go @@ -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) diff --git a/cmd/kpod/containerData.go b/cmd/kpod/containerData.go index 2ecc00e9..0a61f692 100644 --- a/cmd/kpod/containerData.go +++ b/cmd/kpod/containerData.go @@ -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 } diff --git a/cmd/kpod/imageData.go b/cmd/kpod/imageData.go index 1419ecd9..502bac22 100644 --- a/cmd/kpod/imageData.go +++ b/cmd/kpod/imageData.go @@ -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 } diff --git a/cmd/kpod/images.go b/cmd/kpod/images.go index d2a8dc48..be58bc0b 100644 --- a/cmd/kpod/images.go +++ b/cmd/kpod/images.go @@ -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 "" as the image name names = append(names, "") } 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, diff --git a/cmd/kpod/images_test.go b/cmd/kpod/images_test.go deleted file mode 100644 index e714166d..00000000 --- a/cmd/kpod/images_test.go +++ /dev/null @@ -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("", "true") { - t.Error("matchesDangling() should return true with dangling=true and name=") - } - - 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("", "false") { - t.Error("matchesDangling() should return false with dangling=false and name=") - } -} - -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() -} diff --git a/cmd/kpod/rmi_test.go b/cmd/kpod/rmi_test.go deleted file mode 100644 index c10c8eeb..00000000 --- a/cmd/kpod/rmi_test.go +++ /dev/null @@ -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") - } -} diff --git a/libkpod/driver/driver.go b/libkpod/driver/driver.go new file mode 100644 index 00000000..d49008b6 --- /dev/null +++ b/libkpod/driver/driver.go @@ -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) +} diff --git a/libkpod/image/image.go b/libkpod/image/image.go new file mode 100644 index 00000000..1da0d734 --- /dev/null +++ b/libkpod/image/image.go @@ -0,0 +1 @@ +package image diff --git a/libkpod/image/metadata.go b/libkpod/image/metadata.go new file mode 100644 index 00000000..53a1cc47 --- /dev/null +++ b/libkpod/image/metadata.go @@ -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 +}