cloudapi: Add ability to skip uploading and save image locally

During development it can be very useful to store the results locally
instead of uploading to a remote system. This implements a development
only option to help with that.

To use it you need to add OSBUILD_LOCALSAVE to the server's environment.
This can be done by editing /usr/lib/systemd/system/osbuild-composer.service
and adding:

Environment="OSBUILD_LOCALSAVE=1"

You can then use an 'upload_options' object to skip trying to upload to
the default service for the type of image, eg:

    "image_requests": [
    {
      "architecture": "x86_64",
      "image_type": "guest-image",
      "upload_options": {
          "local_save": true
      },
      ...
    }]

The results will be saved to /var/lib/osbuild-composer/artifacts/UUID/
using the default filename for the image type.

If local_save is used without OSBUILD_LOCALSAVE being set it will return
an error with id=36 saying 'local_save is not enabled'.
This commit is contained in:
Brian C. Lane 2023-07-26 16:00:35 -07:00 committed by Tomáš Hozza
parent 98c7a06545
commit 139bf4dec2
4 changed files with 195 additions and 128 deletions

View file

@ -8,6 +8,7 @@ import (
"math"
"math/big"
"net/http"
"os"
"strconv"
"strings"
@ -106,6 +107,33 @@ func splitExtension(filename string) string {
return "." + strings.Join(filenameParts[1:], ".")
}
// isLocalSave checks the environment to see if a local save has been enabled
// and tests the UploadOptions to see if it has been selected
func isLocalSave(options *UploadOptions) (bool, error) {
if options == nil {
return false, nil
}
var local LocalUploadOptions
// This is a terrible way to do this, but it is imposed by the OpenAPI code generator so...
j, err := json.Marshal(*options)
if err != nil {
return false, nil
}
err = json.Unmarshal(j, &local)
if err != nil {
return false, nil
}
// Return an error if local_save is set but not enabled
_, enabled := os.LookupEnv("OSBUILD_LOCALSAVE")
if !enabled && local.LocalSave {
return false, HTTPError(ErrorLocalSaveNotEnabled)
}
return enabled && local.LocalSave, nil
}
type imageRequest struct {
imageType distro.ImageType
arch distro.Arch
@ -196,12 +224,25 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
return err
}
// Check to see if local_save is enabled and set
localSave, err := isLocalSave(ir.UploadOptions)
if err != nil {
return err
}
var irTarget *target.Target
if ir.UploadOptions == nil {
// nowhere to put the image, this is a user error
if request.Koji == nil {
return HTTPError(ErrorJSONUnMarshallingError)
}
} else if localSave {
// Override the image type upload selection and save it locally
// Final image is in /var/lib/osbuild-composer/artifacts/UUID/
irTarget = target.NewWorkerServerTarget()
irTarget.ImageName = imageType.Filename()
irTarget.OsbuildArtifact.ExportFilename = imageType.Filename()
irTarget.OsbuildArtifact.ExportName = imageType.Exports()[0]
} else {
// Get the target for the selected image type
irTarget, err = ir.GetTarget(&request, imageType)