Skip to content
This repository was archived by the owner on Dec 2, 2020. It is now read-only.

Commit 0941938

Browse files
committed
Combine extraction logic
1 parent 3fad6dd commit 0941938

File tree

2 files changed

+131
-136
lines changed

2 files changed

+131
-136
lines changed

img2lambda/extract/repack_image.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package extract
22

33
import (
4+
"archive/tar"
45
"context"
56
"fmt"
7+
"io"
68
"log"
79
"os"
810
"path/filepath"
11+
"strings"
912

1013
"github.com/awslabs/aws-lambda-container-image-converter/img2lambda/types"
1114
"github.com/containers/image/image"
1215
"github.com/containers/image/pkg/blobinfocache"
1316
"github.com/containers/image/transports/alltransports"
1417
imgtypes "github.com/containers/image/types"
18+
zglob "github.com/mattn/go-zglob"
19+
"github.com/mholt/archiver"
1520
"github.com/pkg/errors"
1621
)
1722

@@ -25,6 +30,10 @@ func RepackImage(imageName string, layerOutputDir string) (layers []types.Lambda
2530
return nil, err
2631
}
2732

33+
return repackImage(ref, imageName, layerOutputDir)
34+
}
35+
36+
func repackImage(ref imgtypes.ImageReference, imageName string, layerOutputDir string) (layers []types.LambdaLayer, retErr error) {
2837
sys := &imgtypes.SystemContext{}
2938

3039
ctx := context.Background()
@@ -88,3 +97,125 @@ func RepackImage(imageName string, layerOutputDir string) (layers []types.Lambda
8897

8998
return layers, nil
9099
}
100+
101+
// Converts container image layer archive (tar) to Lambda layer archive (zip).
102+
// Filters files from the source and only writes a new archive if at least
103+
// one file in the source matches the filter (i.e. does not create empty archives).
104+
func repackLayer(outputFilename string, layerContents io.Reader) (created bool, retError error) {
105+
t := archiver.NewTar()
106+
107+
err := t.Open(layerContents, 0)
108+
if err != nil {
109+
return false, fmt.Errorf("opening layer tar: %v", err)
110+
}
111+
defer t.Close()
112+
113+
// Walk the files in the tar
114+
var z *archiver.Zip
115+
var out *os.File
116+
defer func() {
117+
if z != nil {
118+
if err := z.Close(); err != nil {
119+
retError = errors.Wrapf(err, " (zip close error: %v)", err)
120+
}
121+
}
122+
if out != nil {
123+
if err := out.Close(); err != nil {
124+
retError = errors.Wrapf(err, " (file close error: %v)", err)
125+
}
126+
}
127+
}()
128+
129+
for {
130+
// Get next file in tar
131+
f, err := t.Read()
132+
if err == io.EOF {
133+
break
134+
}
135+
136+
if err != nil {
137+
return false, fmt.Errorf("opening next file in layer tar: %v", err)
138+
}
139+
140+
// Determine if this file should be repacked
141+
repack, err := shouldRepackLayerFile(f)
142+
if err != nil {
143+
return false, fmt.Errorf("filtering file in layer tar: %v", err)
144+
}
145+
if repack {
146+
if z == nil {
147+
z, out, err = startZipFile(outputFilename)
148+
if err != nil {
149+
return false, fmt.Errorf("starting zip file: %v", err)
150+
}
151+
}
152+
153+
err = repackLayerFile(f, z)
154+
}
155+
156+
if err != nil {
157+
return false, fmt.Errorf("walking %s in layer tar: %v", f.Name(), err)
158+
}
159+
}
160+
161+
return (z != nil), nil
162+
}
163+
164+
func startZipFile(destination string) (zip *archiver.Zip, zipFile *os.File, err error) {
165+
z := archiver.NewZip()
166+
167+
out, err := os.Create(destination)
168+
if err != nil {
169+
return nil, nil, fmt.Errorf("creating %s: %v", destination, err)
170+
}
171+
172+
err = z.Create(out)
173+
if err != nil {
174+
return nil, nil, fmt.Errorf("creating zip: %v", err)
175+
}
176+
177+
return z, out, nil
178+
}
179+
180+
func shouldRepackLayerFile(f archiver.File) (should bool, err error) {
181+
header, ok := f.Header.(*tar.Header)
182+
if !ok {
183+
return false, fmt.Errorf("expected header to be *tar.Header but was %T", f.Header)
184+
}
185+
186+
if f.IsDir() || header.Typeflag == tar.TypeDir {
187+
return false, nil
188+
}
189+
190+
// Ignore whiteout files
191+
if strings.HasPrefix(f.Name(), ".wh.") {
192+
return false, nil
193+
}
194+
195+
// Only extract files that can be used for Lambda custom runtimes
196+
return zglob.Match("opt/**/**", header.Name)
197+
}
198+
199+
func repackLayerFile(f archiver.File, z *archiver.Zip) error {
200+
hdr, ok := f.Header.(*tar.Header)
201+
if !ok {
202+
return fmt.Errorf("expected header to be *tar.Header but was %T", f.Header)
203+
}
204+
205+
filename := strings.TrimPrefix(filepath.ToSlash(hdr.Name), "opt/")
206+
207+
switch hdr.Typeflag {
208+
case tar.TypeReg, tar.TypeRegA, tar.TypeChar, tar.TypeBlock, tar.TypeFifo, tar.TypeSymlink, tar.TypeLink:
209+
return z.Write(archiver.File{
210+
FileInfo: archiver.FileInfo{
211+
FileInfo: f.FileInfo,
212+
CustomName: filename,
213+
},
214+
ReadCloser: f,
215+
})
216+
case tar.TypeXGlobalHeader:
217+
return nil // ignore
218+
default:
219+
return fmt.Errorf("%s: unknown type flag: %c", hdr.Name, hdr.Typeflag)
220+
}
221+
}

img2lambda/extract/repack_layer.go

Lines changed: 0 additions & 136 deletions
This file was deleted.

0 commit comments

Comments
 (0)