worker: move osbuild exports from OSBuildJob to target

The osbuild export is specific to the upload target and different
targets may require using a different export. While osbuild-composer
still does not support multiple exports for osbuild jobs, this prepares
the ground for such support in the future.

The backward compatibility with older implementations of the composer
and workers is kept on the JSON (Un)mashaling level, where the JSON
message is always a super-set of the old and new way of providing the
exports to osbuild job.
This commit is contained in:
Tomas Hozza 2022-06-23 16:55:35 +02:00 committed by Tom Gundersen
parent 4e26ba82d0
commit 776a54135f
11 changed files with 363 additions and 38 deletions

View file

@ -298,7 +298,8 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
// copy pipeline info to the result
osbuildJobResult.PipelineNames = jobArgs.PipelineNames
exports := jobArgs.Exports
// get exports for all job's targets
exports := jobArgs.OsbuildExports()
if len(exports) == 0 {
// job did not define exports, likely coming from an older version of composer
// fall back to default "assembler"
@ -344,14 +345,13 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
return nil
}
exportPath := exports[0]
for _, jobTarget := range jobArgs.Targets {
var targetResult *target.TargetResult
switch targetOptions := jobTarget.Options.(type) {
case *target.WorkerServerTargetOptions:
targetResult = target.NewWorkerServerTargetResult()
var f *os.File
imagePath := path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename)
imagePath := path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename)
f, err = os.Open(imagePath)
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidTargetConfig, err.Error())
@ -392,7 +392,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
imageName := jobTarget.ImageName + ".vmdk"
imagePath := path.Join(tempDirectory, imageName)
exportedImagePath := path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename)
exportedImagePath := path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename)
err = os.Symlink(exportedImagePath, imagePath)
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidConfig, err.Error())
@ -422,7 +422,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
if impl.AWSBucket != "" {
bucket = impl.AWSBucket
}
_, err = a.Upload(path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename), bucket, key)
_, err = a.Upload(path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename), bucket, key)
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorUploadingImage, err.Error())
break
@ -451,7 +451,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
break
}
url, targetError := uploadToS3(a, outputDirectory, exportPath, bucket, targetOptions.Key, jobTarget.OsbuildArtifact.ExportFilename)
url, targetError := uploadToS3(a, outputDirectory, jobTarget.OsbuildArtifact.ExportName, bucket, targetOptions.Key, jobTarget.OsbuildArtifact.ExportFilename)
if targetError != nil {
targetResult.TargetError = targetError
break
@ -477,7 +477,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
const azureMaxUploadGoroutines = 4
err = azureStorageClient.UploadPageBlob(
metadata,
path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename),
path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename),
azureMaxUploadGoroutines,
)
@ -497,7 +497,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
}
logWithId.Infof("[GCP] 🚀 Uploading image to: %s/%s", targetOptions.Bucket, targetOptions.Object)
_, err = g.StorageObjectUpload(ctx, path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename),
_, err = g.StorageObjectUpload(ctx, path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename),
targetOptions.Bucket, targetOptions.Object, map[string]string{gcp.MetadataKeyImageName: jobTarget.ImageName})
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorUploadingImage, err.Error())
@ -625,7 +625,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
ContainerName: storageContainer,
BlobName: blobName,
},
path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename),
path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename),
azure.DefaultUploadThreads,
)
if err != nil {
@ -682,7 +682,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
}
}()
file, err := os.Open(path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename))
file, err := os.Open(path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename))
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorKojiBuild, fmt.Sprintf("failed to open the image for reading: %v", err))
break
@ -718,7 +718,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
}
logWithId.Info("[OCI] 🔑 Logged in OCI")
logWithId.Info("[OCI] ⬆ Uploading the image")
file, err := os.Open(path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename))
file, err := os.Open(path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename))
if err != nil {
targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidConfig, err.Error())
break
@ -760,7 +760,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
client.TlsVerify = *targetOptions.TlsVerify
}
sourcePath := path.Join(outputDirectory, exportPath, jobTarget.OsbuildArtifact.ExportFilename)
sourcePath := path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename)
// TODO: get the container type from the metadata of the osbuild job
sourceRef := fmt.Sprintf("oci-archive:%s", sourcePath)

View file

@ -435,6 +435,8 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
default:
return HTTPError(ErrorUnsupportedImageType)
}
irTarget.OsbuildArtifact.ExportName = imageType.Exports()[0]
}
irs = append(irs, imageRequest{

View file

@ -119,7 +119,6 @@ func (s *Server) enqueueCompose(distribution distro.Distro, bp blueprint.Bluepri
id, err = s.workers.EnqueueOSBuildAsDependency(ir.arch.Name(), &worker.OSBuildJob{
Targets: []*target.Target{ir.target},
Exports: ir.imageType.Exports(),
PipelineNames: &worker.PipelineNames{
Build: ir.imageType.BuildPipelines(),
Payload: ir.imageType.PayloadPipelines(),
@ -183,10 +182,10 @@ func (s *Server) enqueueKojiCompose(taskID uint64, server, name, version, releas
UploadDirectory: kojiDirectory,
})
kojiTarget.OsbuildArtifact.ExportFilename = ir.imageType.Filename()
kojiTarget.OsbuildArtifact.ExportName = ir.imageType.Exports()[0]
kojiTarget.ImageName = kojiFilename
buildID, err := s.workers.EnqueueOSBuildAsDependency(ir.arch.Name(), &worker.OSBuildJob{
Exports: ir.imageType.Exports(),
PipelineNames: &worker.PipelineNames{
Build: ir.imageType.BuildPipelines(),
Payload: ir.imageType.PayloadPipelines(),

View file

@ -16,6 +16,8 @@ type TargetName string
type OsbuildArtifact struct {
// Filename of the image as produced by osbuild for a given export
ExportFilename string `json:"export_filename"`
// Name of the osbuild pipeline, which should be exported for this target
ExportName string `json:"export_name"`
}
type Target struct {

View file

@ -212,7 +212,7 @@ func TestTargetOptionsFilenameCompatibilityMarshal(t *testing.T) {
target *Target
}{
{
targetJSON: []byte(`{"uuid":"00000000-0000-0000-0000-000000000000","image_name":"my-image","name":"org.osbuild.aws","created":"0001-01-01T00:00:00Z","status":"WAITING","options":{"region":"us","accessKeyID":"id","secretAccessKey":"key","sessionToken":"token","bucket":"bkt","key":"key","shareWithAccounts":["123456789"],"filename":"image.qcow2"},"osbuild_artifact":{"export_filename":"image.qcow2"}}`),
targetJSON: []byte(`{"uuid":"00000000-0000-0000-0000-000000000000","image_name":"my-image","name":"org.osbuild.aws","created":"0001-01-01T00:00:00Z","status":"WAITING","options":{"region":"us","accessKeyID":"id","secretAccessKey":"key","sessionToken":"token","bucket":"bkt","key":"key","shareWithAccounts":["123456789"],"filename":"image.qcow2"},"osbuild_artifact":{"export_filename":"image.qcow2","export_name":""}}`),
target: &Target{
ImageName: "my-image",
OsbuildArtifact: OsbuildArtifact{

View file

@ -2251,6 +2251,7 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
workerServerTarget := target.NewWorkerServerTarget()
workerServerTarget.ImageName = imageType.Filename()
workerServerTarget.OsbuildArtifact.ExportFilename = imageType.Filename()
workerServerTarget.OsbuildArtifact.ExportName = imageType.Exports()[0]
targets = append(targets, workerServerTarget)
if isRequestVersionAtLeast(params, 1) && cr.Upload != nil {
t := uploadRequestToTarget(*cr.Upload, imageType)
@ -2356,7 +2357,6 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
jobId, err = api.workers.EnqueueOSBuild(api.archName, &worker.OSBuildJob{
Manifest: manifest,
Targets: targets,
Exports: imageType.Exports(),
PipelineNames: &worker.PipelineNames{
Build: imageType.BuildPipelines(),
Payload: imageType.PayloadPipelines(),

View file

@ -690,6 +690,7 @@ func TestCompose(t *testing.T) {
ImageName: imgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
@ -716,6 +717,7 @@ func TestCompose(t *testing.T) {
ImageName: imgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
@ -726,6 +728,7 @@ func TestCompose(t *testing.T) {
ImageName: "test_upload",
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Options: &target.AWSTargetOptions{
Region: "frankfurt",
@ -757,6 +760,7 @@ func TestCompose(t *testing.T) {
ImageName: imgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
@ -793,6 +797,7 @@ func TestCompose(t *testing.T) {
ImageName: imgType2.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType2.Filename(),
ExportName: imgType2.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
@ -1733,6 +1738,7 @@ func TestComposePOST_ImageTypeDenylist(t *testing.T) {
ImageName: imgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
@ -1760,6 +1766,7 @@ func TestComposePOST_ImageTypeDenylist(t *testing.T) {
ImageName: imgType2.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType2.Filename(),
ExportName: imgType2.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},

View file

@ -244,6 +244,7 @@ func uploadRequestToTarget(u uploadRequest, imageType distro.ImageType) *target.
t.Uuid = uuid.New()
t.ImageName = u.ImageName
t.OsbuildArtifact.ExportFilename = imageType.Filename()
t.OsbuildArtifact.ExportName = imageType.Exports()[0]
t.Status = common.IBWaiting
t.Created = time.Now()

View file

@ -20,10 +20,25 @@ type OSBuildJob struct {
// Index of the ManifestJobByIDResult instance in the job's dynamic arguments slice
ManifestDynArgsIdx *int `json:"manifest_dyn_args_idx,omitempty"`
Targets []*target.Target `json:"targets,omitempty"`
Exports []string `json:"export_stages,omitempty"`
PipelineNames *PipelineNames `json:"pipeline_names,omitempty"`
}
// OsbuildExports returns a slice of osbuild pipeline names, which should be
// exported as part of running osbuild image build for the job. The pipeline
// names are gathered from the targets specified in the job.
func (j OSBuildJob) OsbuildExports() []string {
exports := []string{}
seenExports := map[string]bool{}
for _, target := range j.Targets {
exists := seenExports[target.OsbuildArtifact.ExportName]
if !exists {
seenExports[target.OsbuildArtifact.ExportName] = true
exports = append(exports, target.OsbuildArtifact.ExportName)
}
}
return exports
}
type JobResult struct {
JobError *clienterrors.Error `json:"job_error,omitempty"`
}
@ -239,21 +254,64 @@ type updateJobRequest struct {
func (j *OSBuildJob) UnmarshalJSON(data []byte) error {
// handles unmarshalling old jobs in the queue that don't contain newer fields
// adds default/fallback values to missing data
type aliastype OSBuildJob
var alias aliastype
if err := json.Unmarshal(data, &alias); err != nil {
type aliasType OSBuildJob
type compatType struct {
aliasType
// Deprecated: Exports should not be used. The export is set in the `Target.OsbuildExport`
Exports []string `json:"export_stages,omitempty"`
}
var compat compatType
if err := json.Unmarshal(data, &compat); err != nil {
return err
}
if alias.PipelineNames == nil {
alias.PipelineNames = &PipelineNames{
if compat.PipelineNames == nil {
compat.PipelineNames = &PipelineNames{
Build: distro.BuildPipelinesFallback(),
Payload: distro.PayloadPipelinesFallback(),
}
}
*j = OSBuildJob(alias)
// Exports used to be specified in the job, but there could be always only a single export specified.
if len(compat.Exports) != 0 {
if len(compat.Exports) > 1 {
return fmt.Errorf("osbuild job has more than one exports specified")
}
export := compat.Exports[0]
// add the single export to each target
for idx := range compat.Targets {
target := compat.Targets[idx]
if target.OsbuildArtifact.ExportName == "" {
target.OsbuildArtifact.ExportName = export
} else if target.OsbuildArtifact.ExportName != export {
return fmt.Errorf("osbuild job has different global exports and export in the target specified at the same time")
}
compat.Targets[idx] = target
}
}
*j = OSBuildJob(compat.aliasType)
return nil
}
func (j OSBuildJob) MarshalJSON() ([]byte, error) {
type aliasType OSBuildJob
type compatType struct {
aliasType
// Depredated: Exports should not be used. The export is set in the `Target.OsbuildExport`
Exports []string `json:"export_stages,omitempty"`
}
compat := compatType{
aliasType: aliasType(j),
}
compat.Exports = j.OsbuildExports()
data, err := json.Marshal(&compat)
if err != nil {
return nil, err
}
return data, nil
}
func (j *OSBuildJobResult) UnmarshalJSON(data []byte) error {
// handles unmarshalling old jobs in the queue that don't contain newer fields
// adds default/fallback values to missing data

View file

@ -1,8 +1,11 @@
package worker
import (
"encoding/json"
"fmt"
"testing"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/target"
"github.com/osbuild/osbuild-composer/internal/worker/clienterrors"
"github.com/stretchr/testify/assert"
@ -83,3 +86,250 @@ func TestOSBuildJobResultTargetErrors(t *testing.T) {
assert.EqualValues(t, testCase.targetErrors, testCase.jobResult.TargetErrors())
}
}
func TestOSBuildJobExports(t *testing.T) {
testCases := []struct {
job *OSBuildJob
expectedExports []string
}{
// one target with export set
{
job: &OSBuildJob{
Manifest: []byte("manifest"),
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
},
},
},
expectedExports: []string{"archive"},
},
// multiple targets with different exports set
{
job: &OSBuildJob{
Manifest: []byte("manifest"),
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
},
{
Name: target.TargetNameAWSS3,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "image",
},
},
},
},
expectedExports: []string{"archive", "image"},
},
// multiple targets with the same export
{
job: &OSBuildJob{
Manifest: []byte("manifest"),
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
},
{
Name: target.TargetNameAWSS3,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
},
},
},
expectedExports: []string{"archive"},
},
}
for idx, testCase := range testCases {
t.Run(fmt.Sprintf("case #%d", idx), func(t *testing.T) {
assert.EqualValues(t, testCase.expectedExports, testCase.job.OsbuildExports())
})
}
}
// Test that that exports set in the OSBuildJob get added to all targets
// defined in the job.
// This covers the case when new worker receives a job from old composer.
// This covers the case when new worker receives a job from new composer.
func TestOSBuildJobExportsCompatibilityUnmarshal(t *testing.T) {
testCases := []struct {
jobJSON []byte
job *OSBuildJob
expectedExports []string
err bool
}{
// Test that one export specified on the job level gets added to each target
{
jobJSON: []byte(`{"export_stages":["archive"],"targets":[{"name":"org.osbuild.aws","options":{}}]}`),
job: &OSBuildJob{
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSTargetOptions{},
},
},
PipelineNames: &PipelineNames{
Build: distro.BuildPipelinesFallback(),
Payload: distro.PayloadPipelinesFallback(),
},
},
expectedExports: []string{"archive"},
},
// Test that one export specified on the job level gets added to each target
{
jobJSON: []byte(`{"export_stages":["archive"],"targets":[{"name":"org.osbuild.aws","options":{}},{"name":"org.osbuild.aws.s3","options":{}}]}`),
job: &OSBuildJob{
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSTargetOptions{},
},
{
Name: target.TargetNameAWSS3,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSS3TargetOptions{},
},
},
PipelineNames: &PipelineNames{
Build: distro.BuildPipelinesFallback(),
Payload: distro.PayloadPipelinesFallback(),
},
},
expectedExports: []string{"archive"},
},
// Test that the job as Marshalled by the current compatibility code is also acceptable/
// Such job has exports set on the job level, but also in the targets
{
jobJSON: []byte(`{"export_stages":["archive"],"targets":[{"name":"org.osbuild.aws","options":{},"osbuild_export":"archive"},{"name":"org.osbuild.aws.s3","options":{},"osbuild_export":"archive"}]}`),
job: &OSBuildJob{
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSTargetOptions{},
},
{
Name: target.TargetNameAWSS3,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSS3TargetOptions{},
},
},
PipelineNames: &PipelineNames{
Build: distro.BuildPipelinesFallback(),
Payload: distro.PayloadPipelinesFallback(),
},
},
expectedExports: []string{"archive"},
},
// Test that different exports defined on the job and target level generate an error
{
jobJSON: []byte(`{"export_stages":["archive"],"targets":[{"name":"org.osbuild.aws","options":{},"osbuild_artifact":{"export_name":"image"}},{"name":"org.osbuild.aws.s3","options":{},"osbuild_artifact":{"export_name":"archive"}}]}`),
err: true,
},
// Test that different exports defined on the job and target level generate an error
{
jobJSON: []byte(`{"export_stages":["image"],"targets":[{"name":"org.osbuild.aws","options":{},"osbuild_artifact":{"export_name":"archive"}},{"name":"org.osbuild.aws.s3","options":{},"osbuild_artifact":{"export_name":"archive"}}]}`),
err: true,
},
// Test that multiple exports defined on the job level generate an error
{
jobJSON: []byte(`{"export_stages":["archive","image"],"targets":[{"name":"org.osbuild.aws","options":{},"osbuild_export":"archive"},{"name":"org.osbuild.aws.s3","options":{},"osbuild_export":"archive"}]}`),
err: true,
},
}
for idx, testCase := range testCases {
t.Run(fmt.Sprintf("Case #%d", idx), func(t *testing.T) {
gotJob := OSBuildJob{}
err := json.Unmarshal(testCase.jobJSON, &gotJob)
if testCase.err {
assert.Error(t, err)
} else {
assert.Nil(t, err)
assert.EqualValues(t, testCase.job, &gotJob)
assert.EqualValues(t, testCase.expectedExports, gotJob.OsbuildExports())
}
})
}
}
// Test that that exports set in the OSBuildJob target get added to the job
// definition itself.
// This covers the case when jobs from new composer are to be picked by old worker.
// This covers the case when new worker receives a job from new composer.
func TestOSBuildJobExportsCompatibilityMarshal(t *testing.T) {
testCases := []struct {
jobJSON []byte
job *OSBuildJob
}{
// Test that the export specified in the target is set also on the job level as it used to be in the past
{
jobJSON: []byte(`{"targets":[{"uuid":"00000000-0000-0000-0000-000000000000","image_name":"","name":"org.osbuild.aws","created":"0001-01-01T00:00:00Z","status":"WAITING","options":{"region":"","accessKeyID":"","secretAccessKey":"","sessionToken":"","bucket":"","key":"","shareWithAccounts":null,"filename":""},"osbuild_artifact":{"export_filename":"","export_name":"archive"}}],"export_stages":["archive"]}`),
job: &OSBuildJob{
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSTargetOptions{},
},
},
},
},
// Test that the export specified in multiple targets is set also on the job level as it used to be in the past.
// We do not test with multiple different exports, because multiple exports in job definition were never allowed.
{
jobJSON: []byte(`{"targets":[{"uuid":"00000000-0000-0000-0000-000000000000","image_name":"","name":"org.osbuild.aws","created":"0001-01-01T00:00:00Z","status":"WAITING","options":{"region":"","accessKeyID":"","secretAccessKey":"","sessionToken":"","bucket":"","key":"","shareWithAccounts":null,"filename":""},"osbuild_artifact":{"export_filename":"","export_name":"archive"}},{"uuid":"00000000-0000-0000-0000-000000000000","image_name":"","name":"org.osbuild.aws.s3","created":"0001-01-01T00:00:00Z","status":"WAITING","options":{"region":"","accessKeyID":"","secretAccessKey":"","sessionToken":"","bucket":"","key":"","endpoint":"","ca_bundle":"","skip_ssl_verification":false,"filename":""},"osbuild_artifact":{"export_filename":"","export_name":"archive"}}],"export_stages":["archive"]}`),
job: &OSBuildJob{
Targets: []*target.Target{
{
Name: target.TargetNameAWS,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSTargetOptions{},
},
{
Name: target.TargetNameAWSS3,
OsbuildArtifact: target.OsbuildArtifact{
ExportName: "archive",
},
Options: &target.AWSS3TargetOptions{},
},
},
},
},
}
for idx, testCase := range testCases {
t.Run(fmt.Sprintf("Case #%d", idx), func(t *testing.T) {
gotJSON, err := json.Marshal(testCase.job)
assert.Nil(t, err)
assert.EqualValues(t, testCase.jobJSON, gotJSON)
})
}
}

View file

@ -225,17 +225,19 @@ func TestArgs(t *testing.T) {
job := worker.OSBuildJob{
Manifest: manifest,
Exports: []string{"assembler"},
PipelineNames: &worker.PipelineNames{
Build: []string{"b"},
Payload: []string{"x", "y", "z"},
},
Targets: []*target.Target{
{
Name: target.TargetNameWorkerServer,
ImageName: "test-image",
ExportFilename: "test-image",
Options: &target.WorkerServerTargetOptions{},
Name: target.TargetNameWorkerServer,
ImageName: "test-image",
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: "test-image",
ExportName: "assembler",
},
Options: &target.WorkerServerTargetOptions{},
},
},
}
@ -409,13 +411,15 @@ func TestMixedOSBuildJob(t *testing.T) {
oldJob := worker.OSBuildJob{
Manifest: emptyManifestV2,
Exports: []string{"assembler"},
Targets: []*target.Target{
{
Name: target.TargetNameWorkerServer,
ImageName: "no-pipeline-names",
ExportFilename: "no-pipeline-names",
Options: &target.WorkerServerTargetOptions{},
Name: target.TargetNameWorkerServer,
ImageName: "no-pipeline-names",
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: "no-pipeline-names",
ExportName: "assembler",
},
Options: &target.WorkerServerTargetOptions{},
},
},
}
@ -424,17 +428,19 @@ func TestMixedOSBuildJob(t *testing.T) {
newJob := worker.OSBuildJob{
Manifest: emptyManifestV2,
Exports: []string{"assembler"},
PipelineNames: &worker.PipelineNames{
Build: []string{"build"},
Payload: []string{"other", "pipelines"},
},
Targets: []*target.Target{
{
Name: target.TargetNameWorkerServer,
ImageName: "with-pipeline-names",
ExportFilename: "with-pipeline-names",
Options: &target.WorkerServerTargetOptions{},
Name: target.TargetNameWorkerServer,
ImageName: "with-pipeline-names",
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: "with-pipeline-names",
ExportName: "assembler",
},
Options: &target.WorkerServerTargetOptions{},
},
},
}