From b011b9845a1fd57728d744b83af7a8e3bfe0c749 Mon Sep 17 00:00:00 2001 From: Achilleas Koutsou Date: Fri, 13 Oct 2023 18:46:26 +0200 Subject: [PATCH] cloudapi: split GetTarget() into functions Separate the handling of each individual target type into its own function called by GetTarget()'s case switch. This makes the function more readable and the target object creation reusable. Added an empty line after each creation of irTarget to make it easier to visually distinguish the cases that fall through. --- internal/cloudapi/v2/imagerequest.go | 359 +++++++++++++++------------ 1 file changed, 194 insertions(+), 165 deletions(-) diff --git a/internal/cloudapi/v2/imagerequest.go b/internal/cloudapi/v2/imagerequest.go index 6aaae11d3..cc6c1ca7d 100644 --- a/internal/cloudapi/v2/imagerequest.go +++ b/internal/cloudapi/v2/imagerequest.go @@ -36,9 +36,193 @@ func (ir *ImageRequest) GetImageOptions(imageType distro.ImageType, bp blueprint return distro.ImageOptions{Size: size, PartitioningMode: disk.AutoLVMPartitioningMode} } +func newAWSTarget(ir *ImageRequest, imageType distro.ImageType) (*target.Target, error) { + var awsUploadOptions AWSEC2UploadOptions + jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONMarshallingError) + } + err = json.Unmarshal(jsonUploadOptions, &awsUploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONUnMarshallingError) + } + + // For service maintenance, images are discovered by the "Name:composer-api-*" + // tag filter. Currently all image names in the service are generated, so they're + // guaranteed to be unique as well. If users are ever allowed to name their images, + // an extra tag should be added. + key := fmt.Sprintf("composer-api-%s", uuid.New().String()) + + var amiBootMode *string + switch imageType.BootMode() { + case distro.BOOT_HYBRID: + amiBootMode = common.ToPtr(ec2.BootModeValuesUefiPreferred) + case distro.BOOT_UEFI: + amiBootMode = common.ToPtr(ec2.BootModeValuesUefi) + case distro.BOOT_LEGACY: + amiBootMode = common.ToPtr(ec2.BootModeValuesLegacyBios) + } + + t := target.NewAWSTarget(&target.AWSTargetOptions{ + Region: awsUploadOptions.Region, + Key: key, + ShareWithAccounts: awsUploadOptions.ShareWithAccounts, + BootMode: amiBootMode, + }) + if awsUploadOptions.SnapshotName != nil { + t.ImageName = *awsUploadOptions.SnapshotName + } else { + t.ImageName = key + } + t.OsbuildArtifact.ExportFilename = imageType.Filename() + return t, nil +} + +func newAWSS3Target(ir *ImageRequest, imageType distro.ImageType) (*target.Target, error) { + var awsS3UploadOptions AWSS3UploadOptions + jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONMarshallingError) + } + err = json.Unmarshal(jsonUploadOptions, &awsS3UploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONUnMarshallingError) + } + + public := false + if awsS3UploadOptions.Public != nil && *awsS3UploadOptions.Public { + public = true + } + + key := fmt.Sprintf("composer-api-%s", uuid.New().String()) + t := target.NewAWSS3Target(&target.AWSS3TargetOptions{ + Region: awsS3UploadOptions.Region, + Key: key, + Public: public, + }) + t.ImageName = key + t.OsbuildArtifact.ExportFilename = imageType.Filename() + return t, nil +} + +func newContainerTarget(ir *ImageRequest, request *ComposeRequest, imageType distro.ImageType) (*target.Target, error) { + var containerUploadOptions ContainerUploadOptions + jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONMarshallingError) + } + err = json.Unmarshal(jsonUploadOptions, &containerUploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONUnMarshallingError) + } + + var name = request.Distribution + var tag = uuid.New().String() + if containerUploadOptions.Name != nil { + name = *containerUploadOptions.Name + if containerUploadOptions.Tag != nil { + tag = *containerUploadOptions.Tag + } + } + + t := target.NewContainerTarget(&target.ContainerTargetOptions{}) + t.ImageName = fmt.Sprintf("%s:%s", name, tag) + t.OsbuildArtifact.ExportFilename = imageType.Filename() + + return t, nil +} + +func newGCPTarget(ir *ImageRequest, imageType distro.ImageType) (*target.Target, error) { + var gcpUploadOptions GCPUploadOptions + jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONMarshallingError) + } + err = json.Unmarshal(jsonUploadOptions, &gcpUploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONUnMarshallingError) + } + + var share []string + if gcpUploadOptions.ShareWithAccounts != nil { + share = *gcpUploadOptions.ShareWithAccounts + } + + imageName := fmt.Sprintf("composer-api-%s", uuid.New().String()) + var bucket string + if gcpUploadOptions.Bucket != nil { + bucket = *gcpUploadOptions.Bucket + } + t := target.NewGCPTarget(&target.GCPTargetOptions{ + Region: gcpUploadOptions.Region, + Os: imageType.Arch().Distro().Name(), // not exposed in cloudapi + Bucket: bucket, + // the uploaded object must have a valid extension + Object: fmt.Sprintf("%s.tar.gz", imageName), + ShareWithAccounts: share, + }) + // Import will fail if an image with this name already exists + if gcpUploadOptions.ImageName != nil { + t.ImageName = *gcpUploadOptions.ImageName + } else { + t.ImageName = imageName + } + t.OsbuildArtifact.ExportFilename = imageType.Filename() + return t, nil +} + +func newAzureTarget(ir *ImageRequest, imageType distro.ImageType) (*target.Target, error) { + var azureUploadOptions AzureUploadOptions + jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONMarshallingError) + } + err = json.Unmarshal(jsonUploadOptions, &azureUploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONUnMarshallingError) + } + rgLocation := "" + if azureUploadOptions.Location != nil { + rgLocation = *azureUploadOptions.Location + } + t := target.NewAzureImageTarget(&target.AzureImageTargetOptions{ + TenantID: azureUploadOptions.TenantId, + Location: rgLocation, + SubscriptionID: azureUploadOptions.SubscriptionId, + ResourceGroup: azureUploadOptions.ResourceGroup, + }) + + if azureUploadOptions.ImageName != nil { + t.ImageName = *azureUploadOptions.ImageName + } else { + // if ImageName wasn't given, generate a random one + t.ImageName = fmt.Sprintf("composer-api-%s", uuid.New().String()) + } + t.OsbuildArtifact.ExportFilename = imageType.Filename() + return t, nil +} + +func newOCITarget(ir *ImageRequest, imageType distro.ImageType) (*target.Target, error) { + var ociUploadOptions OCIUploadOptions + jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONMarshallingError) + } + err = json.Unmarshal(jsonUploadOptions, &ociUploadOptions) + if err != nil { + return nil, HTTPError(ErrorJSONUnMarshallingError) + } + + key := fmt.Sprintf("composer-api-%s", uuid.New().String()) + t := target.NewOCIObjectStorageTarget(&target.OCIObjectStorageTargetOptions{}) + t.ImageName = key + t.OsbuildArtifact.ExportFilename = imageType.Filename() + return t, nil +} + // GetImageTarget returns the target for the selected image type func (ir *ImageRequest) GetTarget(request *ComposeRequest, imageType distro.ImageType) (irTarget *target.Target, err error) { - /* oneOf is not supported by the openapi generator so marshal and unmarshal the uploadrequest based on the type */ + // oneOf is not supported by the openapi generator so marshal and unmarshal the uploadrequest based on the type switch ir.ImageType { case ImageTypesAws: fallthrough @@ -47,46 +231,8 @@ func (ir *ImageRequest) GetTarget(request *ComposeRequest, imageType distro.Imag case ImageTypesAwsHaRhui: fallthrough case ImageTypesAwsSapRhui: - var awsUploadOptions AWSEC2UploadOptions - jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONMarshallingError) - } - err = json.Unmarshal(jsonUploadOptions, &awsUploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONUnMarshallingError) - } + irTarget, err = newAWSTarget(ir, imageType) - // For service maintenance, images are discovered by the "Name:composer-api-*" - // tag filter. Currently all image names in the service are generated, so they're - // guaranteed to be unique as well. If users are ever allowed to name their images, - // an extra tag should be added. - key := fmt.Sprintf("composer-api-%s", uuid.New().String()) - - var amiBootMode *string - switch imageType.BootMode() { - case distro.BOOT_HYBRID: - amiBootMode = common.ToPtr(ec2.BootModeValuesUefiPreferred) - case distro.BOOT_UEFI: - amiBootMode = common.ToPtr(ec2.BootModeValuesUefi) - case distro.BOOT_LEGACY: - amiBootMode = common.ToPtr(ec2.BootModeValuesLegacyBios) - } - - t := target.NewAWSTarget(&target.AWSTargetOptions{ - Region: awsUploadOptions.Region, - Key: key, - ShareWithAccounts: awsUploadOptions.ShareWithAccounts, - BootMode: amiBootMode, - }) - if awsUploadOptions.SnapshotName != nil { - t.ImageName = *awsUploadOptions.SnapshotName - } else { - t.ImageName = key - } - t.OsbuildArtifact.ExportFilename = imageType.Filename() - - irTarget = t case ImageTypesGuestImage: fallthrough case ImageTypesVsphere: @@ -108,98 +254,18 @@ func (ir *ImageRequest) GetTarget(request *ComposeRequest, imageType distro.Imag case ImageTypesIotCommit: fallthrough case ImageTypesIotRawImage: - var awsS3UploadOptions AWSS3UploadOptions - jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONMarshallingError) - } - err = json.Unmarshal(jsonUploadOptions, &awsS3UploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONUnMarshallingError) - } + irTarget, err = newAWSS3Target(ir, imageType) - public := false - if awsS3UploadOptions.Public != nil && *awsS3UploadOptions.Public { - public = true - } - - key := fmt.Sprintf("composer-api-%s", uuid.New().String()) - t := target.NewAWSS3Target(&target.AWSS3TargetOptions{ - Region: awsS3UploadOptions.Region, - Key: key, - Public: public, - }) - t.ImageName = key - t.OsbuildArtifact.ExportFilename = imageType.Filename() - - irTarget = t case ImageTypesEdgeContainer: fallthrough case ImageTypesIotContainer: - var containerUploadOptions ContainerUploadOptions - jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONMarshallingError) - } - err = json.Unmarshal(jsonUploadOptions, &containerUploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONUnMarshallingError) - } + irTarget, err = newContainerTarget(ir, request, imageType) - var name = request.Distribution - var tag = uuid.New().String() - if containerUploadOptions.Name != nil { - name = *containerUploadOptions.Name - if containerUploadOptions.Tag != nil { - tag = *containerUploadOptions.Tag - } - } - - t := target.NewContainerTarget(&target.ContainerTargetOptions{}) - t.ImageName = fmt.Sprintf("%s:%s", name, tag) - t.OsbuildArtifact.ExportFilename = imageType.Filename() - - irTarget = t case ImageTypesGcp: fallthrough case ImageTypesGcpRhui: - var gcpUploadOptions GCPUploadOptions - jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONMarshallingError) - } - err = json.Unmarshal(jsonUploadOptions, &gcpUploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONUnMarshallingError) - } + irTarget, err = newGCPTarget(ir, imageType) - var share []string - if gcpUploadOptions.ShareWithAccounts != nil { - share = *gcpUploadOptions.ShareWithAccounts - } - - imageName := fmt.Sprintf("composer-api-%s", uuid.New().String()) - var bucket string - if gcpUploadOptions.Bucket != nil { - bucket = *gcpUploadOptions.Bucket - } - t := target.NewGCPTarget(&target.GCPTargetOptions{ - Region: gcpUploadOptions.Region, - Os: imageType.Arch().Distro().Name(), // not exposed in cloudapi - Bucket: bucket, - // the uploaded object must have a valid extension - Object: fmt.Sprintf("%s.tar.gz", imageName), - ShareWithAccounts: share, - }) - // Import will fail if an image with this name already exists - if gcpUploadOptions.ImageName != nil { - t.ImageName = *gcpUploadOptions.ImageName - } else { - t.ImageName = imageName - } - t.OsbuildArtifact.ExportFilename = imageType.Filename() - - irTarget = t case ImageTypesAzure: fallthrough case ImageTypesAzureRhui: @@ -207,54 +273,17 @@ func (ir *ImageRequest) GetTarget(request *ComposeRequest, imageType distro.Imag case ImageTypesAzureEap7Rhui: fallthrough case ImageTypesAzureSapRhui: - var azureUploadOptions AzureUploadOptions - jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONMarshallingError) - } - err = json.Unmarshal(jsonUploadOptions, &azureUploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONUnMarshallingError) - } - rgLocation := "" - if azureUploadOptions.Location != nil { - rgLocation = *azureUploadOptions.Location - } - t := target.NewAzureImageTarget(&target.AzureImageTargetOptions{ - TenantID: azureUploadOptions.TenantId, - Location: rgLocation, - SubscriptionID: azureUploadOptions.SubscriptionId, - ResourceGroup: azureUploadOptions.ResourceGroup, - }) + irTarget, err = newAzureTarget(ir, imageType) - if azureUploadOptions.ImageName != nil { - t.ImageName = *azureUploadOptions.ImageName - } else { - // if ImageName wasn't given, generate a random one - t.ImageName = fmt.Sprintf("composer-api-%s", uuid.New().String()) - } - t.OsbuildArtifact.ExportFilename = imageType.Filename() - - irTarget = t case ImageTypesOci: - var ociUploadOptions OCIUploadOptions - jsonUploadOptions, err := json.Marshal(*ir.UploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONMarshallingError) - } - err = json.Unmarshal(jsonUploadOptions, &ociUploadOptions) - if err != nil { - return nil, HTTPError(ErrorJSONUnMarshallingError) - } + irTarget, err = newOCITarget(ir, imageType) - key := fmt.Sprintf("composer-api-%s", uuid.New().String()) - t := target.NewOCIObjectStorageTarget(&target.OCIObjectStorageTargetOptions{}) - t.ImageName = key - t.OsbuildArtifact.ExportFilename = imageType.Filename() - irTarget = t default: return nil, HTTPError(ErrorUnsupportedImageType) } + if err != nil { + return nil, err + } irTarget.OsbuildArtifact.ExportName = imageType.Exports()[0] return irTarget, nil