Skip to content

Commit

Permalink
fix(export): resolve issue with exporting specific images (#6471)
Browse files Browse the repository at this point in the history
Signed-off-by: Yaroslav Pershin <62902094+iapershin@users.noreply.github.com>
  • Loading branch information
iapershin authored Dec 4, 2024
1 parent 04b7178 commit 0b422d2
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 39 deletions.
19 changes: 7 additions & 12 deletions pkg/build/export_phase.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,16 @@ func (e *Exporter) Run(ctx context.Context) error {
return nil
}

imageList := util.SliceToMapWithValue(e.ExportImageNameList, struct{}{})
images := e.Conveyor.imagesTree.GetImagesByName(true)

if err := parallel.DoTasks(ctx, len(e.ExportImageNameList), parallel.DoTasksOptions{
images := e.Conveyor.imagesTree.GetImagesByName(true, build_image.WithExportImageNameList(e.ExportImageNameList))
if err := parallel.DoTasks(ctx, len(images), parallel.DoTasksOptions{
MaxNumberOfWorkers: int(e.Conveyor.ParallelTasksLimit),
}, func(ctx context.Context, taskId int) error {
pair := images[taskId]
name, images := pair.Unpair()
if _, ok := imageList[name]; !ok {
return nil
}
name, imagesToExport := pair.Unpair()

targetPlatforms := util.MapFuncToSlice(images, func(img *build_image.Image) string { return img.TargetPlatform })
targetPlatforms := util.MapFuncToSlice(imagesToExport, func(img *build_image.Image) string { return img.TargetPlatform })
if len(targetPlatforms) == 1 {
img := images[0]
img := imagesToExport[0]
if err := e.exportImage(ctx, img); err != nil {
return fmt.Errorf("unable to export image %q: %w", img.Name, err)
}
Expand All @@ -80,7 +75,7 @@ func (e *Exporter) Run(ctx context.Context) error {
}

func (e *Exporter) exportMultiplatformImage(ctx context.Context, img *build_image.MultiplatformImage) error {
return logboek.Context(ctx).Default().LogProcess("Exporting image...").
return logboek.Context(ctx).Default().LogProcess(fmt.Sprintf("Exporting image %s", img.Name)).
Options(func(options types.LogProcessOptionsInterface) {
options.Style(style.Highlight())
}).
Expand Down Expand Up @@ -112,7 +107,7 @@ func (e *Exporter) exportImage(ctx context.Context, img *build_image.Image) erro
return nil
}

return logboek.Context(ctx).Default().LogProcess("Exporting image...").
return logboek.Context(ctx).Default().LogProcess(fmt.Sprintf("Exporting image %s", img.Name)).
Options(func(options types.LogProcessOptionsInterface) {
options.Style(style.Highlight())
}).
Expand Down
27 changes: 26 additions & 1 deletion pkg/build/image/image_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,27 @@ func (tree *ImagesTree) Calculate(ctx context.Context) error {
return nil
}

func (tree *ImagesTree) GetImagesByName(onlyFinal bool) []util.Pair[string, []*Image] {
type GetImagesByNameOption func(*getImagesByNameConfig)

type getImagesByNameConfig struct {
compareWithImagesList bool
exportImageNameList map[string]struct{}
}

func WithExportImageNameList(l []string) GetImagesByNameOption {
return func(config *getImagesByNameConfig) {
config.exportImageNameList = util.SliceToMapWithValue(l, struct{}{})
config.compareWithImagesList = true
}
}

func (tree *ImagesTree) GetImagesByName(onlyFinal bool, opts ...GetImagesByNameOption) []util.Pair[string, []*Image] {
config := &getImagesByNameConfig{}

for _, opt := range opts {
opt(config)
}

images := make(map[string]map[string]*Image)
var names []string

Expand All @@ -145,6 +165,11 @@ func (tree *ImagesTree) GetImagesByName(onlyFinal bool) []util.Pair[string, []*I
if onlyFinal && !img.IsFinal {
continue
}
if config.compareWithImagesList {
if _, ok := config.exportImageNameList[img.Name]; !ok {
continue
}
}
appendImage(img)
}

Expand Down
13 changes: 13 additions & 0 deletions test/e2e/export/_fixtures/complex/state0/werf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
project: werf-test-e2e-export-complex
configVersion: 1
---
image: backend
from: ubuntu:22.04
---
image: frombackend
fromImage: backend
---
image: frombackend2
fromImage: frombackend
shell:
install: date
34 changes: 34 additions & 0 deletions test/e2e/export/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package e2e_export_test

import (
"strings"
)

type commonTestOptions struct {
Platforms []string
CustomLabels []string
}

func setupEnv() {
SuiteData.WerfRepo = strings.Join([]string{SuiteData.RegistryLocalAddress, SuiteData.ProjectName}, "/")
SuiteData.Stubs.SetEnv("WERF_REPO", SuiteData.WerfRepo)
}

func getExportArgs(imageName string, opts commonTestOptions) []string {
exportArgs := []string{
"--tag",
imageName,
}
if len(opts.Platforms) > 0 {
for _, platform := range opts.Platforms {
exportArgs = append(exportArgs, "--platform", platform)
}
}
if len(opts.CustomLabels) > 0 {
for _, label := range opts.CustomLabels {
exportArgs = append(exportArgs, "--add-label", label)
}
}

return exportArgs
}
81 changes: 81 additions & 0 deletions test/e2e/export/complex_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package e2e_export_test

import (
"context"
"fmt"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/werf/werf/v2/test/pkg/utils"
"github.com/werf/werf/v2/test/pkg/werf"
)

type complexTestOptions struct {
Platforms []string
ImageNames []string
}

var _ = Describe("Complex converge", Label("e2e", "converge", "complex"), func() {
DescribeTable("should succeed and export images",
func(opts complexTestOptions) {
By("initializating")
setupEnv()
repoDirname := "repo0"
By("state0: starting")
{
fixtureRelPath := "complex/state0"

By("state0: preparing test repo")
SuiteData.InitTestRepo(repoDirname, fixtureRelPath)

By("state0: running export")
werfProject := werf.NewProject(SuiteData.WerfBinPath, SuiteData.GetTestRepoPath(repoDirname))
imageTemplate := `werf-export-%image%`
tag := utils.GetRandomString(10)
imageName := fmt.Sprintf("%s/%s:%s", SuiteData.RegistryLocalAddress, imageTemplate, tag)

exportArgs := getExportArgs(imageName, commonTestOptions{
Platforms: opts.Platforms,
})

exportOut := werfProject.Export(&werf.ExportOptions{
CommonOptions: werf.CommonOptions{
ExtraArgs: exportArgs,
},
})
for _, imageName := range opts.ImageNames {
Expect(exportOut).To(ContainSubstring(fmt.Sprintf("Exporting image %s", imageName)))
}

By("state0: checking result")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

for _, imageName := range opts.ImageNames {
b, err := SuiteData.ContainerRegistry.IsTagExist(ctx, fmt.Sprintf("%s/werf-export-%s:%s", SuiteData.RegistryLocalAddress, imageName, tag))
Expect(err).NotTo(HaveOccurred())
Expect(b).To(BeTrue())
}
}
},
Entry("base", complexTestOptions{
ImageNames: []string{
"backend",
"frombackend",
"frombackend2",
},
}),
Entry("multiplatform", complexTestOptions{
Platforms: []string{
"linux/amd64",
},
ImageNames: []string{
"backend",
"frombackend",
"frombackend2",
},
}),
)
})
40 changes: 14 additions & 26 deletions test/e2e/export/simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ var _ = Describe("Simple export", Label("e2e", "export", "simple"), func() {
func(opts simpleTestOptions) {
By("initializating")
{
SuiteData.WerfRepo = strings.Join([]string{SuiteData.RegistryLocalAddress, SuiteData.ProjectName}, "/")
SuiteData.Stubs.SetEnv("WERF_REPO", SuiteData.WerfRepo)
SuiteData.Stubs.SetEnv("DOCKER_BUILDKIT", "1")
setupEnv()
repoDirname := "repo"
fixtureRelPath := "simple"

Expand All @@ -37,27 +35,17 @@ var _ = Describe("Simple export", Label("e2e", "export", "simple"), func() {
werfProject := werf.NewProject(SuiteData.WerfBinPath, SuiteData.GetTestRepoPath(repoDirname))
imageName := fmt.Sprintf("%s/werf-export-%s", SuiteData.RegistryLocalAddress, utils.GetRandomString(10))

exportArgs := []string{
"--tag",
imageName,
}
if len(opts.Platforms) > 0 {
for _, platform := range opts.Platforms {
exportArgs = append(exportArgs, "--platform", platform)
}
}
if len(opts.CustomLabels) > 0 {
for _, label := range opts.CustomLabels {
exportArgs = append(exportArgs, "--add-label", label)
}
}
exportArgs := getExportArgs(imageName, commonTestOptions{
Platforms: opts.Platforms,
CustomLabels: opts.CustomLabels,
})

exportOut := werfProject.Export(&werf.ExportOptions{
CommonOptions: werf.CommonOptions{
ExtraArgs: exportArgs,
},
})
Expect(exportOut).To(ContainSubstring("Exporting image..."))
Expect(exportOut).To(ContainSubstring("Exporting image"))

By("checking result")
commonCheckImageConfigFunc := func(config v1.Config) {
Expand Down Expand Up @@ -125,18 +113,18 @@ var _ = Describe("Simple export", Label("e2e", "export", "simple"), func() {

func checkIndexManifest(reference string, checkIndexManifestFunc func(*v1.IndexManifest), checkImageConfigFunc func(v1.Config)) {
ref, err := name.ParseReference(reference)
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

desc, err := remote.Get(ref)
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

Expect(desc.MediaType.IsIndex()).Should(BeTrue(), "expected index, got image")

ii, err := desc.ImageIndex()
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

im, err := ii.IndexManifest()
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

checkIndexManifestFunc(im)

Expand All @@ -148,18 +136,18 @@ func checkIndexManifest(reference string, checkIndexManifestFunc func(*v1.IndexM

func checkImageManifest(reference string, checkImageConfigFunc func(v1.Config)) {
ref, err := name.ParseReference(reference)
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

desc, err := remote.Get(ref)
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

Expect(desc.MediaType.IsIndex()).ShouldNot(BeTrue(), "expected image, got index")

i, err := desc.Image()
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

c, err := i.ConfigFile()
Expect(err).ShouldNot(HaveOccurred(), err)
Expect(err).ShouldNot(HaveOccurred())

checkImageConfigFunc(c.Config)
}
13 changes: 13 additions & 0 deletions test/e2e/export/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/werf/werf/v2/pkg/docker_registry"
"github.com/werf/werf/v2/test/pkg/suite_init"
"github.com/werf/werf/v2/test/pkg/utils"
"github.com/werf/werf/v2/test/pkg/utils/docker"
Expand All @@ -27,6 +29,7 @@ var SuiteData = struct {
RegistryLocalAddress string
RegistryInternalAddress string
RegistryContainerName string
ContainerRegistry docker_registry.Interface

WerfRepo string
}{}
Expand All @@ -48,3 +51,13 @@ var (
utils.RunSucceedCommand("", SuiteData.WerfBinPath, "host", "purge", "--force", "--project-name", SuiteData.ProjectName)
})
)

var _ = BeforeEach(func() {
containerRegistry, err := docker_registry.NewDockerRegistry(SuiteData.RegistryLocalAddress+"/repo", "", docker_registry.DockerRegistryOptions{
InsecureRegistry: true,
SkipTlsVerifyRegistry: true,
})
Expect(err).ShouldNot(HaveOccurred())

SuiteData.ContainerRegistry = containerRegistry
})

0 comments on commit 0b422d2

Please sign in to comment.