Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions pkg/steps/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,9 +519,40 @@ func handleBuilds(ctx context.Context, buildClient BuildClient, podClient kubern
return utilerrors.NewAggregate(errs)
}

// updateImageStreamTagForArch updates an ObjectReference to use an architecture-specific tag
// if it references the pipeline imagestream. This ensures that multi-arch builds reference
// the correct architecture-specific image instead of the manifest list.
func updateImageStreamTagForArch(ref *corev1.ObjectReference, arch string) *corev1.ObjectReference {
if ref == nil || ref.Kind != "ImageStreamTag" {
return ref
}

// Check if this is a pipeline imagestream reference
parts := strings.SplitN(ref.Name, ":", 2)
if len(parts) != 2 {
return ref
}

imageStreamName, tag := parts[0], parts[1]
if imageStreamName != api.PipelineImageStream {
return ref
}

// Don't modify tags that already have an architecture suffix
if strings.HasSuffix(tag, fmt.Sprintf("-%s", arch)) {
return ref
}

// Create a new reference with the architecture suffix
updated := ref.DeepCopy()
updated.Name = fmt.Sprintf("%s:%s-%s", imageStreamName, tag, arch)
return updated
}

// constructMultiArchBuilds gets a specific build and constructs multiple builds for each architecture.
// The name and the output image of the build is suffixed with the architecture name and it will include the nodeSelector for the specific architecture.
// e.x if the build name is "foo" and the architectures are "amd64,arm64", the new builds will be "foo-amd64" and "foo-arm64".
// All pipeline imagestream references (From and image sources) are updated to use architecture-specific tags.
func constructMultiArchBuilds(build buildapi.Build, stepArchitectures []string) []buildapi.Build {
var ret []buildapi.Build

Expand All @@ -531,7 +562,7 @@ func constructMultiArchBuilds(build buildapi.Build, stepArchitectures []string)
}

for _, arch := range archs {
b := build
b := build.DeepCopy()
b.Name = fmt.Sprintf("%s-%s", b.Name, arch)
b.Spec.NodeSelector = map[string]string{
corev1.LabelArchStable: arch,
Expand All @@ -542,7 +573,18 @@ func constructMultiArchBuilds(build buildapi.Build, stepArchitectures []string)
Namespace: b.Namespace,
Name: fmt.Sprintf("%s:%s", api.PipelineImageStream, b.Name),
}
ret = append(ret, b)

// Update the From field to use architecture-specific tag if it references the pipeline imagestream
if b.Spec.Strategy.DockerStrategy != nil && b.Spec.Strategy.DockerStrategy.From != nil {
b.Spec.Strategy.DockerStrategy.From = updateImageStreamTagForArch(b.Spec.Strategy.DockerStrategy.From, arch)
}

// Update any image source inputs to use architecture-specific tags
for i := range b.Spec.Source.Images {
b.Spec.Source.Images[i].From = *updateImageStreamTagForArch(&b.Spec.Source.Images[i].From, arch)
}

ret = append(ret, *b)
}

return ret
Expand Down
128 changes: 128 additions & 0 deletions pkg/steps/source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,134 @@ func Test_constructMultiArchBuilds(t *testing.T) {
},
},
},
{
name: "multi-arch with From field and image sources",
stepArchitectures: []string{"amd64", "arm64"},
build: buildapi.Build{
ObjectMeta: meta.ObjectMeta{Name: "test-build"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &coreapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "pipeline:src",
},
},
},
Source: buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: coreapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "pipeline:base",
},
Paths: []buildapi.ImageSourcePath{{SourcePath: "/src", DestinationDir: "/dst"}},
},
{
From: coreapi.ObjectReference{
Kind: "DockerImage",
Name: "registry.example.com/image:tag",
},
Paths: []buildapi.ImageSourcePath{{SourcePath: "/other", DestinationDir: "/other-dst"}},
},
},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{Name: "io.openshift.build.namespace", Value: "namespace"},
},
},
},
},
},
want: []buildapi.Build{
{
ObjectMeta: meta.ObjectMeta{Name: "test-build-amd64"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
NodeSelector: map[string]string{
"kubernetes.io/arch": "amd64",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &coreapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "pipeline:src-amd64",
},
},
},
Source: buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: coreapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "pipeline:base-amd64",
},
Paths: []buildapi.ImageSourcePath{{SourcePath: "/src", DestinationDir: "/dst"}},
},
{
From: coreapi.ObjectReference{
Kind: "DockerImage",
Name: "registry.example.com/image:tag",
},
Paths: []buildapi.ImageSourcePath{{SourcePath: "/other", DestinationDir: "/other-dst"}},
},
},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{Name: "io.openshift.build.namespace", Value: "namespace"},
},
To: &coreapi.ObjectReference{Name: "pipeline:test-build-amd64"},
},
},
},
},
{
ObjectMeta: meta.ObjectMeta{Name: "test-build-arm64"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
NodeSelector: map[string]string{
"kubernetes.io/arch": "arm64",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &coreapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "pipeline:src-arm64",
},
},
},
Source: buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: coreapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "pipeline:base-arm64",
},
Paths: []buildapi.ImageSourcePath{{SourcePath: "/src", DestinationDir: "/dst"}},
},
{
From: coreapi.ObjectReference{
Kind: "DockerImage",
Name: "registry.example.com/image:tag",
},
Paths: []buildapi.ImageSourcePath{{SourcePath: "/other", DestinationDir: "/other-dst"}},
},
},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{Name: "io.openshift.build.namespace", Value: "namespace"},
},
To: &coreapi.ObjectReference{Name: "pipeline:test-build-arm64"},
},
},
},
},
},
},
}

for _, tt := range tests {
Expand Down