Cloud API: support cloud upload for Koji composes
Add support to handle upload options in image requests for Koji composes. The image is always uploaded to Koji, but now it can be uploaded to the cloud environment in addition to Koji as part of the build. The image name used for Koji image can't be used as is for uploading to the cloud, because each cloud provider has its own requirements for the valid characters. For now, let the Cloud API implementation generate a random image name. The name is always returned in the compose status's upload status, so it should be possible to attach it to the Koji build to allow users to find the image.
This commit is contained in:
parent
77a1672b79
commit
85f9f07a1f
2 changed files with 79 additions and 46 deletions
|
|
@ -299,10 +299,6 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
|
|||
return HTTPError(ErrorJSONUnMarshallingError)
|
||||
}
|
||||
} else {
|
||||
// TODO: support uploads also for koji
|
||||
if request.Koji != nil {
|
||||
return HTTPError(ErrorJSONUnMarshallingError)
|
||||
}
|
||||
/* oneOf is not supported by the openapi generator so marshal and unmarshal the uploadrequest based on the type */
|
||||
switch ir.ImageType {
|
||||
case ImageTypesAws:
|
||||
|
|
@ -516,6 +512,53 @@ func imageTypeFromApiImageType(it ImageTypes, arch distro.Arch) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func targetResultToUploadStatus(t *target.TargetResult) (*UploadStatus, error) {
|
||||
var us *UploadStatus
|
||||
var uploadType UploadTypes
|
||||
var uploadOptions interface{}
|
||||
|
||||
switch t.Name {
|
||||
case target.TargetNameAWS:
|
||||
uploadType = UploadTypesAws
|
||||
awsOptions := t.Options.(*target.AWSTargetResultOptions)
|
||||
uploadOptions = AWSEC2UploadStatus{
|
||||
Ami: awsOptions.Ami,
|
||||
Region: awsOptions.Region,
|
||||
}
|
||||
case target.TargetNameAWSS3:
|
||||
uploadType = UploadTypesAwsS3
|
||||
awsOptions := t.Options.(*target.AWSS3TargetResultOptions)
|
||||
uploadOptions = AWSS3UploadStatus{
|
||||
Url: awsOptions.URL,
|
||||
}
|
||||
case target.TargetNameGCP:
|
||||
uploadType = UploadTypesGcp
|
||||
gcpOptions := t.Options.(*target.GCPTargetResultOptions)
|
||||
uploadOptions = GCPUploadStatus{
|
||||
ImageName: gcpOptions.ImageName,
|
||||
ProjectId: gcpOptions.ProjectID,
|
||||
}
|
||||
case target.TargetNameAzureImage:
|
||||
uploadType = UploadTypesAzure
|
||||
gcpOptions := t.Options.(*target.AzureImageTargetResultOptions)
|
||||
uploadOptions = AzureUploadStatus{
|
||||
ImageName: gcpOptions.ImageName,
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown upload target: %s", t.Name)
|
||||
}
|
||||
|
||||
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),
|
||||
Type: uploadType,
|
||||
Options: uploadOptions,
|
||||
}
|
||||
|
||||
return us, nil
|
||||
}
|
||||
|
||||
func (h *apiHandlers) GetComposeStatus(ctx echo.Context, id string) error {
|
||||
return h.server.EnsureJobChannel(h.getComposeStatusImpl)(ctx, id)
|
||||
}
|
||||
|
|
@ -549,47 +592,13 @@ func (h *apiHandlers) getComposeStatusImpl(ctx echo.Context, id string) error {
|
|||
if len(result.TargetResults) != 1 {
|
||||
return HTTPError(ErrorSeveralUploadTargets)
|
||||
}
|
||||
tr := *result.TargetResults[0]
|
||||
|
||||
var uploadType UploadTypes
|
||||
var uploadOptions interface{}
|
||||
|
||||
switch tr.Name {
|
||||
case target.TargetNameAWS:
|
||||
uploadType = UploadTypesAws
|
||||
awsOptions := tr.Options.(*target.AWSTargetResultOptions)
|
||||
uploadOptions = AWSEC2UploadStatus{
|
||||
Ami: awsOptions.Ami,
|
||||
Region: awsOptions.Region,
|
||||
}
|
||||
case target.TargetNameAWSS3:
|
||||
uploadType = UploadTypesAwsS3
|
||||
awsOptions := tr.Options.(*target.AWSS3TargetResultOptions)
|
||||
uploadOptions = AWSS3UploadStatus{
|
||||
Url: awsOptions.URL,
|
||||
}
|
||||
case target.TargetNameGCP:
|
||||
uploadType = UploadTypesGcp
|
||||
gcpOptions := tr.Options.(*target.GCPTargetResultOptions)
|
||||
uploadOptions = GCPUploadStatus{
|
||||
ImageName: gcpOptions.ImageName,
|
||||
ProjectId: gcpOptions.ProjectID,
|
||||
}
|
||||
case target.TargetNameAzureImage:
|
||||
uploadType = UploadTypesAzure
|
||||
gcpOptions := tr.Options.(*target.AzureImageTargetResultOptions)
|
||||
uploadOptions = AzureUploadStatus{
|
||||
ImageName: gcpOptions.ImageName,
|
||||
}
|
||||
default:
|
||||
tr := result.TargetResults[0]
|
||||
us, err = targetResultToUploadStatus(tr)
|
||||
if err != nil {
|
||||
return HTTPError(ErrorUnknownUploadTarget)
|
||||
}
|
||||
|
||||
us = &UploadStatus{
|
||||
Status: UploadStatusValue(result.UploadStatus),
|
||||
Type: uploadType,
|
||||
Options: uploadOptions,
|
||||
}
|
||||
// TODO: determine upload status based on the target results, not job results
|
||||
us.Status = UploadStatusValue(result.UploadStatus)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, ComposeStatus{
|
||||
|
|
@ -631,10 +640,28 @@ func (h *apiHandlers) getComposeStatusImpl(ctx echo.Context, id string) error {
|
|||
if err != nil {
|
||||
return HTTPError(ErrorGettingBuildDependencyStatus)
|
||||
}
|
||||
|
||||
var us *UploadStatus
|
||||
// only single upload target in addition to Koji is allowed
|
||||
if len(buildJobResult.TargetResults) > 2 {
|
||||
return HTTPError(ErrorSeveralUploadTargets)
|
||||
}
|
||||
for _, tr := range buildJobResult.TargetResults {
|
||||
if tr.Name != target.TargetNameKoji {
|
||||
us, err = targetResultToUploadStatus(tr)
|
||||
if err != nil {
|
||||
return HTTPError(ErrorUnknownUploadTarget)
|
||||
}
|
||||
// TODO: determine upload status based on the target results, not job results
|
||||
us.Status = UploadStatusValue(buildJobResult.UploadStatus)
|
||||
}
|
||||
}
|
||||
|
||||
buildJobResults = append(buildJobResults, buildJobResult)
|
||||
buildJobStatuses = append(buildJobStatuses, ImageStatus{
|
||||
Status: imageStatusFromKojiJobStatus(buildJobStatus, &initResult, &buildJobResult),
|
||||
Error: composeStatusErrorFromJobError(buildJobError),
|
||||
Status: imageStatusFromKojiJobStatus(buildJobStatus, &initResult, &buildJobResult),
|
||||
Error: composeStatusErrorFromJobError(buildJobError),
|
||||
UploadStatus: us,
|
||||
})
|
||||
}
|
||||
response := ComposeStatus{
|
||||
|
|
|
|||
|
|
@ -185,12 +185,18 @@ func (s *Server) enqueueKojiCompose(taskID uint64, server, name, version, releas
|
|||
kojiTarget.OsbuildArtifact.ExportName = ir.imageType.Exports()[0]
|
||||
kojiTarget.ImageName = kojiFilename
|
||||
|
||||
targets := []*target.Target{kojiTarget}
|
||||
// add any cloud upload target if defined
|
||||
if ir.target != nil {
|
||||
targets = append(targets, ir.target)
|
||||
}
|
||||
|
||||
buildID, err := s.workers.EnqueueOSBuildAsDependency(ir.arch.Name(), &worker.OSBuildJob{
|
||||
PipelineNames: &worker.PipelineNames{
|
||||
Build: ir.imageType.BuildPipelines(),
|
||||
Payload: ir.imageType.PayloadPipelines(),
|
||||
},
|
||||
Targets: []*target.Target{kojiTarget},
|
||||
Targets: targets,
|
||||
ManifestDynArgsIdx: common.IntToPtr(1),
|
||||
}, []uuid.UUID{initID, manifestJobID}, channel)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue