From 2ff34767cc38e8bc8ce622fb8a952322876c25f6 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Wed, 20 Jul 2022 22:48:00 +0200 Subject: [PATCH] worker/osbuild: workaround cloud upload for compressed images The AWS and Azure RHUI images are produced as compressed archives, which can be uploaded to Koji, but they can't be uploaded to the cloud provider in this format. To support cloud upload for these types of images, we need to decompress them before the upload. Add a workaround for AWS and AzureImage targets to check if the image has `.xz` suffix and if yes, decompress it before uploading to cloud. This workaround is needed until image definitions will support and use multiple exports per image to allow using different export per upload target. --- cmd/osbuild-worker/jobimpl-osbuild.go | 50 +++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/cmd/osbuild-worker/jobimpl-osbuild.go b/cmd/osbuild-worker/jobimpl-osbuild.go index 25185c168..2733291a0 100644 --- a/cmd/osbuild-worker/jobimpl-osbuild.go +++ b/cmd/osbuild-worker/jobimpl-osbuild.go @@ -9,6 +9,7 @@ import ( "math/big" "net/url" "os" + "os/exec" "path" "strings" @@ -418,7 +419,22 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error { if impl.AWSBucket != "" { bucket = impl.AWSBucket } - _, err = a.Upload(path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename), bucket, key) + + // TODO: Remove this once multiple exports will be supported and used by image definitions + // RHUI images tend to be produced as archives in Brew to save disk space, + // however they can't be imported to the cloud provider as an archive. + // Workaround this situation for Koji composes by checking if the image file + // is an archive and if it is, extract it before uploading to the cloud. + imagePath := path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename) + if strings.HasSuffix(imagePath, ".xz") { + imagePath, err = extractXzArchive(imagePath) + if err != nil { + targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorTargetError, "Failed to extract compressed image", err.Error()) + break + } + } + + _, err = a.Upload(imagePath, bucket, key) if err != nil { targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorUploadingImage, err.Error()) break @@ -614,6 +630,20 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error { // Azure cannot create an image from a blob without .vhd extension blobName := azure.EnsureVHDExtension(jobTarget.ImageName) + // TODO: Remove this once multiple exports will be supported and used by image definitions + // RHUI images tend to be produced as archives in Brew to save disk space, + // however they can't be imported to the cloud provider as an archive. + // Workaround this situation for Koji composes by checking if the image file + // is an archive and if it is, extract it before uploading to the cloud. + imagePath := path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename) + if strings.HasSuffix(imagePath, ".xz") { + imagePath, err = extractXzArchive(imagePath) + if err != nil { + targetResult.TargetError = clienterrors.WorkerClientError(clienterrors.ErrorTargetError, "Failed to extract compressed image", err.Error()) + break + } + } + logWithId.Info("[Azure] ⬆ Uploading the image") err = azureStorageClient.UploadPageBlob( azure.BlobMetadata{ @@ -621,7 +651,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error { ContainerName: storageContainer, BlobName: blobName, }, - path.Join(outputDirectory, jobTarget.OsbuildArtifact.ExportName, jobTarget.OsbuildArtifact.ExportFilename), + imagePath, azure.DefaultUploadThreads, ) if err != nil { @@ -790,3 +820,19 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error { return nil } + +// extractXzArchive extracts the provided XZ archive in the same directory +// and returns the path to decompressed file. +func extractXzArchive(archivePath string) (string, error) { + workingDir, archiveFilename := path.Split(archivePath) + decompressedFilename := strings.TrimSuffix(archiveFilename, ".xz") + + cmd := exec.Command("xz", "-d", archivePath) + cmd.Dir = workingDir + err := cmd.Run() + if err != nil { + return "", err + } + + return path.Join(workingDir, decompressedFilename), nil +}