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:
parent
4e26ba82d0
commit
776a54135f
11 changed files with 363 additions and 38 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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{},
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue