cloudapi: split GetImageRequests off PostCompose
This allows us to do some testing of the ComposeRequest => []imageRequest conversion without actually enqueueing any jobs (which requires us to do quite a lot of setup in the testsuite). Signed-off-by: Ondřej Budai <ondrej@budai.cz>
This commit is contained in:
parent
28ef0bc855
commit
504a51089c
2 changed files with 131 additions and 119 deletions
|
|
@ -2,7 +2,13 @@ package v2
|
||||||
|
|
||||||
// ComposeRequest methods to make it easier to use and test
|
// ComposeRequest methods to make it easier to use and test
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/osbuild/images/pkg/distrofactory"
|
||||||
|
"github.com/osbuild/images/pkg/rhsm/facts"
|
||||||
|
"github.com/osbuild/osbuild-composer/internal/target"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/osbuild/images/pkg/disk"
|
"github.com/osbuild/images/pkg/disk"
|
||||||
|
|
@ -927,3 +933,127 @@ func (request *ComposeRequest) GetPartitioningMode() (disk.PartitioningMode, err
|
||||||
|
|
||||||
return disk.AutoLVMPartitioningMode, HTTPError(ErrorInvalidPartitioningMode)
|
return disk.AutoLVMPartitioningMode, HTTPError(ErrorInvalidPartitioningMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetImageRequests converts a composeRequest structure from the API to an intermediate imageRequest structure
|
||||||
|
// that's used for generating manifests and orchestrating worker jobs.
|
||||||
|
func (request *ComposeRequest) GetImageRequests(distroFactory *distrofactory.Factory) ([]imageRequest, error) {
|
||||||
|
distribution := distroFactory.GetDistro(request.Distribution)
|
||||||
|
if distribution == nil {
|
||||||
|
return nil, HTTPError(ErrorUnsupportedDistribution)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenAPI enforces blueprint or customization, not both
|
||||||
|
// but check anyway
|
||||||
|
if request.Customizations != nil && request.Blueprint != nil {
|
||||||
|
return nil, HTTPError(ErrorBlueprintOrCustomNotBoth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a blueprint from the request
|
||||||
|
bp, err := request.GetBlueprint()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the user-defined repositories only to the depsolve job for the
|
||||||
|
// payload (the packages for the final image)
|
||||||
|
payloadRepositories := request.GetPayloadRepositories()
|
||||||
|
|
||||||
|
// use the same seed for all images so we get the same IDs
|
||||||
|
bigSeed, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
|
||||||
|
if err != nil {
|
||||||
|
return nil, HTTPError(ErrorFailedToGenerateManifestSeed)
|
||||||
|
}
|
||||||
|
manifestSeed := bigSeed.Int64()
|
||||||
|
|
||||||
|
// For backwards compatibility, we support both a single image request
|
||||||
|
// as well as an array of requests in the API. Exactly one must be
|
||||||
|
// specified.
|
||||||
|
if request.ImageRequest != nil {
|
||||||
|
if request.ImageRequests != nil {
|
||||||
|
// we should really be using oneOf in the spec
|
||||||
|
return nil, HTTPError(ErrorInvalidNumberOfImageBuilds)
|
||||||
|
}
|
||||||
|
request.ImageRequests = &[]ImageRequest{*request.ImageRequest}
|
||||||
|
}
|
||||||
|
if request.ImageRequests == nil {
|
||||||
|
return nil, HTTPError(ErrorInvalidNumberOfImageBuilds)
|
||||||
|
}
|
||||||
|
var irs []imageRequest
|
||||||
|
for _, ir := range *request.ImageRequests {
|
||||||
|
arch, err := distribution.GetArch(ir.Architecture)
|
||||||
|
if err != nil {
|
||||||
|
return nil, HTTPError(ErrorUnsupportedArchitecture)
|
||||||
|
}
|
||||||
|
imageType, err := arch.GetImageType(imageTypeFromApiImageType(ir.ImageType, arch))
|
||||||
|
if err != nil {
|
||||||
|
return nil, HTTPError(ErrorUnsupportedImageType)
|
||||||
|
}
|
||||||
|
|
||||||
|
repos, err := convertRepos(ir.Repositories, payloadRepositories, imageType.PayloadPackageSets())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the initial ImageOptions with image size set
|
||||||
|
imageOptions := ir.GetImageOptions(imageType, bp)
|
||||||
|
|
||||||
|
if request.Koji == nil {
|
||||||
|
imageOptions.Facts = &facts.ImageOptions{
|
||||||
|
APIType: facts.CLOUDV2_APITYPE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Subscription from the compose request
|
||||||
|
imageOptions.Subscription = request.GetSubscription()
|
||||||
|
|
||||||
|
// Set PartitioningMode from the compose request
|
||||||
|
imageOptions.PartitioningMode, err = request.GetPartitioningMode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set OSTree options from the image request
|
||||||
|
imageOptions.OSTree, err = ir.GetOSTreeOptions()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if local_save is enabled and set
|
||||||
|
localSave, err := isLocalSave(ir.UploadOptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var irTargets []*target.Target
|
||||||
|
if ir.UploadOptions == nil && (ir.UploadTargets == nil || len(*ir.UploadTargets) == 0) {
|
||||||
|
// nowhere to put the image, this is a user error
|
||||||
|
if request.Koji == nil {
|
||||||
|
return nil, 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/
|
||||||
|
srvTarget := target.NewWorkerServerTarget()
|
||||||
|
srvTarget.ImageName = imageType.Filename()
|
||||||
|
srvTarget.OsbuildArtifact.ExportFilename = imageType.Filename()
|
||||||
|
srvTarget.OsbuildArtifact.ExportName = imageType.Exports()[0]
|
||||||
|
irTargets = []*target.Target{srvTarget}
|
||||||
|
} else {
|
||||||
|
// Get the target for the selected image type
|
||||||
|
irTargets, err = ir.GetTargets(request, imageType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irs = append(irs, imageRequest{
|
||||||
|
imageType: imageType,
|
||||||
|
repositories: repos,
|
||||||
|
imageOptions: imageOptions,
|
||||||
|
targets: irTargets,
|
||||||
|
blueprint: bp,
|
||||||
|
manifestSeed: manifestSeed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return irs, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,9 @@
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||||
"math"
|
|
||||||
"math/big"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -19,7 +16,6 @@ import (
|
||||||
"github.com/osbuild/images/pkg/distro"
|
"github.com/osbuild/images/pkg/distro"
|
||||||
"github.com/osbuild/images/pkg/manifest"
|
"github.com/osbuild/images/pkg/manifest"
|
||||||
"github.com/osbuild/images/pkg/osbuild"
|
"github.com/osbuild/images/pkg/osbuild"
|
||||||
"github.com/osbuild/images/pkg/rhsm/facts"
|
|
||||||
"github.com/osbuild/images/pkg/rpmmd"
|
"github.com/osbuild/images/pkg/rpmmd"
|
||||||
"github.com/osbuild/osbuild-composer/internal/common"
|
"github.com/osbuild/osbuild-composer/internal/common"
|
||||||
"github.com/osbuild/osbuild-composer/internal/target"
|
"github.com/osbuild/osbuild-composer/internal/target"
|
||||||
|
|
@ -157,125 +153,11 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
|
||||||
return HTTPErrorWithInternal(ErrorTenantNotFound, err)
|
return HTTPErrorWithInternal(ErrorTenantNotFound, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
distribution := h.server.distros.GetDistro(request.Distribution)
|
irs, err := request.GetImageRequests(h.server.distros)
|
||||||
if distribution == nil {
|
|
||||||
return HTTPError(ErrorUnsupportedDistribution)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenAPI enforces blueprint or customization, not both
|
|
||||||
// but check anyway
|
|
||||||
if request.Customizations != nil && request.Blueprint != nil {
|
|
||||||
return HTTPError(ErrorBlueprintOrCustomNotBoth)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a blueprint from the request
|
|
||||||
bp, err := request.GetBlueprint()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the user-defined repositories only to the depsolve job for the
|
|
||||||
// payload (the packages for the final image)
|
|
||||||
payloadRepositories := request.GetPayloadRepositories()
|
|
||||||
|
|
||||||
// use the same seed for all images so we get the same IDs
|
|
||||||
bigSeed, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
|
|
||||||
if err != nil {
|
|
||||||
return HTTPError(ErrorFailedToGenerateManifestSeed)
|
|
||||||
}
|
|
||||||
manifestSeed := bigSeed.Int64()
|
|
||||||
|
|
||||||
// For backwards compatibility, we support both a single image request
|
|
||||||
// as well as an array of requests in the API. Exactly one must be
|
|
||||||
// specified.
|
|
||||||
if request.ImageRequest != nil {
|
|
||||||
if request.ImageRequests != nil {
|
|
||||||
// we should really be using oneOf in the spec
|
|
||||||
return HTTPError(ErrorInvalidNumberOfImageBuilds)
|
|
||||||
}
|
|
||||||
request.ImageRequests = &[]ImageRequest{*request.ImageRequest}
|
|
||||||
}
|
|
||||||
if request.ImageRequests == nil {
|
|
||||||
return HTTPError(ErrorInvalidNumberOfImageBuilds)
|
|
||||||
}
|
|
||||||
var irs []imageRequest
|
|
||||||
for _, ir := range *request.ImageRequests {
|
|
||||||
arch, err := distribution.GetArch(ir.Architecture)
|
|
||||||
if err != nil {
|
|
||||||
return HTTPError(ErrorUnsupportedArchitecture)
|
|
||||||
}
|
|
||||||
imageType, err := arch.GetImageType(imageTypeFromApiImageType(ir.ImageType, arch))
|
|
||||||
if err != nil {
|
|
||||||
return HTTPError(ErrorUnsupportedImageType)
|
|
||||||
}
|
|
||||||
|
|
||||||
repos, err := convertRepos(ir.Repositories, payloadRepositories, imageType.PayloadPackageSets())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the initial ImageOptions with image size set
|
|
||||||
imageOptions := ir.GetImageOptions(imageType, bp)
|
|
||||||
|
|
||||||
if request.Koji == nil {
|
|
||||||
imageOptions.Facts = &facts.ImageOptions{
|
|
||||||
APIType: facts.CLOUDV2_APITYPE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set Subscription from the compose request
|
|
||||||
imageOptions.Subscription = request.GetSubscription()
|
|
||||||
|
|
||||||
// Set PartitioningMode from the compose request
|
|
||||||
imageOptions.PartitioningMode, err = request.GetPartitioningMode()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set OSTree options from the image request
|
|
||||||
imageOptions.OSTree, err = ir.GetOSTreeOptions()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if local_save is enabled and set
|
|
||||||
localSave, err := isLocalSave(ir.UploadOptions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var irTargets []*target.Target
|
|
||||||
if ir.UploadOptions == nil && (ir.UploadTargets == nil || len(*ir.UploadTargets) == 0) {
|
|
||||||
// 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/
|
|
||||||
srvTarget := target.NewWorkerServerTarget()
|
|
||||||
srvTarget.ImageName = imageType.Filename()
|
|
||||||
srvTarget.OsbuildArtifact.ExportFilename = imageType.Filename()
|
|
||||||
srvTarget.OsbuildArtifact.ExportName = imageType.Exports()[0]
|
|
||||||
irTargets = []*target.Target{srvTarget}
|
|
||||||
} else {
|
|
||||||
// Get the target for the selected image type
|
|
||||||
irTargets, err = ir.GetTargets(&request, imageType)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
irs = append(irs, imageRequest{
|
|
||||||
imageType: imageType,
|
|
||||||
repositories: repos,
|
|
||||||
imageOptions: imageOptions,
|
|
||||||
targets: irTargets,
|
|
||||||
blueprint: bp,
|
|
||||||
manifestSeed: manifestSeed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var id uuid.UUID
|
var id uuid.UUID
|
||||||
if request.Koji != nil {
|
if request.Koji != nil {
|
||||||
id, err = h.server.enqueueKojiCompose(uint64(request.Koji.TaskId), request.Koji.Server, request.Koji.Name, request.Koji.Version, request.Koji.Release, irs, channel)
|
id, err = h.server.enqueueKojiCompose(uint64(request.Koji.TaskId), request.Koji.Server, request.Koji.Name, request.Koji.Version, request.Koji.Release, irs, channel)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue