Skip to content

Commit

Permalink
Allow CustomBuilders and Builders to create windows builder images
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewmcnew authored and tomkennedy513 committed Dec 23, 2020
1 parent 3eef4b0 commit e28bb30
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 40 deletions.
53 changes: 46 additions & 7 deletions hack/lifecycle/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"regexp"
"time"

"github.com/buildpacks/imgutil/layer"
"github.com/google/go-containerregistry/pkg/authn"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
Expand All @@ -41,10 +42,11 @@ func main() {
flag.Parse()

image, err := lifecycleImage(
"https://github.com/buildpacks/lifecycle/releases/download/v0.9.2/lifecycle-v0.9.2+linux.x86-64.tgz",
"https://github.com/buildpacks/lifecycle/releases/download/v0.9.3/lifecycle-v0.9.3+linux.x86-64.tgz",
"https://github.com/buildpacks/lifecycle/releases/download/v0.9.3/lifecycle-v0.9.3+windows.x86-64.tgz",
cnb.LifecycleMetadata{
LifecycleInfo: cnb.LifecycleInfo{
Version: "0.9.2",
Version: "0.9.3",
},
API: cnb.LifecycleAPI{
BuildpackVersion: "0.2",
Expand Down Expand Up @@ -75,18 +77,42 @@ func main() {

}

func lifecycleImage(url string, lifecycleMetadata cnb.LifecycleMetadata) (v1.Image, error) {
func lifecycleImage(linuxUrl, windowsUrl string, lifecycleMetadata cnb.LifecycleMetadata) (v1.Image, error) {
image, err := random.Image(0, 0)
if err != nil {
return nil, err
}

layer, err := lifecycleLayer(url)
linuxLayer, err := lifecycleLayer(linuxUrl, "linux")
if err != nil {
return nil, err
}
linuxDiffID, err := linuxLayer.DiffID()
if err != nil {
return nil, err
}

image, err = imagehelpers.SetStringLabel(image, "linux", linuxDiffID.String())
if err != nil {
return nil, err
}

windowsLayer, err := lifecycleLayer(windowsUrl, "windows")
if err != nil {
return nil, err
}

windowsDiffID, err := windowsLayer.DiffID()
if err != nil {
return nil, err
}

image, err = imagehelpers.SetStringLabel(image, "windows", windowsDiffID.String())
if err != nil {
return nil, err
}

image, err = mutate.AppendLayers(image, layer)
image, err = mutate.AppendLayers(image, linuxLayer, windowsLayer)
if err != nil {
return nil, err
}
Expand All @@ -96,9 +122,9 @@ func lifecycleImage(url string, lifecycleMetadata cnb.LifecycleMetadata) (v1.Ima
})
}

func lifecycleLayer(url string) (v1.Layer, error) {
func lifecycleLayer(url, os string) (v1.Layer, error) {
b := &bytes.Buffer{}
tw := tar.NewWriter(b)
tw := newLayerWriter(b, os)

var regex = regexp.MustCompile(`^[^/]+/([^/]+)$`)

Expand Down Expand Up @@ -197,3 +223,16 @@ type ReadCloserWrapper struct {
func (r *ReadCloserWrapper) Close() error {
return r.closer()
}

func newLayerWriter(fileWriter io.Writer, os string) layerWriter {
if os == "windows" {
return layer.NewWindowsWriter(fileWriter)
}
return tar.NewWriter(fileWriter)
}

type layerWriter interface {
WriteHeader(hdr *tar.Header) error
Write(b []byte) (int, error)
Close() error
}
47 changes: 36 additions & 11 deletions pkg/cnb/builder_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package cnb
import (
"archive/tar"
"bytes"
"io"
"sort"
"time"

"github.com/BurntSushi/toml"
"github.com/buildpacks/imgutil/layer"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/tarball"
Expand Down Expand Up @@ -41,6 +43,7 @@ type builderBlder struct {
kpackVersion string
runImage string
mixins []string
os string
}

func newBuilderBldr(lifecycleImage v1.Image, kpackVersion string) (*builderBlder, error) {
Expand All @@ -58,13 +61,20 @@ func newBuilderBldr(lifecycleImage v1.Image, kpackVersion string) (*builderBlder
}, nil
}

func (bb *builderBlder) AddStack(baseImage v1.Image, clusterStack *v1alpha1.ClusterStack) {
func (bb *builderBlder) AddStack(baseImage v1.Image, clusterStack *v1alpha1.ClusterStack) error {
file, err := baseImage.ConfigFile()
if err != nil {
return err
}

bb.os = file.OS
bb.baseImage = baseImage
bb.stackId = clusterStack.Status.Id
bb.runImage = clusterStack.Status.RunImage.Image
bb.mixins = clusterStack.Status.Mixins
bb.cnbUserId = clusterStack.Status.UserID
bb.cnbGroupId = clusterStack.Status.GroupID
return nil
}

func (bb *builderBlder) AddGroup(buildpacks ...RemoteBuildpackRef) {
Expand Down Expand Up @@ -176,16 +186,17 @@ func (bb *builderBlder) buildpacks() []DescriptiveBuildpackInfo {
}

func (bb *builderBlder) lifecycleLayer() (v1.Layer, error) {
layers, err := bb.lifecycleImage.Layers()
diffId, err := imagehelpers.GetStringLabel(bb.lifecycleImage, bb.os)
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "could not find lifecycle for os: %s", bb.os)
}

if len(layers) != 1 {
return nil, errors.New("invalid lifecycle image")
hash, err := v1.NewHash(diffId)
if err != nil {
return nil, err
}

return layers[0], nil
return bb.lifecycleImage.LayerByDiffID(hash)
}

func (bb *builderBlder) stackLayer() (v1.Layer, error) {
Expand All @@ -207,7 +218,7 @@ func (bb *builderBlder) stackLayer() (v1.Layer, error) {
if err != nil {
return nil, err
}
return singeFileLayer(stackTomlPath, stackBuf.Bytes())
return bb.singeFileLayer(stackTomlPath, stackBuf.Bytes())
}

func (bb *builderBlder) orderLayer() (v1.Layer, error) {
Expand Down Expand Up @@ -246,12 +257,12 @@ func (bb *builderBlder) orderLayer() (v1.Layer, error) {
if err != nil {
return nil, err
}
return singeFileLayer(orderTomlPath, orderBuf.Bytes())
return bb.singeFileLayer(orderTomlPath, orderBuf.Bytes())
}

func singeFileLayer(file string, contents []byte) (v1.Layer, error) {
func (bb *builderBlder) singeFileLayer(file string, contents []byte) (v1.Layer, error) {
b := &bytes.Buffer{}
w := tar.NewWriter(b)
w := bb.layerWriter(b)
if err := w.WriteHeader(&tar.Header{
Name: file,
Size: int64(len(contents)),
Expand Down Expand Up @@ -283,7 +294,7 @@ func (bb *builderBlder) defaultDirsLayer() (v1.Layer, error) {
}

b := &bytes.Buffer{}
tw := tar.NewWriter(b)
tw := bb.layerWriter(b)

for _, header := range dirs {
if err := tw.WriteHeader(header); err != nil {
Expand Down Expand Up @@ -318,6 +329,20 @@ func (bb *builderBlder) rootOwnedDir(path string) *tar.Header {
}
}

func (bb *builderBlder) layerWriter(fileWriter io.Writer) layerWriter {
if bb.os == "windows" {
return layer.NewWindowsWriter(fileWriter)
}
return tar.NewWriter(fileWriter)

}

type layerWriter interface {
WriteHeader(hdr *tar.Header) error
Write(b []byte) (int, error)
Close() error
}

func deterministicSortBySize(layers map[DescriptiveBuildpackInfo]buildpackLayer) []DescriptiveBuildpackInfo {
keys := make([]DescriptiveBuildpackInfo, 0, len(layers))
sizes := make(map[DescriptiveBuildpackInfo]int64, len(layers))
Expand Down
5 changes: 4 additions & 1 deletion pkg/cnb/create_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ func (r *RemoteBuilderCreator) CreateBuilder(keychain authn.Keychain, buildpackR
return v1alpha1.BuilderRecord{}, err
}

builderBldr.AddStack(buildImage, clusterStack)
err = builderBldr.AddStack(buildImage, clusterStack)
if err != nil {
return v1alpha1.BuilderRecord{}, err
}

for _, group := range spec.Order {
buildpacks := make([]RemoteBuildpackRef, 0, len(group.Group))
Expand Down
Loading

0 comments on commit e28bb30

Please sign in to comment.