From 8a813b52318f06acb83fc44aff215d95c57e8f09 Mon Sep 17 00:00:00 2001 From: Timofey Kirillov Date: Thu, 17 Nov 2022 13:00:06 +0300 Subject: [PATCH] feat(staged-dockerfile): support ONBUILD instructions (part 1, preparations) refs #2215 Signed-off-by: Timofey Kirillov --- pkg/build/build_phase.go | 7 ++++-- pkg/build/image/image.go | 20 ++++++++++++++++- pkg/image/info.go | 17 ++++++++++++++ pkg/storage/manager/storage_manager.go | 31 ++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/pkg/build/build_phase.go b/pkg/build/build_phase.go index dcf9030d25..2f9086a007 100644 --- a/pkg/build/build_phase.go +++ b/pkg/build/build_phase.go @@ -242,8 +242,11 @@ func (phase *BuildPhase) ImageProcessingShouldBeStopped(_ context.Context, _ *im func (phase *BuildPhase) BeforeImageStages(ctx context.Context, img *image.Image) (deferFn func(), err error) { phase.StagesIterator = NewStagesIterator(phase.Conveyor) - if err := img.SetupBaseImage(); err != nil { - return nil, err + if err := img.SetupBaseImage(ctx, phase.Conveyor.StorageManager, manager.StorageOptions{ + ContainerBackend: phase.Conveyor.ContainerBackend, + DockerRegistry: docker_registry.API(), + }); err != nil { + return nil, fmt.Errorf("unable to setup base image: %w", err) } if img.UsesBuildContext() { diff --git a/pkg/build/image/image.go b/pkg/build/image/image.go index 7e58ad2eec..dfe5f71935 100644 --- a/pkg/build/image/image.go +++ b/pkg/build/image/image.go @@ -201,7 +201,7 @@ func (i *Image) GetRebuilt() bool { return i.rebuilt } -func (i *Image) SetupBaseImage() error { +func (i *Image) SetupBaseImage(ctx context.Context, storageManager manager.StorageManagerInterface, storageOpts manager.StorageOptions) error { switch i.baseImageType { case StageAsBaseImage: i.stageAsBaseImage = i.Conveyor.GetImage(i.baseImageName).GetLastNonEmptyStage() @@ -222,6 +222,24 @@ func (i *Image) SetupBaseImage() error { panic(fmt.Sprintf("unknown base image type %q", i.baseImageType)) } + if i.IsDockerfileImage && i.DockerfileImageConfig.Staged { + switch i.baseImageType { + case StageAsBaseImage, ImageFromRegistryAsBaseImage: + + fmt.Printf("-- %s SetupBaseImage %q\n", i.Name, i.baseImageReference) + + info, err := storageManager.GetImageInfo(ctx, i.baseImageReference, storageOpts) + if err != nil { + return fmt.Errorf("unable to get base image %q manifest: %w", i.baseImageReference, err) + } + + fmt.Printf("-- %s SetupBaseImage %q -> %#v\n", i.Name, i.baseImageReference, info) + for _, expression := range info.OnBuild { + fmt.Printf(">> %q\n", expression) + } + } + } + return nil } diff --git a/pkg/image/info.go b/pkg/image/info.go index e2465e164d..5bf51fb656 100644 --- a/pkg/image/info.go +++ b/pkg/image/info.go @@ -6,6 +6,7 @@ import ( "time" "github.com/docker/docker/api/types" + v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/werf/werf/pkg/util" ) @@ -99,3 +100,19 @@ func ParseRepositoryAndTag(ref string) (string, string) { repository := util.Reverse(parts[1]) return repository, tag } + +func NewImageInfoFromRegistryConfig(ref string, cfg *v1.ConfigFile) *Info { + repository, tag := ParseRepositoryAndTag(ref) + return &Info{ + Name: ref, + Repository: repository, + Tag: tag, + Labels: cfg.Config.Labels, + OnBuild: cfg.Config.OnBuild, + CreatedAtUnixNano: cfg.Created.UnixNano(), + RepoDigest: "", // TODO + ID: "", // TODO + ParentID: "", // TODO + Size: 0, // TODO + } +} diff --git a/pkg/storage/manager/storage_manager.go b/pkg/storage/manager/storage_manager.go index 3fc9c6a5e4..90778ad936 100644 --- a/pkg/storage/manager/storage_manager.go +++ b/pkg/storage/manager/storage_manager.go @@ -16,6 +16,7 @@ import ( "github.com/werf/logboek/pkg/types" "github.com/werf/werf/pkg/build/stage" "github.com/werf/werf/pkg/container_backend" + "github.com/werf/werf/pkg/docker_registry" "github.com/werf/werf/pkg/image" "github.com/werf/werf/pkg/storage" "github.com/werf/werf/pkg/storage/lrumeta" @@ -47,6 +48,11 @@ type ForEachDeleteStageOptions struct { storage.FilterStagesAndProcessRelatedDataOptions } +type StorageOptions struct { + ContainerBackend container_backend.ContainerBackend + DockerRegistry docker_registry.ApiInterface +} + type StorageManagerInterface interface { InitCache(ctx context.Context) error @@ -59,6 +65,8 @@ type StorageManagerInterface interface { MaxNumberOfWorkers() int GenerateStageUniqueID(digest string, stages []*image.StageDescription) (string, int64) + GetImageInfo(ctx context.Context, ref string, opts StorageOptions) (*image.Info, error) + LockStageImage(ctx context.Context, imageName string) error GetStagesByDigest(ctx context.Context, stageName, stageDigest string) ([]*image.StageDescription, error) GetStagesByDigestWithCache(ctx context.Context, stageName, stageDigest string) ([]*image.StageDescription, error) @@ -342,6 +350,29 @@ func (m *StorageManager) ForEachDeleteStage(ctx context.Context, options ForEach }) } +func (m *StorageManager) GetImageInfo(ctx context.Context, ref string, opts StorageOptions) (*image.Info, error) { + info, err := m.getImageInfoFromContainerBackend(ctx, ref, opts.ContainerBackend) + if err != nil { + return nil, err + } + if info != nil { + return info, err + } + return m.getImageInfoFromRegistry(ctx, ref, opts.DockerRegistry) +} + +func (m *StorageManager) getImageInfoFromContainerBackend(ctx context.Context, ref string, containerBackend container_backend.ContainerBackend) (*image.Info, error) { + return containerBackend.GetImageInfo(ctx, ref, container_backend.GetImageInfoOpts{}) +} + +func (m *StorageManager) getImageInfoFromRegistry(ctx context.Context, ref string, dockerRegistry docker_registry.ApiInterface) (*image.Info, error) { + cfg, err := dockerRegistry.GetRepoImageConfigFile(ctx, ref) + if err != nil { + return nil, err + } + return image.NewImageInfoFromRegistryConfig(ref, cfg), nil +} + func (m *StorageManager) LockStageImage(ctx context.Context, imageName string) error { imageLockName := container_backend.ImageLockName(imageName)