cloudapi/v2: adapt to new oapi-codegen

Fixed distribution list type, function signatures (later versions parse
uuids in the generated code), defaults actually being set and added
x-go-type where needed.
This commit is contained in:
Sanne Raymaekers 2025-03-21 12:24:45 +01:00 committed by Ondřej Budai
parent 17416bf60b
commit 7652af83d7
12 changed files with 511 additions and 554 deletions

View file

@ -235,7 +235,7 @@ func (rbp *Blueprint) GetCustomizationsFromBlueprintRequest() (*blueprint.Custom
}
if rbpc.Openscap.PolicyId != nil {
oscap.PolicyID = *rbpc.Openscap.PolicyId
oscap.PolicyID = rbpc.Openscap.PolicyId.String()
}
if rbpc.Openscap.Datastream != nil {
@ -288,23 +288,27 @@ func (rbp *Blueprint) GetCustomizationsFromBlueprintRequest() (*blueprint.Custom
dirCustomization.Mode = *d.Mode
}
if d.User != nil {
dirCustomization.User = *d.User
if uid, ok := dirCustomization.User.(float64); ok {
// check if uid can be converted to int64
if uid != float64(int64(uid)) {
return nil, fmt.Errorf("invalid user %f: must be an integer", uid)
user0, err := d.User.AsDirectoryUser0()
if err == nil {
dirCustomization.User = user0
} else {
user1, err := d.User.AsDirectoryUser1()
if err != nil {
return nil, fmt.Errorf("invalid user: %w", err)
}
dirCustomization.User = int64(uid)
dirCustomization.User = user1
}
}
if d.Group != nil {
dirCustomization.Group = *d.Group
if gid, ok := dirCustomization.Group.(float64); ok {
// check if gid can be converted to int64
if gid != float64(int64(gid)) {
return nil, fmt.Errorf("invalid group %f: must be an integer", gid)
group0, err := d.Group.AsDirectoryGroup0()
if err == nil {
dirCustomization.Group = group0
} else {
group1, err := d.Group.AsDirectoryGroup1()
if err != nil {
return nil, fmt.Errorf("invalid group: %w", err)
}
dirCustomization.Group = int64(gid)
dirCustomization.Group = group1
}
}
if d.EnsureParents != nil {
@ -335,23 +339,29 @@ func (rbp *Blueprint) GetCustomizationsFromBlueprintRequest() (*blueprint.Custom
fileCustomization.Mode = *f.Mode
}
if f.User != nil {
fileCustomization.User = *f.User
if uid, ok := fileCustomization.User.(float64); ok {
// check if uid can be converted to int64
if uid != float64(int64(uid)) {
return nil, fmt.Errorf("invalid user %f: must be an integer", uid)
user0, err := f.User.AsBlueprintFileUser0()
if err == nil {
fileCustomization.User = user0
} else {
user1, err := f.User.AsBlueprintFileUser1()
if err != nil {
return nil, fmt.Errorf("invalid user: %w", err)
}
fileCustomization.User = int64(uid)
fileCustomization.User = user1
}
}
if f.Group != nil {
fileCustomization.Group = *f.Group
if gid, ok := fileCustomization.Group.(float64); ok {
// check if gid can be converted to int64
if gid != float64(int64(gid)) {
return nil, fmt.Errorf("invalid group %f: must be an integer", gid)
group0, err := f.Group.AsBlueprintFileGroup0()
if err == nil {
fileCustomization.Group = group0
} else {
group1, err := f.Group.AsBlueprintFileGroup1()
if err != nil {
return nil, fmt.Errorf("invalid group: %w", err)
}
if group1 != 0 {
fileCustomization.Group = group1
}
fileCustomization.Group = int64(gid)
}
}
fileCustomizations = append(fileCustomizations, fileCustomization)
@ -655,23 +665,27 @@ func (request *ComposeRequest) GetBlueprintFromCustomizations() (blueprint.Bluep
dirCustomization.Mode = *d.Mode
}
if d.User != nil {
dirCustomization.User = *d.User
if uid, ok := dirCustomization.User.(float64); ok {
// check if uid can be converted to int64
if uid != float64(int64(uid)) {
return bp, fmt.Errorf("invalid user %f: must be an integer", uid)
user0, err := d.User.AsDirectoryUser0()
if err == nil {
dirCustomization.User = user0
} else {
user1, err := d.User.AsDirectoryUser1()
if err != nil {
return bp, fmt.Errorf("invalid user: %w", err)
}
dirCustomization.User = int64(uid)
dirCustomization.User = user1
}
}
if d.Group != nil {
dirCustomization.Group = *d.Group
if gid, ok := dirCustomization.Group.(float64); ok {
// check if gid can be converted to int64
if gid != float64(int64(gid)) {
return bp, fmt.Errorf("invalid group %f: must be an integer", gid)
group0, err := d.Group.AsDirectoryGroup0()
if err == nil {
dirCustomization.Group = group0
} else {
group1, err := d.Group.AsDirectoryGroup1()
if err != nil {
return bp, fmt.Errorf("invalid group: %w", err)
}
dirCustomization.Group = int64(gid)
dirCustomization.Group = group1
}
}
if d.EnsureParents != nil {
@ -702,23 +716,27 @@ func (request *ComposeRequest) GetBlueprintFromCustomizations() (blueprint.Bluep
fileCustomization.Mode = *f.Mode
}
if f.User != nil {
fileCustomization.User = *f.User
if uid, ok := fileCustomization.User.(float64); ok {
// check if uid can be converted to int64
if uid != float64(int64(uid)) {
return bp, fmt.Errorf("invalid user %f: must be an integer", uid)
user0, err := f.User.AsFileUser0()
if err == nil {
fileCustomization.User = user0
} else {
user1, err := f.User.AsFileUser1()
if err != nil {
return bp, fmt.Errorf("invalid user: %w", err)
}
fileCustomization.User = int64(uid)
fileCustomization.User = user1
}
}
if f.Group != nil {
fileCustomization.Group = *f.Group
if gid, ok := fileCustomization.Group.(float64); ok {
// check if gid can be converted to int64
if gid != float64(int64(gid)) {
return bp, fmt.Errorf("invalid group %f: must be an integer", gid)
group0, err := f.Group.AsFileGroup0()
if err == nil {
fileCustomization.Group = group0
} else {
group1, err := f.Group.AsFileGroup1()
if err != nil {
return bp, fmt.Errorf("invalid group: %w", err)
}
fileCustomization.Group = int64(gid)
fileCustomization.Group = group1
}
}
fileCustomizations = append(fileCustomizations, fileCustomization)
@ -770,7 +788,7 @@ func (request *ComposeRequest) GetBlueprintFromCustomizations() (blueprint.Bluep
}
if request.Customizations.Openscap.PolicyId != nil {
openSCAPCustomization.PolicyID = *request.Customizations.Openscap.PolicyId
openSCAPCustomization.PolicyID = request.Customizations.Openscap.PolicyId.String()
}
if request.Customizations.Openscap.Tailoring != nil && request.Customizations.Openscap.JsonTailoring != nil {

View file

@ -201,8 +201,14 @@ func TestGetBlueprintFromCustomizations(t *testing.T) {
assert.Equal(t, "0.0.0", bp.Version)
assert.Nil(t, bp.Customizations)
// interface{} is a terrible idea. Work around it...
var rootStr interface{} = "root"
var dirUser Directory_User
require.NoError(t, dirUser.FromDirectoryUser0("root"))
var dirGroup Directory_Group
require.NoError(t, dirGroup.FromDirectoryGroup0("root"))
var fileUser File_User
require.NoError(t, fileUser.FromFileUser0("root"))
var fileGroup File_Group
require.NoError(t, fileGroup.FromFileGroup0("root"))
// Construct the compose request with customizations
cr = ComposeRequest{Customizations: &Customizations{
@ -230,8 +236,8 @@ func TestGetBlueprintFromCustomizations(t *testing.T) {
Directory{
Path: "/opt/extra",
EnsureParents: common.ToPtr(true),
User: &rootStr,
Group: &rootStr,
User: &dirUser,
Group: &dirGroup,
Mode: common.ToPtr("0755"),
},
},
@ -240,8 +246,8 @@ func TestGetBlueprintFromCustomizations(t *testing.T) {
Path: "/etc/mad.conf",
Data: common.ToPtr("Alfred E. Neuman was here.\n"),
EnsureParents: common.ToPtr(true),
User: &rootStr,
Group: &rootStr,
User: &fileUser,
Group: &fileGroup,
Mode: common.ToPtr("0644"),
},
},
@ -379,8 +385,14 @@ func TestGetBlueprintFromCompose(t *testing.T) {
assert.Equal(t, "0.0.0", bp.Version)
assert.Nil(t, bp.Customizations)
// interface{} is a terrible idea. Work around it...
var rootStr interface{} = "root"
var dirUser Directory_User
require.NoError(t, dirUser.FromDirectoryUser0("root"))
var dirGroup Directory_Group
require.NoError(t, dirGroup.FromDirectoryGroup0("root"))
var fileUser BlueprintFile_User
require.NoError(t, fileUser.FromBlueprintFileUser0("root"))
var fileGroup BlueprintFile_Group
require.NoError(t, fileGroup.FromBlueprintFileGroup0("root"))
// Construct the compose request with a blueprint
cr = ComposeRequest{Blueprint: &Blueprint{
@ -411,8 +423,8 @@ func TestGetBlueprintFromCompose(t *testing.T) {
Directory{
Path: "/opt/extra",
EnsureParents: common.ToPtr(true),
User: &rootStr,
Group: &rootStr,
User: &dirUser,
Group: &dirGroup,
Mode: common.ToPtr("0755"),
},
},
@ -420,8 +432,8 @@ func TestGetBlueprintFromCompose(t *testing.T) {
{
Path: "/etc/mad.conf",
Data: common.ToPtr("Alfred E. Neuman was here.\n"),
User: &rootStr,
Group: &rootStr,
User: &fileUser,
Group: &fileGroup,
Mode: common.ToPtr("0644"),
},
},
@ -800,13 +812,12 @@ func TestGetImageRequests_ImageTypeConversion(t *testing.T) {
for _, tt := range tests {
t.Run(string(tt.requestedImageType), func(t *testing.T) {
for _, d := range tt.requestedDistros {
uo := UploadOptions(struct{}{})
request := &ComposeRequest{
Distribution: d,
ImageRequest: &ImageRequest{
Architecture: "x86_64",
ImageType: tt.requestedImageType,
UploadOptions: &uo,
UploadOptions: &UploadOptions{},
Repositories: []Repository{
Repository{
Baseurl: common.ToPtr("http://example.org/pub/linux/repo"),
@ -828,13 +839,12 @@ func TestGetImageRequests_ImageTypeConversion(t *testing.T) {
}
func TestGetImageRequests_NoRepositories(t *testing.T) {
uo := UploadOptions(struct{}{})
request := &ComposeRequest{
Distribution: TEST_DISTRO_NAME,
ImageRequest: &ImageRequest{
Architecture: "x86_64",
ImageType: ImageTypesAws,
UploadOptions: &uo,
UploadOptions: &UploadOptions{},
Repositories: []Repository{},
},
}
@ -849,13 +859,12 @@ func TestGetImageRequests_NoRepositories(t *testing.T) {
// TestGetImageRequests_BlueprintDistro test to make sure blueprint distro overrides request distro
func TestGetImageRequests_BlueprintDistro(t *testing.T) {
uo := UploadOptions(struct{}{})
request := &ComposeRequest{
Distribution: TEST_DISTRO_NAME,
ImageRequest: &ImageRequest{
Architecture: "x86_64",
ImageType: ImageTypesAws,
UploadOptions: &uo,
UploadOptions: &UploadOptions{},
Repositories: []Repository{},
},
Blueprint: &Blueprint{

View file

@ -52,6 +52,7 @@ const (
ErrorBlueprintOrCustomNotBoth ServiceErrorCode = 39
ErrorMismatchedDistribution ServiceErrorCode = 40
ErrorMismatchedArchitecture ServiceErrorCode = 41
ErrorBadRequest ServiceErrorCode = 42
// Internal errors, these are bugs
ErrorFailedToInitializeBlueprint ServiceErrorCode = 1000
@ -136,8 +137,9 @@ func getServiceErrors() serviceErrors {
serviceError{ErrorInvalidPartitioningMode, http.StatusBadRequest, "Requested partitioning mode is invalid"},
serviceError{ErrorInvalidUploadTarget, http.StatusBadRequest, "Invalid upload target for image type"},
serviceError{ErrorBlueprintOrCustomNotBoth, http.StatusBadRequest, "Invalid request, include blueprint or customizations, not both"},
serviceError{ErrorMismatchedDistribution, http.StatusBadRequest, "Invalid request, Blueprint and Cloud API request Distribution must match."},
serviceError{ErrorMismatchedArchitecture, http.StatusBadRequest, "Invalid request, Blueprint and Cloud API request Architecture must match."},
serviceError{ErrorMismatchedDistribution, http.StatusBadRequest, "Invalid request, Blueprint and Cloud API request Distribution must match"},
serviceError{ErrorMismatchedArchitecture, http.StatusBadRequest, "Invalid request, Blueprint and Cloud API request Architecture must match"},
serviceError{ErrorBadRequest, http.StatusBadRequest, "Invalid request, see details for more information"},
serviceError{ErrorFailedToInitializeBlueprint, http.StatusInternalServerError, "Failed to initialize blueprint"},
serviceError{ErrorFailedToGenerateManifestSeed, http.StatusInternalServerError, "Failed to generate manifest seed"},
@ -221,11 +223,9 @@ func APIError(serviceError *serviceError, c echo.Context, details interface{}) *
}
apiErr := &Error{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("%s/%d", ErrorHREF, serviceError.code),
Id: fmt.Sprintf("%d", serviceError.code),
Kind: "Error",
},
Href: fmt.Sprintf("%s/%d", ErrorHREF, serviceError.code),
Id: fmt.Sprintf("%d", serviceError.code),
Kind: "Error",
Code: fmt.Sprintf("%s%d", ErrorCodePrefix, serviceError.code),
OperationId: operationID, // set operation id from context
Reason: serviceError.reason,
@ -239,12 +239,10 @@ func APIError(serviceError *serviceError, c echo.Context, details interface{}) *
// Helper to make the ErrorList as defined in openapi.v2.yml
func APIErrorList(page int, pageSize int, c echo.Context) *ErrorList {
list := &ErrorList{
List: List{
Kind: "ErrorList",
Page: page,
Size: 0,
Total: len(getServiceErrors()),
},
Kind: "ErrorList",
Page: page,
Size: 0,
Total: len(getServiceErrors()),
Items: []Error{},
}
@ -273,6 +271,8 @@ func apiErrorFromEchoError(echoError *echo.HTTPError) ServiceErrorCode {
switch echoError.Code {
case http.StatusNotFound:
return ErrorResourceNotFound
case http.StatusBadRequest:
return ErrorBadRequest
case http.StatusMethodNotAllowed:
return ErrorMethodNotAllowed
case http.StatusNotAcceptable:
@ -322,7 +322,7 @@ func HTTPErrorHandler(echoError error, c echo.Context) {
err, ok := he.Message.(detailsError)
if !ok {
// No service code was set, so Echo threw this error
// No service code was set, so Echo or the generated code threw this error
doResponse(he.Error(), apiErrorFromEchoError(he), c, he.Internal)
return
}

View file

@ -159,12 +159,9 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
}
return ctx.JSON(http.StatusCreated, &ComposeId{
ObjectReference: ObjectReference{
Href: "/api/image-builder-composer/v2/compose",
Id: id.String(),
Kind: "ComposeId",
},
Id: id.String(),
Href: "/api/image-builder-composer/v2/compose",
Id: id,
Kind: "ComposeId",
})
}
@ -229,56 +226,56 @@ func imageTypeFromApiImageType(it ImageTypes, arch distro.Arch) string {
}
func (h *apiHandlers) targetResultToUploadStatus(jobId uuid.UUID, t *target.TargetResult) (*UploadStatus, error) {
var us *UploadStatus
var uploadType UploadTypes
var uploadOptions interface{}
var fromErr error
var uploadOptions UploadStatus_Options
switch t.Name {
case target.TargetNameAWS:
uploadType = UploadTypesAws
awsOptions := t.Options.(*target.AWSTargetResultOptions)
uploadOptions = AWSEC2UploadStatus{
fromErr = uploadOptions.FromAWSEC2UploadStatus(AWSEC2UploadStatus{
Ami: awsOptions.Ami,
Region: awsOptions.Region,
}
})
case target.TargetNameAWSS3:
uploadType = UploadTypesAwsS3
awsOptions := t.Options.(*target.AWSS3TargetResultOptions)
uploadOptions = AWSS3UploadStatus{
fromErr = uploadOptions.FromAWSS3UploadStatus(AWSS3UploadStatus{
Url: awsOptions.URL,
}
})
case target.TargetNameGCP:
uploadType = UploadTypesGcp
gcpOptions := t.Options.(*target.GCPTargetResultOptions)
uploadOptions = GCPUploadStatus{
fromErr = uploadOptions.FromGCPUploadStatus(GCPUploadStatus{
ImageName: gcpOptions.ImageName,
ProjectId: gcpOptions.ProjectID,
}
})
case target.TargetNameAzureImage:
uploadType = UploadTypesAzure
gcpOptions := t.Options.(*target.AzureImageTargetResultOptions)
uploadOptions = AzureUploadStatus{
fromErr = uploadOptions.FromAzureUploadStatus(AzureUploadStatus{
ImageName: gcpOptions.ImageName,
}
})
case target.TargetNameContainer:
uploadType = UploadTypesContainer
containerOptions := t.Options.(*target.ContainerTargetResultOptions)
uploadOptions = ContainerUploadStatus{
fromErr = uploadOptions.FromContainerUploadStatus(ContainerUploadStatus{
Url: containerOptions.URL,
Digest: containerOptions.Digest,
}
})
case target.TargetNameOCIObjectStorage:
uploadType = UploadTypesOciObjectstorage
ociOptions := t.Options.(*target.OCIObjectStorageTargetResultOptions)
uploadOptions = OCIUploadStatus{
fromErr = uploadOptions.FromOCIUploadStatus(OCIUploadStatus{
Url: ociOptions.URL,
}
})
case target.TargetNamePulpOSTree:
uploadType = UploadTypesPulpOstree
pulpOSTreeOptions := t.Options.(*target.PulpOSTreeTargetResultOptions)
uploadOptions = PulpOSTreeUploadStatus{
fromErr = uploadOptions.FromPulpOSTreeUploadStatus(PulpOSTreeUploadStatus{
RepoUrl: pulpOSTreeOptions.RepoURL,
}
})
case target.TargetNameWorkerServer:
uploadType = UploadTypesLocal
workerServerOptions := t.Options.(*target.WorkerServerTargetResultOptions)
@ -286,14 +283,18 @@ func (h *apiHandlers) targetResultToUploadStatus(jobId uuid.UUID, t *target.Targ
if err != nil {
return nil, fmt.Errorf("unable to find job artifact: %w", err)
}
uploadOptions = LocalUploadStatus{
fromErr = uploadOptions.FromLocalUploadStatus(LocalUploadStatus{
ArtifactPath: absPath,
}
})
default:
return nil, fmt.Errorf("unknown upload target: %s", t.Name)
}
us = &UploadStatus{
if fromErr != nil {
return nil, fmt.Errorf("unable to form upload status: %w", fromErr)
}
us := &UploadStatus{
// TODO: determine upload status based on the target results, not job results
// Don't set the status here for now, but let it be set by the caller.
//Status: UploadStatusValue(result.UploadStatus),
@ -328,16 +329,11 @@ func (h *apiHandlers) GetComposeList(ctx echo.Context) error {
return ctx.JSON(http.StatusOK, stats)
}
func (h *apiHandlers) GetComposeStatus(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeStatusImpl)(ctx, id)
func (h *apiHandlers) GetComposeStatus(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.getComposeStatusImpl)(ctx, jobId)
}
func (h *apiHandlers) getComposeStatusImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
func (h *apiHandlers) getComposeStatusImpl(ctx echo.Context, jobId uuid.UUID) error {
response, err := h.getJobIDComposeStatus(jobId)
if err != nil {
return err
@ -388,11 +384,9 @@ func (h *apiHandlers) getJobIDComposeStatus(jobId uuid.UUID) (ComposeStatus, err
}
return ComposeStatus{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v", jobId),
Id: jobId.String(),
Kind: "ComposeStatus",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v", jobId),
Id: jobId.String(),
Kind: "ComposeStatus",
Status: composeStatusFromOSBuildJobStatus(jobInfo.JobStatus, &result),
ImageStatus: ImageStatus{
Status: imageStatusFromOSBuildJobStatus(jobInfo.JobStatus, &result),
@ -462,11 +456,9 @@ func (h *apiHandlers) getJobIDComposeStatus(jobId uuid.UUID) (ComposeStatus, err
})
}
response := ComposeStatus{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v", jobId),
Id: jobId.String(),
Kind: "ComposeStatus",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v", jobId),
Id: jobId.String(),
Kind: "ComposeStatus",
Status: composeStatusFromKojiJobStatus(finalizeInfo.JobStatus, &initResult, buildJobResults, &result),
ImageStatus: buildJobStatuses[0], // backwards compatibility
ImageStatuses: &buildJobStatuses,
@ -599,16 +591,11 @@ func composeStatusFromKojiJobStatus(js *worker.JobStatus, initResult *worker.Koj
}
// ComposeMetadata handles a /composes/{id}/metadata GET request
func (h *apiHandlers) GetComposeMetadata(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeMetadataImpl)(ctx, id)
func (h *apiHandlers) GetComposeMetadata(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.getComposeMetadataImpl)(ctx, jobId)
}
func (h *apiHandlers) getComposeMetadataImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
func (h *apiHandlers) getComposeMetadataImpl(ctx echo.Context, jobId uuid.UUID) error {
jobType, err := h.server.workers.JobType(jobId)
if err != nil {
return HTTPError(ErrorComposeNotFound)
@ -639,11 +626,9 @@ func (h *apiHandlers) getComposeMetadataImpl(ctx echo.Context, id string) error
if buildInfo.JobStatus.Finished.IsZero() {
// job still running: empty response
return ctx.JSON(200, ComposeMetadata{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/metadata", jobId),
Id: jobId.String(),
Kind: "ComposeMetadata",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/metadata", jobId),
Id: jobId.String(),
Kind: "ComposeMetadata",
Request: request,
})
}
@ -651,11 +636,9 @@ func (h *apiHandlers) getComposeMetadataImpl(ctx echo.Context, id string) error
if buildInfo.JobStatus.Canceled || !result.Success {
// job canceled or failed, empty response
return ctx.JSON(200, ComposeMetadata{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/metadata", jobId),
Id: jobId.String(),
Kind: "ComposeMetadata",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/metadata", jobId),
Id: jobId.String(),
Kind: "ComposeMetadata",
Request: request,
})
}
@ -685,11 +668,9 @@ func (h *apiHandlers) getComposeMetadataImpl(ctx echo.Context, id string) error
packages := stagesToPackageMetadata(rpmStagesMd)
resp := &ComposeMetadata{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/metadata", jobId),
Id: jobId.String(),
Kind: "ComposeMetadata",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/metadata", jobId),
Id: jobId.String(),
Kind: "ComposeMetadata",
Packages: &packages,
Request: request,
}
@ -707,16 +688,14 @@ func stagesToPackageMetadata(stages []osbuild.RPMStageMetadata) []PackageMetadat
for _, rpm := range md.Packages {
packages = append(packages,
PackageMetadata{
PackageMetadataCommon: PackageMetadataCommon{
Type: "rpm",
Name: rpm.Name,
Version: rpm.Version,
Release: rpm.Release,
Epoch: rpm.Epoch,
Arch: rpm.Arch,
Signature: osbuild.RPMPackageMetadataToSignature(rpm),
},
Sigmd5: rpm.SigMD5,
Type: "rpm",
Name: rpm.Name,
Version: rpm.Version,
Release: rpm.Release,
Epoch: rpm.Epoch,
Arch: rpm.Arch,
Signature: osbuild.RPMPackageMetadataToSignature(rpm),
Sigmd5: rpm.SigMD5,
},
)
}
@ -725,17 +704,11 @@ func stagesToPackageMetadata(stages []osbuild.RPMStageMetadata) []PackageMetadat
}
// Get logs for a compose
func (h *apiHandlers) GetComposeLogs(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeLogsImpl)(ctx, id)
func (h *apiHandlers) GetComposeLogs(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.getComposeLogsImpl)(ctx, jobId)
}
func (h *apiHandlers) getComposeLogsImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
func (h *apiHandlers) getComposeLogsImpl(ctx echo.Context, jobId uuid.UUID) error {
jobType, err := h.server.workers.JobType(jobId)
if err != nil {
return HTTPError(ErrorComposeNotFound)
@ -744,11 +717,9 @@ func (h *apiHandlers) getComposeLogsImpl(ctx echo.Context, id string) error {
var buildResultBlobs []interface{}
resp := &ComposeLogs{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/logs", jobId),
Id: jobId.String(),
Kind: "ComposeLogs",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/logs", jobId),
Id: jobId.String(),
Kind: "ComposeLogs",
}
switch jobType {
@ -831,16 +802,11 @@ func manifestJobResultsFromJobDeps(w *worker.Server, deps []uuid.UUID) (*worker.
}
// GetComposeIdManifests returns the Manifests for a given Compose (one for each image).
func (h *apiHandlers) GetComposeManifests(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeManifestsImpl)(ctx, id)
func (h *apiHandlers) GetComposeManifests(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.getComposeManifestsImpl)(ctx, jobId)
}
func (h *apiHandlers) getComposeManifestsImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
func (h *apiHandlers) getComposeManifestsImpl(ctx echo.Context, jobId uuid.UUID) error {
jobType, err := h.server.workers.JobType(jobId)
if err != nil {
return HTTPError(ErrorComposeNotFound)
@ -921,11 +887,9 @@ func (h *apiHandlers) getComposeManifestsImpl(ctx echo.Context, id string) error
}
resp := &ComposeManifests{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/manifests", jobId),
Id: jobId.String(),
Kind: "ComposeManifests",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/manifests", jobId),
Id: jobId.String(),
Kind: "ComposeManifests",
Manifests: manifestBlobs,
}
@ -942,10 +906,10 @@ func sbomsFromOSBuildJob(w *worker.Server, osbuildJobUUID uuid.UUID) ([]ImageSBO
pipelineNameToPurpose := func(pipelineName string) (ImageSBOMPipelinePurpose, error) {
if slices.Contains(osbuildJobResult.PipelineNames.Payload, pipelineName) {
return ImageSBOMPipelinePurposeImage, nil
return ImageSBOMPipelinePurpose(Image), nil
}
if slices.Contains(osbuildJobResult.PipelineNames.Build, pipelineName) {
return ImageSBOMPipelinePurposeBuildroot, nil
return ImageSBOMPipelinePurpose(Buildroot), nil
}
return "", fmt.Errorf("Pipeline %q is not listed as either a payload or build pipeline", pipelineName)
}
@ -988,7 +952,7 @@ func sbomsFromOSBuildJob(w *worker.Server, osbuildJobUUID uuid.UUID) ([]ImageSBO
var sbomType ImageSBOMSbomType
switch sbomDoc.DocType {
case sbom.StandardTypeSpdx:
sbomType = ImageSBOMSbomTypeSpdx
sbomType = ImageSBOMSbomType(Spdx)
default:
return nil, fmt.Errorf("Unknown SBOM type %q attached to depsolve job %q", sbomDoc.DocType, manifestDepUUID)
}
@ -1020,16 +984,11 @@ func sbomsFromOSBuildJob(w *worker.Server, osbuildJobUUID uuid.UUID) ([]ImageSBO
}
// GetComposeSBOMs returns the SBOM documents for a given Compose (multiple SBOMs for each image).
func (h *apiHandlers) GetComposeSBOMs(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeSBOMsImpl)(ctx, id)
func (h *apiHandlers) GetComposeSBOMs(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.getComposeSBOMsImpl)(ctx, jobId)
}
func (h *apiHandlers) getComposeSBOMsImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
func (h *apiHandlers) getComposeSBOMsImpl(ctx echo.Context, jobId uuid.UUID) error {
jobType, err := h.server.workers.JobType(jobId)
if err != nil {
return HTTPError(ErrorComposeNotFound)
@ -1084,11 +1043,9 @@ func (h *apiHandlers) getComposeSBOMsImpl(ctx echo.Context, id string) error {
}
resp := &ComposeSBOMs{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/sboms", jobId),
Id: jobId.String(),
Kind: "ComposeSBOMs",
},
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/sboms", jobId),
Id: jobId.String(),
Kind: "ComposeSBOMs",
Items: items,
}
@ -1172,21 +1129,16 @@ func genRepoConfig(repo Repository) (*rpmmd.RepoConfig, error) {
return repoConfig, nil
}
func (h *apiHandlers) PostCloneCompose(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.postCloneComposeImpl)(ctx, id)
func (h *apiHandlers) PostCloneCompose(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.postCloneComposeImpl)(ctx, jobId)
}
func (h *apiHandlers) postCloneComposeImpl(ctx echo.Context, id string) error {
func (h *apiHandlers) postCloneComposeImpl(ctx echo.Context, jobId uuid.UUID) error {
channel, err := h.server.getTenantChannel(ctx)
if err != nil {
return HTTPErrorWithInternal(ErrorTenantNotFound, err)
}
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
jobType, err := h.server.workers.JobType(jobId)
if err != nil {
return HTTPError(ErrorComposeNotFound)
@ -1233,9 +1185,12 @@ func (h *apiHandlers) postCloneComposeImpl(ctx echo.Context, id string) error {
finalJob := jobId
// look at the upload status of the osbuild dependency to decide what to do
if us.Type == UploadTypesAws {
options := us.Options.(AWSEC2UploadStatus)
options, err := us.Options.AsAWSEC2UploadStatus()
if err != nil {
return err
}
var img AWSEC2CloneCompose
err := ctx.Bind(&img)
err = ctx.Bind(&img)
if err != nil {
return err
}
@ -1310,31 +1265,25 @@ func (h *apiHandlers) postCloneComposeImpl(ctx echo.Context, id string) error {
}
return ctx.JSON(http.StatusCreated, CloneComposeResponse{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/clone", jobId),
Id: finalJob.String(),
Kind: "CloneComposeId",
},
Id: finalJob.String(),
Href: fmt.Sprintf("/api/image-builder-composer/v2/composes/%v/clone", jobId),
Id: finalJob,
Kind: "CloneComposeId",
})
}
func (h *apiHandlers) GetCloneStatus(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getCloneStatus)(ctx, id)
func (h *apiHandlers) GetCloneStatus(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.getCloneStatus)(ctx, jobId)
}
func (h *apiHandlers) getCloneStatus(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
func (h *apiHandlers) getCloneStatus(ctx echo.Context, jobId uuid.UUID) error {
jobType, err := h.server.workers.JobType(jobId)
if err != nil {
return HTTPError(ErrorComposeNotFound)
}
var us UploadStatus
var status UploadStatusValue
var uploadType UploadTypes
var options CloneStatus_Options
switch jobType {
case worker.JobTypeAWSEC2Copy:
var result worker.AWSEC2CopyJobResult
@ -1343,13 +1292,14 @@ func (h *apiHandlers) getCloneStatus(ctx echo.Context, id string) error {
return HTTPError(ErrorGettingAWSEC2JobStatus)
}
us = UploadStatus{
Status: uploadStatusFromJobStatus(info.JobStatus, result.JobError),
Type: UploadTypesAws,
Options: AWSEC2UploadStatus{
Ami: result.Ami,
Region: result.Region,
},
status = uploadStatusFromJobStatus(info.JobStatus, result.JobError)
uploadType = UploadTypesAws
err = options.FromAWSEC2UploadStatus(AWSEC2UploadStatus{
Ami: result.Ami,
Region: result.Region,
})
if err != nil {
return HTTPErrorWithInternal(ErrorGettingAWSEC2JobStatus, err)
}
case worker.JobTypeAWSEC2Share:
var result worker.AWSEC2ShareJobResult
@ -1358,42 +1308,43 @@ func (h *apiHandlers) getCloneStatus(ctx echo.Context, id string) error {
return HTTPError(ErrorGettingAWSEC2JobStatus)
}
us = UploadStatus{
Status: uploadStatusFromJobStatus(info.JobStatus, result.JobError),
Type: UploadTypesAws,
Options: AWSEC2UploadStatus{
Ami: result.Ami,
Region: result.Region,
},
status = uploadStatusFromJobStatus(info.JobStatus, result.JobError)
uploadType = UploadTypesAws
err = options.FromAWSEC2UploadStatus(AWSEC2UploadStatus{
Ami: result.Ami,
Region: result.Region,
})
if err != nil {
return HTTPErrorWithInternal(ErrorGettingAWSEC2JobStatus, err)
}
default:
return HTTPError(ErrorInvalidJobType)
}
return ctx.JSON(http.StatusOK, CloneStatus{
ObjectReference: ObjectReference{
Href: fmt.Sprintf("/api/image-builder-composer/v2/clones/%v", jobId),
Id: jobId.String(),
Kind: "CloneComposeStatus",
},
UploadStatus: us,
Href: fmt.Sprintf("/api/image-builder-composer/v2/clones/%v", jobId),
Id: jobId.String(),
Kind: "CloneComposeStatus",
Status: status,
Type: uploadType,
Options: options,
})
}
// TODO: determine upload status based on the target results, not job results
func uploadStatusFromJobStatus(js *worker.JobStatus, je *clienterrors.Error) UploadStatusValue {
if je != nil || js.Canceled {
return UploadStatusValueFailure
return UploadStatusValue(Failure)
}
if js.Started.IsZero() {
return UploadStatusValuePending
return UploadStatusValue(Pending)
}
if js.Finished.IsZero() {
return UploadStatusValueRunning
return UploadStatusValue(Running)
}
return UploadStatusValueSuccess
return UploadStatusValue(Success)
}
// PostDepsolveBlueprint depsolves the packages in a blueprint and returns
@ -1541,16 +1492,11 @@ func (h *apiHandlers) GetDistributionList(ctx echo.Context) error {
}
// GetComposeDownload downloads a compose artifact
func (h *apiHandlers) GetComposeDownload(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeDownloadImpl)(ctx, id)
func (h *apiHandlers) GetComposeDownload(ctx echo.Context, jobId uuid.UUID) error {
return h.server.EnsureJobChannel(h.getComposeDownloadImpl)(ctx, jobId)
}
func (h *apiHandlers) getComposeDownloadImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
func (h *apiHandlers) getComposeDownloadImpl(ctx echo.Context, jobId uuid.UUID) error {
jobType, err := h.server.workers.JobType(jobId)
if err != nil {
return HTTPError(ErrorComposeNotFound)

View file

@ -187,7 +187,7 @@ func newAzureTarget(options UploadOptions, imageType distro.ImageType) (*target.
hypvgen := target.HyperVGenV1
if azureUploadOptions.HyperVGeneration != nil &&
*azureUploadOptions.HyperVGeneration == AzureUploadOptionsHyperVGenerationV2 {
*azureUploadOptions.HyperVGeneration == AzureUploadOptionsHyperVGeneration(V2) {
hypvgen = target.HyperVGenV2
}

View file

@ -25,16 +25,11 @@ func (s *Server) getTenantChannel(ctx echo.Context) (string, error) {
return "", nil
}
type ComposeHandlerFunc func(ctx echo.Context, id string) error
type ComposeHandlerFunc func(ctx echo.Context, jobId uuid.UUID) error
// Ensures that the job's channel matches the JWT cannel set in the echo.Context
func (s *Server) EnsureJobChannel(next ComposeHandlerFunc) ComposeHandlerFunc {
return func(c echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
}
return func(c echo.Context, jobId uuid.UUID) error {
ctxChannel, err := s.getTenantChannel(c)
if err != nil {
return err
@ -50,7 +45,7 @@ func (s *Server) EnsureJobChannel(next ComposeHandlerFunc) ComposeHandlerFunc {
return HTTPError(ErrorComposeNotFound)
}
return next(c, id)
return next(c, jobId)
}
}

View file

@ -314,7 +314,7 @@ type BlueprintFile struct {
type BlueprintFileGroup0 = string
// BlueprintFileGroup1 defines model for .
type BlueprintFileGroup1 = int
type BlueprintFileGroup1 = int64
// BlueprintFile_Group Group of the file as a gid or a group name
type BlueprintFile_Group struct {
@ -325,7 +325,7 @@ type BlueprintFile_Group struct {
type BlueprintFileUser0 = string
// BlueprintFileUser1 defines model for .
type BlueprintFileUser1 = int
type BlueprintFileUser1 = int64
// BlueprintFile_User Owner of the file as a uid or a user name
type BlueprintFile_User struct {
@ -688,7 +688,7 @@ type Directory struct {
type DirectoryGroup0 = string
// DirectoryGroup1 defines model for .
type DirectoryGroup1 = int
type DirectoryGroup1 = int64
// Directory_Group Group of the directory as a group name or a gid
type Directory_Group struct {
@ -699,18 +699,15 @@ type Directory_Group struct {
type DirectoryUser0 = string
// DirectoryUser1 defines model for .
type DirectoryUser1 = int
type DirectoryUser1 = int64
// Directory_User Owner of the directory as a user name or a uid
type Directory_User struct {
union json.RawMessage
}
// DistributionList defines model for DistributionList.
type DistributionList struct {
// Map Distribution name
Map *map[string]interface{} `json:"map,omitempty"`
}
// DistributionList Map of distributions to their architecture.
type DistributionList map[string]map[string][]BlueprintRepository
// Error defines model for Error.
type Error struct {
@ -772,7 +769,7 @@ type File struct {
type FileGroup0 = string
// FileGroup1 defines model for .
type FileGroup1 = int
type FileGroup1 = int64
// File_Group Group of the file as a gid or a group name
type File_Group struct {
@ -783,7 +780,7 @@ type File_Group struct {
type FileUser0 = string
// FileUser1 defines model for .
type FileUser1 = int
type FileUser1 = int64
// File_User Owner of the file as a uid or a user name
type File_User struct {
@ -2786,207 +2783,207 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
"N87X7/8/AAD//86RvuTV6AAA",
"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",
"1IWqTKCeZt04X7///wAAAP//wpER3BXpAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file

View file

@ -767,23 +767,18 @@ components:
$ref: '#/components/schemas/ComposeStatus'
DistributionList:
properties:
map:
type: object
description: Distribution name
additionalProperties:
map:
type: object
description: Architecture name
additionalProperties:
map:
type: object
description: Image type name
additionalProperties:
type: array
description: Repository used for this distro:arch:image-type
items:
$ref: '#/components/schemas/BlueprintRepository'
type: object
description: |
Map of distributions to their architecture.
additionalProperties:
type: object
description: |
Map of architectures to their repositories.
additionalProperties:
type: array
description: Repository used for this distro:arch:image-type
items:
$ref: '#/components/schemas/BlueprintRepository'
ComposeStatus:
allOf:
@ -2056,12 +2051,14 @@ components:
oneOf:
- type: string
- type: integer
x-go-type: int64
description: Owner of the directory as a user name or a uid
example: 'root'
group:
oneOf:
- type: string
- type: integer
x-go-type: int64
description: Group of the directory as a group name or a gid
example: 'root'
ensure_parents:
@ -2087,12 +2084,14 @@ components:
oneOf:
- type: string
- type: integer
x-go-type: int64
description: Owner of the file as a uid or a user name
example: 'root'
group:
oneOf:
- type: string
- type: integer
x-go-type: int64
description: Group of the file as a gid or a group name
example: 'root'
data:
@ -2122,12 +2121,14 @@ components:
oneOf:
- type: string
- type: integer
x-go-type: int64
description: Owner of the file as a uid or a user name
example: 'root'
group:
oneOf:
- type: string
- type: integer
x-go-type: int64
description: Group of the file as a gid or a group name
example: 'root'
data:

View file

@ -279,28 +279,24 @@ func TestStagesToPackageMetadata(t *testing.T) {
},
pkgs: []PackageMetadata{
{
PackageMetadataCommon: PackageMetadataCommon{
Type: "rpm",
Name: "vim-minimal",
Version: "8.0.1763",
Release: "15.el8",
Epoch: common.ToPtr("2"),
Arch: "x86_64",
Signature: common.ToPtr("v"),
},
Sigmd5: "v",
Type: "rpm",
Name: "vim-minimal",
Version: "8.0.1763",
Release: "15.el8",
Epoch: common.ToPtr("2"),
Arch: "x86_64",
Signature: common.ToPtr("v"),
Sigmd5: "v",
},
{
PackageMetadataCommon: PackageMetadataCommon{
Type: "rpm",
Name: "unique",
Version: "1.90",
Release: "10",
Epoch: nil,
Arch: "aarch64",
Signature: common.ToPtr("v"),
},
Sigmd5: "v",
Type: "rpm",
Name: "unique",
Version: "1.90",
Release: "10",
Epoch: nil,
Arch: "aarch64",
Signature: common.ToPtr("v"),
Sigmd5: "v",
},
},
},
@ -337,28 +333,24 @@ func TestStagesToPackageMetadata(t *testing.T) {
},
pkgs: []PackageMetadata{
{
PackageMetadataCommon: PackageMetadataCommon{
Type: "rpm",
Name: "vim-minimal",
Version: "8.0.1763",
Release: "15.el8",
Epoch: common.ToPtr("2"),
Arch: "x86_64",
Signature: common.ToPtr("v"),
},
Sigmd5: "v",
Type: "rpm",
Name: "vim-minimal",
Version: "8.0.1763",
Release: "15.el8",
Epoch: common.ToPtr("2"),
Arch: "x86_64",
Signature: common.ToPtr("v"),
Sigmd5: "v",
},
{
PackageMetadataCommon: PackageMetadataCommon{
Type: "rpm",
Name: "unique",
Version: "1.90",
Release: "10",
Epoch: nil,
Arch: "aarch64",
Signature: common.ToPtr("v"),
},
Sigmd5: "v",
Type: "rpm",
Name: "unique",
Version: "1.90",
Release: "10",
Epoch: nil,
Arch: "aarch64",
Signature: common.ToPtr("v"),
Sigmd5: "v",
},
},
},

View file

@ -414,8 +414,6 @@ func TestKojiCompose(t *testing.T) {
var composeReply v2.ComposeId
err := json.Unmarshal(composeRawReply, &composeReply)
require.NoError(t, err)
composeId, err := uuid.Parse(composeReply.Id)
require.NoError(t, err)
// handle koji-init
_, token, jobType, rawJob, _, err := workerServer.RequestJob(context.Background(), test_distro.TestArch3Name, []string{worker.JobTypeKojiInit}, []string{""}, uuid.Nil)
@ -438,7 +436,7 @@ func TestKojiCompose(t *testing.T) {
// Finishing of the goroutine handling the manifest job is not deterministic and as a result, we may get
// the second osbuild job first.
// The build jobs ID is determined from the dependencies of the koji-finalize job dependencies.
finalizeInfo, err := workerServer.KojiFinalizeJobInfo(composeId, &worker.KojiFinalizeJobResult{})
finalizeInfo, err := workerServer.KojiFinalizeJobInfo(composeReply.Id, &worker.KojiFinalizeJobResult{})
require.NoError(t, err)
buildJobIDs := finalizeInfo.Deps[1:]
require.Len(t, buildJobIDs, 2)
@ -551,7 +549,7 @@ func TestKojiCompose(t *testing.T) {
}
]
]
}`, finalizeID, finalizeID, sbomDoc, v2.ImageSBOMSbomTypeSpdx), "details")
}`, finalizeID, finalizeID, sbomDoc, v2.ImageSBOMSbomType(v2.Spdx)), "details")
})
}
}

View file

@ -95,8 +95,7 @@ func scheduleRequest(t *testing.T, handler http.Handler, orgID, request string)
// Parse ID
var id v2.ComposeId
require.NoError(t, json.Unmarshal(result.Body, &id))
return uuid.MustParse(id.Id)
return id.Id
}
func getAllJobsOfCompose(t *testing.T, q jobqueue.JobQueue, finalJob uuid.UUID) []uuid.UUID {

View file

@ -895,7 +895,7 @@ func TestComposeStatusSuccess(t *testing.T) {
}
]
]
}`, jobId, jobId, sbomDoc, v2.ImageSBOMSbomTypeSpdx), "details")
}`, jobId, jobId, sbomDoc, v2.ImageSBOMSbomType(v2.Spdx)), "details")
}
func TestComposeStatusFailure(t *testing.T) {
@ -959,12 +959,12 @@ func TestComposeStatusInvalidUUID(t *testing.T) {
test.TestRoute(t, srv.Handler("/api/image-builder-composer/v2"), false, "GET", "/api/image-builder-composer/v2/composes/abcdef", ``, http.StatusBadRequest, `
{
"code": "IMAGE-BUILDER-COMPOSER-14",
"details": "",
"href": "/api/image-builder-composer/v2/errors/14",
"id": "14",
"code": "IMAGE-BUILDER-COMPOSER-42",
"details": "code=400, message=Invalid format for parameter id: error unmarshaling 'abcdef' text as *uuid.UUID: invalid UUID length: 6",
"href": "/api/image-builder-composer/v2/errors/42",
"id": "42",
"kind": "Error",
"reason": "Invalid format for compose id"
"reason": "Invalid request, see details for more information"
}
`, "operation_id")
}
@ -1748,7 +1748,7 @@ func TestDepsolveDistroErrors(t *testing.T) {
"id": "40",
"kind": "Error",
"code": "IMAGE-BUILDER-COMPOSER-40",
"reason": "Invalid request, Blueprint and Cloud API request Distribution must match."
"reason": "Invalid request, Blueprint and Cloud API request Distribution must match"
}`, "operation_id", "details")
// Bad distro in request, none in blueprint
@ -1905,13 +1905,11 @@ func TestComposesRoute(t *testing.T) {
var composeReply v2.ComposeId
err := json.Unmarshal(reply, &composeReply)
require.NoError(t, err)
jobID, err := uuid.Parse(composeReply.Id)
require.NoError(t, err)
// List root composes
test.TestRoute(t, srv.Handler("/api/image-builder-composer/v2"), false, "GET", "/api/image-builder-composer/v2/composes/", ``,
http.StatusOK, fmt.Sprintf(`[{"href":"/api/image-builder-composer/v2/composes/%[1]s", "id":"%[1]s", "image_status":{"status":"pending"}, "kind":"ComposeStatus", "status":"pending"}]`,
jobID.String()))
composeReply.Id.String()))
}
func TestDownload(t *testing.T) {
@ -2082,12 +2080,16 @@ func TestComposeRequestMetadata(t *testing.T) {
"image_requests":[{
"architecture": "%s",
"image_type": "aws",
"size": 0,
"repositories": [{
"baseurl": "somerepo.org",
"rhsm": false
"rhsm": false,
"check_repo_gpg": false,
"module_hotfixes": false
}],
"upload_options": {
"region": "eu-central-1"
"region": "eu-central-1",
"public": false
}
}]
}`, test_distro.TestDistro1Name, test_distro.TestArch3Name)