Skip to content

Commit 237e0d7

Browse files
Merge pull request #121 from kevinrizza/fix-docker-image-unpack
Make imagereader work for all layer paths
2 parents 5d342b2 + ab7034f commit 237e0d7

File tree

13 files changed

+6086
-22
lines changed

13 files changed

+6086
-22
lines changed

pkg/containertools/containertoolsfakes/fake_image_reader.go

Lines changed: 10 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package containertools
2+
3+
type GetImageDataOptions struct {
4+
WorkingDir string
5+
}
6+
7+
type GetImageDataOption func(*GetImageDataOptions)
8+
9+
10+
func WithWorkingDir(workingDir string) GetImageDataOption {
11+
return func(o *GetImageDataOptions) {
12+
o.WorkingDir = workingDir
13+
}
14+
}

pkg/containertools/imagereader.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,29 @@ type imageManifest struct {
2525
}
2626

2727
type ImageReader interface {
28-
GetImageData(string, string) error
28+
GetImageData(string, string, ...GetImageDataOption) error
2929
}
3030

3131
type ImageLayerReader struct {
32-
Cmd CommandRunner
32+
Cmd CommandRunner
3333
Logger *logrus.Entry
3434
}
3535

3636
func NewImageReader(containerTool string, logger *logrus.Entry) ImageReader {
3737
cmd := NewCommandRunner(containerTool, logger)
3838

3939
return &ImageLayerReader{
40-
Cmd: cmd,
40+
Cmd: cmd,
4141
Logger: logger,
4242
}
4343
}
4444

