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

Commit aad6f8a

Browse files
committed
Initial stab at walking the layer tar file
1 parent d20dd3f commit aad6f8a

File tree

2 files changed

+96
-16
lines changed

2 files changed

+96
-16
lines changed

main.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"log"
77
"os"
8-
"os/exec"
98
"path/filepath"
109

1110
"github.com/containers/image/image"
@@ -23,6 +22,7 @@ func main() {
2322
}
2423
}
2524

25+
// Converts container image to Lambda layers
2626
func ConvertImage(name string) (retErr error) {
2727
// Get image's layer data from image name
2828
ref, err := alltransports.ParseImageName(name)
@@ -57,35 +57,35 @@ func ConvertImage(name string) (retErr error) {
5757

5858
layerInfos := src.LayerInfos()
5959

60+
// Unpack and inspect each image layer, copy relevant files to new Lambda layer
6061
dir, err := os.Getwd()
6162
if err != nil {
6263
log.Fatal(err)
6364
}
65+
layerOutputDir := filepath.Join(dir, "image-output", name)
66+
if err := os.MkdirAll(layerOutputDir, 0777); err != nil {
67+
return err
68+
}
69+
70+
lambdaLayerNum := 1
6471

65-
// Unpack each layer onto disk
6672
for _, layerInfo := range layerInfos {
67-
blobStream, _, err := rawSource.GetBlob(ctx, layerInfo, cache)
73+
lambdaLayerFilename := filepath.Join(layerOutputDir, fmt.Sprintf("layer-%d.zip", lambdaLayerNum))
74+
75+
layerStream, _, err := rawSource.GetBlob(ctx, layerInfo, cache)
6876
if err != nil {
6977
return err
7078
}
79+
defer layerStream.Close()
7180

72-
imageDir := filepath.Join(dir, "image-output", name, string(layerInfo.Digest))
73-
74-
if err := os.MkdirAll(imageDir, 0777); err != nil {
81+
fileCreated, err := RepackLayer(lambdaLayerFilename, layerStream, "opt/**/**")
82+
if err != nil {
7583
return err
7684
}
7785

78-
fmt.Printf("Layer %s, size %d, media type %s\n", layerInfo.Digest, layerInfo.Size, layerInfo.MediaType)
79-
fmt.Printf("Dir %s\n", imageDir)
80-
81-
tarCmd := exec.Command("tar", "-p", "-x", "-C", imageDir)
82-
tarCmd.Stdin = blobStream
83-
if output, err := tarCmd.CombinedOutput(); err != nil {
84-
fmt.Printf("combined out:\n%s\n", string(output))
85-
return err
86+
if fileCreated {
87+
lambdaLayerNum++
8688
}
87-
88-
blobStream.Close()
8989
}
9090

9191
return nil

repack_layer.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package main
2+
3+
import (
4+
"archive/tar"
5+
"fmt"
6+
"io"
7+
"log"
8+
"strings"
9+
10+
zglob "github.com/mattn/go-zglob"
11+
"github.com/mholt/archiver"
12+
)
13+
14+
// Converts container image layer archive (tar) to Lambda layer archive (zip).
15+
// Filters files from the source and only writes a new archive if at least
16+
// one file in the source matches the filter (i.e. does not create empty archives).
17+
func RepackLayer(outputFilename string, layerContents io.Reader, filterPattern string) (created bool, err error) {
18+
// TODO: support image types other than local Docker images (docker-daemon transport),
19+
// where the layer format is tar. For example, layers directly from a Docker registry
20+
// will be .tar.gz-formatted. OCI images can be either tar or tar.gz, based on the
21+
// layer's media type.
22+
t := archiver.NewTar()
23+
24+
err = t.Open(layerContents, 0)
25+
if err != nil {
26+
return false, fmt.Errorf("opening layer tar: %v", err)
27+
}
28+
defer t.Close()
29+
30+
// Walk the files in the tar
31+
for {
32+
// Get next file in tar
33+
f, err := t.Read()
34+
if err == io.EOF {
35+
break
36+
}
37+
38+
if err != nil {
39+
return false, fmt.Errorf("opening next file in layer tar: %v", err)
40+
}
41+
42+
// Determine if this file should be repacked
43+
repack, err := shouldRepackLayerFile(f, filterPattern)
44+
if err != nil {
45+
return false, fmt.Errorf("filtering file in layer tar: %v", err)
46+
}
47+
if repack {
48+
err = repackLayerFile(f)
49+
}
50+
51+
if err != nil {
52+
return false, fmt.Errorf("walking %s in layer tar: %v", f.Name(), err)
53+
}
54+
}
55+
56+
return false, nil
57+
}
58+
59+
func shouldRepackLayerFile(f archiver.File, matchPattern string) (should bool, err error) {
60+
header, ok := f.Header.(*tar.Header)
61+
if !ok {
62+
return false, fmt.Errorf("expected header to be *tar.Header but was %T", f.Header)
63+
}
64+
65+
if f.IsDir() {
66+
return false, nil
67+
}
68+
69+
if strings.HasPrefix(f.Name(), ".wh.") {
70+
return false, nil
71+
}
72+
73+
return zglob.Match(matchPattern, header.Name)
74+
}
75+
76+
func repackLayerFile(f archiver.File) error {
77+
log.Printf(f.Header.(*tar.Header).Name)
78+
79+
return nil
80+
}

0 commit comments

Comments
 (0)