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

Commit f92bed7

Browse files
authored
Merge pull request #164 from vrothberg/fix-remote-rpm
RPMAnalzyer: download absent `remote://` images
2 parents 72c8435 + 7fd20e1 commit f92bed7

File tree

6 files changed

+97
-4
lines changed

6 files changed

+97
-4
lines changed

differs/rpm_diff.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func (a RPMAnalyzer) getPackages(image pkgutil.Image) (map[string]util.PackageIn
8080
if _, err := os.Stat(rpmBinary); err != nil {
8181
rpmBinary = filepath.Join(path, "usr/bin/rpm")
8282
if _, err = os.Stat(rpmBinary); err != nil {
83+
logrus.Errorf("Could not detect RPM binary in unpacked image %s", image.Source)
8384
return packages, nil
8485
}
8586
}
@@ -99,7 +100,7 @@ func rpmDataFromContainer(image pkgutil.Image) (map[string]util.PackageInfo, err
99100

100101
// if image is a tar archive, we need to load it
101102
imageName := image.Source
102-
if pkgutil.IsTar(imageName) {
103+
if image.IsTar() {
103104
// NOTE: all work below is only required for multilayer tar
104105
// archives generated by `docker save`. Flat file-system
105106
// archives generated by `docker create` can just be imported
@@ -123,6 +124,33 @@ func rpmDataFromContainer(image pkgutil.Image) (map[string]util.PackageInfo, err
123124

124125
defer client.RemoveImage(imageName)
125126
defer logrus.Infof("Removing image %s", imageName)
127+
} else if image.IsCloud() {
128+
// if it's a remote image we pull it unconditionally and avoid
129+
// name/tag conflicts by pulling it via its sha256 digest
130+
var buf bytes.Buffer
131+
digest, err := image.GetRemoteDigest()
132+
if err != nil {
133+
return packages, err
134+
}
135+
imageName = image.GetName() + "@" + digest
136+
logrus.Infof("Pulling remote image %s", imageName)
137+
pullOpts := godocker.PullImageOptions{
138+
Repository: imageName,
139+
OutputStream: &buf,
140+
}
141+
if err := client.PullImage(pullOpts, godocker.AuthConfiguration{}); err != nil {
142+
return packages, fmt.Errorf("Error pulling remote image %s: %s", imageName, err)
143+
}
144+
// log PullImage() output in debug mode
145+
if logrus.GetLevel() == logrus.DebugLevel {
146+
// log each line separately for consistency
147+
for _, out := range strings.Split(buf.String(), "\n") {
148+
if len(out) > 0 {
149+
logrus.Debug(out)
150+
}
151+
}
152+
}
153+
defer client.RemoveImage(imageName)
126154
}
127155

128156
contConf := godocker.Config{

pkg/util/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ go_library(
1919
"//vendor/github.com/containers/image/docker:go_default_library",
2020
"//vendor/github.com/containers/image/docker/daemon:go_default_library",
2121
"//vendor/github.com/containers/image/docker/tarfile:go_default_library",
22+
"//vendor/github.com/containers/image/manifest:go_default_library",
2223
"//vendor/github.com/containers/image/pkg/compression:go_default_library",
2324
"//vendor/github.com/containers/image/types:go_default_library",
2425
"//vendor/github.com/docker/docker/client:go_default_library",

pkg/util/cloud_prepper.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ func (p CloudPrepper) GetSource() string {
3838
}
3939

4040
func (p CloudPrepper) GetImage() (Image, error) {
41-
return getImage(p)
41+
image, err := getImage(p)
42+
image.Type = ImageTypeCloud
43+
return image, err
4244
}
4345

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

pkg/util/daemon_prepper.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ func (p DaemonPrepper) GetSource() string {
4141
}
4242

4343
func (p DaemonPrepper) GetImage() (Image, error) {
44-
return getImage(p)
44+
image, err := getImage(p)
45+
image.Type = ImageTypeDaemon
46+
return image, err
4547
}
4648

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

pkg/util/image_prep_utils.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
"strings"
2828

2929
"github.com/GoogleCloudPlatform/container-diff/pkg/cache"
30+
"github.com/containers/image/docker"
31+
"github.com/containers/image/manifest"
3032
"github.com/containers/image/pkg/compression"
3133
"github.com/containers/image/types"
3234
"github.com/sirupsen/logrus"
@@ -40,10 +42,43 @@ type Prepper interface {
4042
GetSource() string
4143
}
4244

45+
type ImageType int
46+
47+
const (
48+
ImageTypeTar ImageType = iota
49+
ImageTypeDaemon
50+
ImageTypeCloud
51+
)
52+
4353
type Image struct {
4454
Source string
4555
FSPath string
4656
Config ConfigSchema
57+
Type ImageType
58+
}
59+
60+
func (i *Image) IsTar() bool {
61+
return i.Type == ImageTypeTar
62+
}
63+
64+
func (i *Image) IsDaemon() bool {
65+
return i.Type == ImageTypeDaemon
66+
}
67+
68+
func (i *Image) IsCloud() bool {
69+
return i.Type == ImageTypeCloud
70+
}
71+
72+
func (i *Image) GetRemoteDigest() (string, error) {
73+
ref, err := docker.ParseReference("//" + i.Source)
74+
if err != nil {
75+
return "", err
76+
}
77+
return getDigestFromReference(ref, i.Source)
78+
}
79+
80+
func (i *Image) GetName() string {
81+
return strings.Split(i.Source, ":")[0]
4782
}
4883

4984
type ImageHistoryItem struct {
@@ -167,6 +202,29 @@ func getFileSystemFromReference(ref types.ImageReference, imageName string, cach
167202
return path, nil
168203
}
169204

205+
func getDigestFromReference(ref types.ImageReference, source string) (string, error) {
206+
img, err := ref.NewImage(nil)
207+
if err != nil {
208+
logrus.Errorf("Error referencing image %s from registry: %s", source, err)
209+
return "", errors.New("Could not obtain image digest")
210+
}
211+
defer img.Close()
212+
213+
rawManifest, _, err := img.Manifest()
214+
if err != nil {
215+
logrus.Errorf("Error referencing image %s from registry: %s", source, err)
216+
return "", errors.New("Could not obtain image digest")
217+
}
218+
219+
digest, err := manifest.Digest(rawManifest)
220+
if err != nil {
221+
logrus.Errorf("Error referencing image %s from registry: %s", source, err)
222+
return "", errors.New("Could not obtain image digest")
223+
}
224+
225+
return digest.String(), nil
226+
}
227+
170228
func getConfigFromReference(ref types.ImageReference, source string) (ConfigSchema, error) {
171229
img, err := ref.NewImage(nil)
172230
if err != nil {

pkg/util/tar_prepper.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ func (p TarPrepper) GetSource() string {
4444
}
4545

4646
func (p TarPrepper) GetImage() (Image, error) {
47-
return getImage(p)
47+
image, err := getImage(p)
48+
image.Type = ImageTypeTar
49+
return image, err
4850
}
4951

5052
func (p TarPrepper) GetFileSystem() (string, error) {

0 commit comments

Comments
 (0)