Skip to content
This repository was archived by the owner on Mar 27, 2024. It is now read-only.

Commit b089b9b

Browse files
authored
Merge pull request #101 from nkubala/refactor
remove ImagePrepper in favor of processing individual preppers directly
2 parents ec010de + 16b2889 commit b089b9b

17 files changed

+154
-228
lines changed

.travis.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ language: go
22
os: linux
33
go: 1.8.3
44

5+
sudo: required
6+
7+
services:
8+
- docker
9+
510
go_import_path: github.com/GoogleCloudPlatform/container-diff
611

712
addons:

Makefile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ test: $(BUILD_DIR)/$(PROJECT)
6262

6363
.PHONY: integration
6464
integration: $(BUILD_DIR)/$(PROJECT)
65-
go test -v -tags integration $(REPOPATH)/tests
65+
go test -v -tags integration $(REPOPATH)/tests -timeout 20m
6666

6767
.PHONY: release
6868
release: cross
@@ -71,5 +71,3 @@ release: cross
7171
.PHONY: clean
7272
clean:
7373
rm -rf $(BUILD_DIR)
74-
75-

cmd/analyze.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,24 @@ func checkAnalyzeArgNum(args []string) error {
5656
return nil
5757
}
5858

59-
func analyzeImage(imageArg string, analyzerArgs []string) error {
59+
func analyzeImage(imageName string, analyzerArgs []string) error {
6060
analyzeTypes, err := differs.GetAnalyzers(analyzerArgs)
6161
if err != nil {
6262
return err
6363
}
6464

65-
cli, err := NewClient()
65+
cli, err := pkgutil.NewClient()
6666
if err != nil {
6767
return fmt.Errorf("Error getting docker client: %s", err)
6868
}
6969
defer cli.Close()
70-
ip := pkgutil.ImagePrepper{
71-
Source: imageArg,
72-
Client: cli,
70+
71+
prepper, err := getPrepperForImage(imageName)
72+
if err != nil {
73+
return err
7374
}
74-
image, err := ip.GetImage()
75+
76+
image, err := prepper.GetImage()
7577

7678
if !save {
7779
defer pkgutil.CleanupImage(image)

cmd/diff.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func diffImages(image1Arg, image2Arg string, diffArgs []string) error {
6363
return err
6464
}
6565

66-
cli, err := NewClient()
66+
cli, err := pkgutil.NewClient()
6767
if err != nil {
6868
return err
6969
}
@@ -77,17 +77,20 @@ func diffImages(image1Arg, image2Arg string, diffArgs []string) error {
7777
image1Arg: {},
7878
image2Arg: {},
7979
}
80+
// TODO: fix error handling here
8081
for imageArg := range imageMap {
8182
go func(imageName string, imageMap map[string]*pkgutil.Image) {
8283
defer wg.Done()
83-
ip := pkgutil.ImagePrepper{
84-
Source: imageName,
85-
Client: cli,
84+
85+
prepper, err := getPrepperForImage(imageName)
86+
if err != nil {
87+
glog.Error(err)
88+
return
8689
}
87-
image, err := ip.GetImage()
90+
image, err := prepper.GetImage()
8891
imageMap[imageName] = &image
8992
if err != nil {
90-
glog.Errorf("Diff may be inaccurate: %s", err.Error())
93+
glog.Warningf("Diff may be inaccurate: %s", err)
9194
}
9295
}(imageArg, imageMap)
9396
}
@@ -109,7 +112,6 @@ func diffImages(image1Arg, image2Arg string, diffArgs []string) error {
109112
if save {
110113
glog.Infof("Images were saved at %s and %s", imageMap[image1Arg].FSPath,
111114
imageMap[image2Arg].FSPath)
112-
113115
}
114116
return nil
115117
}

cmd/root.go

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ limitations under the License.
1717
package cmd
1818

1919
import (
20-
"context"
20+
"errors"
2121
goflag "flag"
2222
"fmt"
2323
"sort"
2424
"strings"
2525

2626
"github.com/GoogleCloudPlatform/container-diff/differs"
27+
pkgutil "github.com/GoogleCloudPlatform/container-diff/pkg/util"
2728
"github.com/GoogleCloudPlatform/container-diff/util"
2829
"github.com/docker/docker/client"
2930
"github.com/golang/glog"
@@ -37,20 +38,22 @@ var types string
3738

3839
type validatefxn func(args []string) error
3940

41+
const (
42+
DaemonPrefix = "daemon://"
43+
RemotePrefix = "remote://"
44+
)
45+
4046
var RootCmd = &cobra.Command{
4147
Use: "container-diff",
4248
Short: "container-diff is a tool for analyzing and comparing container images",
43-
Long: `container-diff is a CLI tool for analyzing and comparing container images.`,
44-
}
49+
Long: `container-diff is a CLI tool for analyzing and comparing container images.
4550
46-
func NewClient() (*client.Client, error) {
47-
cli, err := client.NewEnvClient()
48-
if err != nil {
49-
return nil, fmt.Errorf("Error getting docker client: %s", err)
50-
}
51-
cli.NegotiateAPIVersion(context.Background())
51+
Images can be specified from either a local Docker daemon, or from a remote registry.
52+
To specify a local image, prefix the image ID with 'daemon://', e.g. 'daemon://gcr.io/foo/bar'.
53+
To specify a remote image, prefix the image ID with 'remote://', e.g. 'remote://gcr.io/foo/bar'.
54+
If no prefix is specified, the local daemon will be checked first.
5255
53-
return cli, nil
56+
Tarballs can also be specified by simply providing the path to the .tar, .tar.gz, or .tgz file.`,
5457
}
5558

5659
func outputResults(resultMap map[string]util.Result) {
@@ -92,7 +95,7 @@ func validateArgs(args []string, validatefxns ...validatefxn) error {
9295

9396
func checkIfValidAnalyzer(flagtypes string) error {
9497
if flagtypes == "" {
95-
return nil
98+
return errors.New("Please provide at least one analyzer to run")
9699
}
97100
analyzers := strings.Split(flagtypes, ",")
98101
for _, name := range analyzers {
@@ -103,6 +106,30 @@ func checkIfValidAnalyzer(flagtypes string) error {
103106
return nil
104107
}
105108

109+
func getPrepperForImage(image string) (pkgutil.Prepper, error) {
110+
cli, err := client.NewEnvClient()
111+
if err != nil {
112+
return nil, err
113+
}
114+
if pkgutil.IsTar(image) {
115+
return pkgutil.TarPrepper{
116+
Source: image,
117+
Client: cli,
118+
}, nil
119+
120+
} else if strings.HasPrefix(image, DaemonPrefix) {
121+
return pkgutil.DaemonPrepper{
122+
Source: strings.Replace(image, DaemonPrefix, "", -1),
123+
Client: cli,
124+
}, nil
125+
}
126+
// either has remote prefix or has no prefix, in which case we force remote
127+
return pkgutil.CloudPrepper{
128+
Source: strings.Replace(image, RemotePrefix, "", -1),
129+
Client: cli,
130+
}, nil
131+
}
132+
106133
func init() {
107134
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
108135
}

pkg/util/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ go_library(
88
"docker_utils.go",
99
"fs_utils.go",
1010
"image_prep_utils.go",
11-
"image_prepper.go",
1211
"image_utils.go",
1312
"tar_prepper.go",
1413
"tar_utils.go",

pkg/util/cloud_prepper.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,26 @@ limitations under the License.
1717
package util
1818

1919
import (
20-
"regexp"
21-
2220
"github.com/containers/image/docker"
21+
"github.com/docker/docker/client"
2322
)
2423

2524
// CloudPrepper prepares images sourced from a Cloud registry
2625
type CloudPrepper struct {
27-
ImagePrepper
26+
Source string
27+
Client *client.Client
2828
}
2929

3030
func (p CloudPrepper) Name() string {
3131
return "Cloud Registry"
3232
}
3333

3434
func (p CloudPrepper) GetSource() string {
35-
return p.ImagePrepper.Source
35+
return p.Source
3636
}
3737

38-
func (p CloudPrepper) SupportsImage() bool {
39-
pattern := regexp.MustCompile("^.+/.+(:.+){0,1}$")
40-
image := p.ImagePrepper.Source
41-
if exp := pattern.FindString(image); exp != image || CheckTar(image) {
42-
return false
43-
}
44-
return true
38+
func (p CloudPrepper) GetImage() (Image, error) {
39+
return getImage(p)
4540
}
4641

4742
func (p CloudPrepper) GetFileSystem() (string, error) {

pkg/util/daemon_prepper.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,28 @@ package util
1818

1919
import (
2020
"context"
21-
"regexp"
2221

2322
"github.com/containers/image/docker/daemon"
23+
24+
"github.com/docker/docker/client"
2425
"github.com/golang/glog"
2526
)
2627

2728
type DaemonPrepper struct {
28-
ImagePrepper
29+
Source string
30+
Client *client.Client
2931
}
3032

3133
func (p DaemonPrepper) Name() string {
3234
return "Local Daemon"
3335
}
3436

3537
func (p DaemonPrepper) GetSource() string {
36-
return p.ImagePrepper.Source
38+
return p.Source
3739
}
3840

39-
func (p DaemonPrepper) SupportsImage() bool {
40-
pattern := regexp.MustCompile("[a-z|0-9]{12}")
41-
if exp := pattern.FindString(p.ImagePrepper.Source); exp != p.ImagePrepper.Source {
42-
return false
43-
}
44-
return true
41+
func (p DaemonPrepper) GetImage() (Image, error) {
42+
return getImage(p)
4543
}
4644

4745
func (p DaemonPrepper) GetFileSystem() (string, error) {

pkg/util/docker_utils.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ type Event struct {
3939
} `json:"progressDetail"`
4040
}
4141

42+
func NewClient() (*client.Client, error) {
43+
cli, err := client.NewEnvClient()
44+
if err != nil {
45+
return nil, fmt.Errorf("Error getting docker client: %s", err)
46+
}
47+
cli.NegotiateAPIVersion(context.Background())
48+
49+
return cli, nil
50+
}
51+
4252
func getLayersFromManifest(manifestPath string) ([]string, error) {
4353
type Manifest struct {
4454
Layers []string

pkg/util/image_prep_utils.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"archive/tar"
2121
"encoding/json"
2222
"errors"
23+
"fmt"
2324
"io/ioutil"
2425
"os"
2526
"path/filepath"
@@ -30,10 +31,12 @@ import (
3031
"github.com/golang/glog"
3132
)
3233

33-
var orderedPreppers = []func(ip ImagePrepper) Prepper{
34-
func(ip ImagePrepper) Prepper { return DaemonPrepper{ImagePrepper: ip} },
35-
func(ip ImagePrepper) Prepper { return CloudPrepper{ImagePrepper: ip} },
36-
func(ip ImagePrepper) Prepper { return TarPrepper{ImagePrepper: ip} },
34+
type Prepper interface {
35+
Name() string
36+
GetConfig() (ConfigSchema, error)
37+
GetFileSystem() (string, error)
38+
GetImage() (Image, error)
39+
GetSource() string
3740
}
3841

3942
type Image struct {
@@ -55,6 +58,27 @@ type ConfigSchema struct {
5558
History []ImageHistoryItem `json:"history"`
5659
}
5760

61+
func getImage(p Prepper) (Image, error) {
62+
glog.Infof("Retrieving image %s from source %s", p.GetSource(), p.Name())
63+
imgPath, err := p.GetFileSystem()
64+
if err != nil {
65+
return Image{}, err
66+
}
67+
68+
config, err := p.GetConfig()
69+
if err != nil {
70+
glog.Error("Error retrieving History: ", err)
71+
}
72+
73+
glog.Infof("Finished prepping image %s", p.GetSource())
74+
return Image{
75+
Source: p.GetSource(),
76+
FSPath: imgPath,
77+
Config: config,
78+
}, nil
79+
return Image{}, fmt.Errorf("Could not retrieve image %s from source", p.GetSource())
80+
}
81+
5882
func getImageFromTar(tarPath string) (string, error) {
5983
glog.Info("Extracting image tar to obtain image file system")
6084
path := strings.TrimSuffix(tarPath, filepath.Ext(tarPath))

0 commit comments

Comments
 (0)