45-
func (b ImageLayerReader) GetImageData(image, outputDir string) error {
45+
func (b ImageLayerReader) GetImageData(image, outputDir string, opts ...GetImageDataOption) error {
46+
options := GetImageDataOptions{}
47+
for _, o := range opts {
48+
o(&options)
49+
}
50+
4651
// Create the output directory if it doesn't exist
4752
if _, err := os.Stat(outputDir); os.IsNotExist(err) {
4853
os.Mkdir(outputDir, 0777)
@@ -53,11 +58,14 @@ func (b ImageLayerReader) GetImageData(image, outputDir string) error {
5358
return err
5459
}
5560

56-
workingDir, err := ioutil.TempDir("./", "bundle_staging_")
57-
if err != nil {
58-
return err
61+
workingDir := options.WorkingDir
62+
if workingDir == "" {
63+
workingDir, err := ioutil.TempDir("./", "bundle_staging_")
64+
if err != nil {
65+
return err
66+
}
67+
defer os.RemoveAll(workingDir)
5968
}
60-
defer os.RemoveAll(workingDir)
6169

6270
rootTarfile := filepath.Join(workingDir, "bundle.tar")
6371

@@ -77,7 +85,7 @@ func (b ImageLayerReader) GetImageData(image, outputDir string) error {
7785
if err != nil {
7886
return err
7987
}
80-
88+
8189
// Untar the image layer tarballs and push the bundle manifests to the output directory
8290
for _, tarball := range layerTarballs {
8391
f, err = os.Open(rootTarfile)
@@ -143,18 +151,16 @@ func extractBundleManifests(layerTarball, outputDir string, tarReader *tar.Reade
143151

144152
if header.Typeflag == tar.TypeReg {
145153
if header.Name == layerTarball {
146-
// Found the embedded top layer tarball
154+
// Found the embedded tarball for the layer
147155
layerReader := tar.NewReader(tarReader)
148156

149157
err = extractTarballToDir(outputDir, layerReader)
150158
if err != nil {
151159
return err
152160
}
153-
}
154161

155-
continue
156-
} else {
157-
return nil
162+
return nil
163+
}
158164
}
159165
}
160166
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package containertools_test
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"testing"
10+
11+
"github.com/operator-framework/operator-registry/pkg/containertools"
12+
"github.com/operator-framework/operator-registry/pkg/containertools/containertoolsfakes"
13+
14+
"github.com/sirupsen/logrus"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
const (
19+
expectedFilePath = "testdata/expected_unpack"
20+
)
21+
22+
func TestReadImageLayersDocker(t *testing.T) {
23+
image := "quay.io/operator-framework/example"
24+
testWorkingDir := "testdata/docker"
25+
testOutputDir := "testdata/output"
26+
27+
expectedFiles, err := helperGetExpectedFiles()
28+
29+
logger := logrus.NewEntry(logrus.New())
30+
mockCmd := containertoolsfakes.FakeCommandRunner{}
31+
32+
mockCmd.PullReturns(nil)
33+
mockCmd.SaveReturns(nil)
34+
35+
imageReader := containertools.ImageLayerReader{
36+
Cmd: &mockCmd,
37+
Logger: logger,
38+
}
39+
40+
err = imageReader.GetImageData(image, testOutputDir, containertools.WithWorkingDir(testWorkingDir))
41+
require.NoError(t, err)
42+
43+
for _, file := range expectedFiles {
44+
expectedFilePath := filepath.Join(expectedFilePath, file)
45+
expectedFile, err := ioutil.ReadFile(expectedFilePath)
46+
require.NoError(t, err)
47+
48+
actualFilePath := filepath.Join(testOutputDir, file)
49+
actualFile, err := ioutil.ReadFile(actualFilePath)
50+
require.NoError(t, err)
51+
52+
require.Equal(t, string(expectedFile), string(actualFile))
53+
}
54+
55+
err = os.RemoveAll(testOutputDir)
56+
require.NoError(t, err)
57+
}
58+
59+
func TestReadImageLayersPodman(t *testing.T) {
60+
image := "quay.io/operator-framework/example"
61+
testWorkingDir := "testdata/podman"
62+
testOutputDir := "testdata/output"
63+
64+
expectedFiles, err := helperGetExpectedFiles()
65+
66+
logger := logrus.NewEntry(logrus.New())
67+
mockCmd := containertoolsfakes.FakeCommandRunner{}
68+
69+
mockCmd.PullReturns(nil)
70+
mockCmd.SaveReturns(nil)
71+
72+
imageReader := containertools.ImageLayerReader{
73+
Cmd: &mockCmd,
74+
Logger: logger,
75+
}
76+
77+
err = imageReader.GetImageData(image, testOutputDir, containertools.WithWorkingDir(testWorkingDir))
78+
require.NoError(t, err)
79+
80+
for _, file := range expectedFiles {
81+
expectedFilePath := filepath.Join(expectedFilePath, file)
82+
expectedFile, err := ioutil.ReadFile(expectedFilePath)
83+
require.NoError(t, err)
84+
85+
actualFilePath := filepath.Join(testOutputDir, file)
86+
actualFile, err := ioutil.ReadFile(actualFilePath)
87+
require.NoError(t, err)
88+
89+
require.Equal(t, string(expectedFile), string(actualFile))
90+
}
91+
92+
err = os.RemoveAll(testOutputDir)
93+
require.NoError(t, err)
94+
}
95+
96+
func TestReadImageLayers_PullError(t *testing.T) {
97+
image := "quay.io/operator-framework/example"
98+
testOutputDir := "testdata/output"
99+
100+
logger := logrus.NewEntry(logrus.New())
101+
mockCmd := containertoolsfakes.FakeCommandRunner{}
102+
103+
mockCmd.PullReturns(fmt.Errorf("Unable to pull image"))
104+
105+
imageReader := containertools.ImageLayerReader{
106+
Cmd: &mockCmd,
107+
Logger: logger,
108+
}
109+
110+
err := imageReader.GetImageData(image, testOutputDir)
111+
require.Error(t, err)
112+
}
113+
114+
func TestReadImageLayers_SaveError(t *testing.T) {
115+
image := "quay.io/operator-framework/example"
116+
testOutputDir := "testdata/output"
117+
118+
logger := logrus.NewEntry(logrus.New())
119+
mockCmd := containertoolsfakes.FakeCommandRunner{}
120+
121+
mockCmd.PullReturns(nil)
122+
mockCmd.SaveReturns(fmt.Errorf("Unable to save image"))
123+
124+
imageReader := containertools.ImageLayerReader{
125+
Cmd: &mockCmd,
126+
Logger: logger,
127+
}
128+
129+
err := imageReader.GetImageData(image, testOutputDir)
130+
require.Error(t, err)
131+
}
132+
133+
func helperGetExpectedFiles() ([]string, error) {
134+
var files []string
135+
136+
err := filepath.Walk(expectedFilePath, func(path string, f os.FileInfo, err error) error {
137+
if !f.IsDir() {
138+
fileName := strings.Replace(path, expectedFilePath, "", -1)
139+
files = append(files, fileName)
140+
}
141+
return nil
142+
})
143+
144+
return files, err
145+
}
366 KB
Binary file not shown.

0 commit comments

Comments
 (0)