The internal blueprint implementation has been removed from osbuild/images. Conversion from osbuild/blueprint blueprints to osbuild/images blueprints is no longer necessary.
145 lines
4.2 KiB
Go
145 lines
4.2 KiB
Go
package v2
|
|
|
|
// DepsolveRequest methods
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"fmt"
|
|
"math"
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/osbuild/images/pkg/distrofactory"
|
|
"github.com/osbuild/images/pkg/reporegistry"
|
|
"github.com/osbuild/images/pkg/rpmmd"
|
|
"github.com/osbuild/images/pkg/sbom"
|
|
"github.com/osbuild/osbuild-composer/internal/worker"
|
|
)
|
|
|
|
func (request *DepsolveRequest) Depsolve(df *distrofactory.Factory, rr *reporegistry.RepoRegistry, workers *worker.Server) ([]rpmmd.PackageSpec, error) {
|
|
// Convert the requested blueprint to a composer blueprint
|
|
bp, err := ConvertRequestBP(request.Blueprint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If the blueprint include distro and/or architecture they must match the ones
|
|
// in request -- otherwise the results may not be what is expected.
|
|
if len(bp.Distro) > 0 && bp.Distro != request.Distribution {
|
|
return nil, HTTPError(ErrorMismatchedDistribution)
|
|
}
|
|
|
|
// XXX CloudAPI Blueprint needs to have missing Architecture added first
|
|
/*
|
|
if len(bp.Architecture) > 0 && bp.Architecture != request.Architecture {
|
|
return nil, HTTPError(ErrorMismatchedArchitecture)
|
|
}
|
|
*/
|
|
distro := df.GetDistro(request.Distribution)
|
|
if distro == nil {
|
|
return nil, HTTPError(ErrorUnsupportedDistribution)
|
|
}
|
|
distroArch, err := distro.GetArch(request.Architecture)
|
|
if err != nil {
|
|
return nil, HTTPErrorWithInternal(ErrorUnsupportedArchitecture, err)
|
|
}
|
|
|
|
var repos []rpmmd.RepoConfig
|
|
if request.Repositories != nil {
|
|
repos, err = convertRepos(*request.Repositories, []Repository{}, []string{})
|
|
if err != nil {
|
|
// Error comes from genRepoConfig and is already an HTTPError
|
|
return nil, err
|
|
}
|
|
} else {
|
|
repos, err = rr.ReposByArchName(request.Distribution, distroArch.Name(), false)
|
|
if err != nil {
|
|
return nil, HTTPErrorWithInternal(ErrorInvalidRepository, err)
|
|
}
|
|
}
|
|
|
|
packageSet := make(map[string][]rpmmd.PackageSet, 1)
|
|
|
|
// If there is an optional image_type we use manifest to setup the package/repo list
|
|
if request.ImageType != nil {
|
|
imageType, err := distroArch.GetImageType(imageTypeFromApiImageType(*request.ImageType, distroArch))
|
|
if err != nil {
|
|
return nil, HTTPError(ErrorUnsupportedImageType)
|
|
}
|
|
|
|
// 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()
|
|
|
|
ir := imageRequest{
|
|
imageType: imageType,
|
|
repositories: repos,
|
|
manifestSeed: manifestSeed,
|
|
}
|
|
|
|
manifestSource, _, err := ir.imageType.Manifest(&bp, ir.imageOptions, ir.repositories, &ir.manifestSeed)
|
|
if err != nil {
|
|
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, err)
|
|
}
|
|
|
|
packageSet = manifestSource.GetPackageSetChains()
|
|
} else {
|
|
// Send the depsolve request to the worker
|
|
packageSet["os"] = []rpmmd.PackageSet{
|
|
{
|
|
Include: bp.GetPackages(),
|
|
EnabledModules: bp.GetEnabledModules(),
|
|
Repositories: repos,
|
|
},
|
|
}
|
|
}
|
|
|
|
depsolveJobID, err := workers.EnqueueDepsolve(&worker.DepsolveJob{
|
|
PackageSets: packageSet,
|
|
ModulePlatformID: distro.ModulePlatformID(),
|
|
Arch: distroArch.Name(),
|
|
Releasever: distro.Releasever(),
|
|
SbomType: sbom.StandardTypeNone,
|
|
}, "")
|
|
if err != nil {
|
|
return nil, HTTPErrorWithInternal(ErrorEnqueueingJob, err)
|
|
}
|
|
|
|
// Limit how long a depsolve can take
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*depsolveTimeoutMin)
|
|
defer cancel()
|
|
|
|
// Wait until depsolve job is finished, fails, or is canceled
|
|
var result worker.DepsolveJobResult
|
|
for {
|
|
time.Sleep(time.Millisecond * 50)
|
|
info, err := workers.DepsolveJobInfo(depsolveJobID, &result)
|
|
if err != nil {
|
|
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, err)
|
|
}
|
|
if result.JobError != nil {
|
|
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, err)
|
|
}
|
|
if info.JobStatus != nil {
|
|
if info.JobStatus.Canceled {
|
|
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, err)
|
|
}
|
|
|
|
if !info.JobStatus.Finished.IsZero() {
|
|
break
|
|
}
|
|
}
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, fmt.Errorf("Depsolve job %q timed out", depsolveJobID))
|
|
default:
|
|
}
|
|
}
|
|
|
|
return result.PackageSpecs["os"], nil
|
|
}
|