diff --git a/internal/v1/api.go b/internal/v1/api.go index c8f4f4f65..4e5d631b2 100644 --- a/internal/v1/api.go +++ b/internal/v1/api.go @@ -249,7 +249,7 @@ type ImageRequest struct { Architecture ImageRequestArchitecture `json:"architecture"` ImageType ImageTypes `json:"image_type"` Ostree *OSTree `json:"ostree,omitempty"` - UploadRequest UploadRequest `json:"upload_request"` + UploadRequest *UploadRequest `json:"upload_request,omitempty"` } // CPU architecture of the image, only x86_64 is currently supported. @@ -674,36 +674,36 @@ var swaggerSpec = []string{ "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", + "18Z726d7invGR3Gwvdn+TwAAAP//1jLcHOM7AAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/internal/v1/api.yaml b/internal/v1/api.yaml index d120b5d92..6163014cf 100644 --- a/internal/v1/api.yaml +++ b/internal/v1/api.yaml @@ -395,7 +395,6 @@ components: required: - architecture - image_type - - upload_request properties: architecture: type: string diff --git a/internal/v1/server.go b/internal/v1/server.go index 4dbc6ef5b..d78e4403c 100644 --- a/internal/v1/server.go +++ b/internal/v1/server.go @@ -507,7 +507,7 @@ func (h *Handlers) ComposeImage(ctx echo.Context) error { return err } - if (composeRequest.ImageRequests[0].UploadRequest == UploadRequest{}) { + if (composeRequest.ImageRequests[0].UploadRequest == &UploadRequest{}) { return echo.NewHTTPError(http.StatusBadRequest, "Exactly one upload request should be included") } @@ -610,23 +610,28 @@ func (h *Handlers) ComposeImage(ctx echo.Context) error { }) } -func (s *Server) buildUploadOptions(ur UploadRequest, it ImageTypes) (composer.UploadOptions, composer.ImageTypes, error) { +func (s *Server) buildAWSS3UploadOptions(options []byte, composerImageType composer.ImageTypes) (composer.UploadOptions, composer.ImageTypes, error) { + var awsOptions AWSS3UploadRequestOptions + err := json.Unmarshal(options, &awsOptions) + if err != nil { + return nil, "", echo.NewHTTPError(http.StatusBadRequest, "Unable to unmarshal UploadRequestOptions") + } + return composer.AWSS3UploadOptions{ + Region: s.aws.Region, + }, composerImageType, nil +} + +func (s *Server) buildUploadOptions(ur *UploadRequest, it ImageTypes) (composer.UploadOptions, composer.ImageTypes, error) { // HACK deepmap doesn't really support `oneOf`, so marshal and unmarshal into target object optionsJSON, err := json.Marshal(ur.Options) if err != nil { return nil, "", echo.NewHTTPError(http.StatusBadRequest, "Unable to marshal UploadRequestOptions") } - switch ur.Type { - case UploadTypesAws: - var composerImageType composer.ImageTypes - switch it { - case ImageTypesAws: - fallthrough - case ImageTypesAmi: - composerImageType = composer.ImageTypesAws - default: - return nil, "", echo.NewHTTPError(http.StatusBadRequest, "Invalid image type for upload target") - } + + switch it { + + // Upload Type AWS + case ImageTypesAmi, ImageTypesAws: var awsOptions AWSUploadRequestOptions err = json.Unmarshal(optionsJSON, &awsOptions) if err != nil { @@ -635,43 +640,22 @@ func (s *Server) buildUploadOptions(ur UploadRequest, it ImageTypes) (composer.U return composer.AWSEC2UploadOptions{ Region: s.aws.Region, ShareWithAccounts: awsOptions.ShareWithAccounts, - }, composerImageType, nil - case UploadTypesAwsS3: - var composerImageType composer.ImageTypes - switch it { - case ImageTypesEdgeCommit: - fallthrough - case ImageTypesRhelEdgeCommit: - composerImageType = composer.ImageTypesEdgeCommit - case ImageTypesEdgeInstaller: - fallthrough - case ImageTypesRhelEdgeInstaller: - composerImageType = composer.ImageTypesEdgeInstaller - case ImageTypesGuestImage: - composerImageType = composer.ImageTypesGuestImage - case ImageTypesImageInstaller: - composerImageType = composer.ImageTypesImageInstaller - case ImageTypesVsphere: - composerImageType = composer.ImageTypesVsphere - default: - return nil, "", echo.NewHTTPError(http.StatusBadRequest, "Invalid image type for upload target") - } - var awsOptions AWSS3UploadRequestOptions - err = json.Unmarshal(optionsJSON, &awsOptions) - if err != nil { - return nil, "", echo.NewHTTPError(http.StatusBadRequest, "Unable to unmarshal UploadRequestOptions") - } - return composer.AWSS3UploadOptions{ - Region: s.aws.Region, - }, composerImageType, nil - case UploadTypesGcp: - var composerImageType composer.ImageTypes - switch it { - case ImageTypesGcp: - composerImageType = composer.ImageTypesGcp - default: - return nil, "", echo.NewHTTPError(http.StatusBadRequest, "Invalid image type for upload target") - } + }, composer.ImageTypesAws, nil + + // Upload Type AWS S3 + case ImageTypesEdgeCommit, ImageTypesRhelEdgeCommit: + return s.buildAWSS3UploadOptions(optionsJSON, composer.ImageTypesEdgeCommit) + case ImageTypesEdgeInstaller, ImageTypesRhelEdgeInstaller: + return s.buildAWSS3UploadOptions(optionsJSON, composer.ImageTypesEdgeInstaller) + case ImageTypesGuestImage: + return s.buildAWSS3UploadOptions(optionsJSON, composer.ImageTypesGuestImage) + case ImageTypesImageInstaller: + return s.buildAWSS3UploadOptions(optionsJSON, composer.ImageTypesImageInstaller) + case ImageTypesVsphere: + return s.buildAWSS3UploadOptions(optionsJSON, composer.ImageTypesVsphere) + + // Upload Type GCP + case ImageTypesGcp: var gcpOptions GCPUploadRequestOptions err = json.Unmarshal(optionsJSON, &gcpOptions) if err != nil { @@ -681,17 +665,10 @@ func (s *Server) buildUploadOptions(ur UploadRequest, it ImageTypes) (composer.U Bucket: s.gcp.Bucket, Region: s.gcp.Region, ShareWithAccounts: &gcpOptions.ShareWithAccounts, - }, composerImageType, nil - case UploadTypesAzure: - var composerImageType composer.ImageTypes - switch it { - case ImageTypesAzure: - fallthrough - case ImageTypesVhd: - composerImageType = composer.ImageTypesAzure - default: - return nil, "", echo.NewHTTPError(http.StatusBadRequest, "Invalid image type for upload target") - } + }, composer.ImageTypesGcp, nil + + // Upload Type Azure + case ImageTypesAzure, ImageTypesVhd: var azureOptions AzureUploadRequestOptions err = json.Unmarshal(optionsJSON, &azureOptions) if err != nil { @@ -702,7 +679,8 @@ func (s *Server) buildUploadOptions(ur UploadRequest, it ImageTypes) (composer.U SubscriptionId: azureOptions.SubscriptionId, ResourceGroup: azureOptions.ResourceGroup, Location: s.azure.Location, - }, composerImageType, nil + }, composer.ImageTypesAzure, nil + default: return nil, "", echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unknown UploadRequest type %s", ur.Type)) } diff --git a/internal/v1/server_test.go b/internal/v1/server_test.go index 4e579c8f8..527802880 100644 --- a/internal/v1/server_test.go +++ b/internal/v1/server_test.go @@ -554,7 +554,7 @@ func TestComposeImage(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAws, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -564,7 +564,7 @@ func TestComposeImage(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAmi, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -578,22 +578,19 @@ func TestComposeImage(t *testing.T) { require.Contains(t, body, `Error at \"/image_requests\": maximum number of items is 1`) }) - t.Run("ErrorsForZeroUploadRequests", func(t *testing.T) { + t.Run("NoErrorsForZeroUploadRequests", func(t *testing.T) { payload := ComposeRequest{ Customizations: nil, Distribution: "centos-8", ImageRequests: []ImageRequest{ { - Architecture: "x86_64", - ImageType: ImageTypesAzure, - UploadRequest: UploadRequest{}, + Architecture: "x86_64", + ImageType: ImageTypesAzure, }, }, } - response, body := tutils.PostResponseBody(t, "http://localhost:8086/api/image-builder/v1/compose", payload) - require.Equal(t, 400, response.StatusCode) - require.Regexp(t, "image_requests/0/upload_request/options|image_requests/0/upload_request/type", body) - require.Regexp(t, "Value is not nullable|value is not one of the allowed values", body) + response, _ := tutils.PostResponseBody(t, "http://localhost:8086/api/image-builder/v1/compose", payload) + require.Equal(t, 200, response.StatusCode) }) t.Run("ISEWhenRepositoriesNotFound", func(t *testing.T) { @@ -606,7 +603,7 @@ func TestComposeImage(t *testing.T) { { Architecture: "unsupported-arch", ImageType: ImageTypesAws, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -644,7 +641,7 @@ func TestComposeImage(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAmi, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -667,7 +664,7 @@ func TestComposeImage(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAzure, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: "unknown", Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -713,7 +710,7 @@ func TestComposeImageErrorsWhenStatusCodeIsNotStatusCreated(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAws, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -757,7 +754,7 @@ func TestComposeImageErrorsWhenCannotParseResponse(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAws, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -803,7 +800,7 @@ func TestComposeImageReturnsIdWhenNoErrors(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAws, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -850,7 +847,7 @@ func TestComposeImageAllowList(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesAws, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAws, Options: AWSUploadRequestOptions{ ShareWithAccounts: []string{"test-account"}, @@ -1008,7 +1005,7 @@ func TestComposeCustomizations(t *testing.T) { { Architecture: "x86_64", ImageType: ImageTypesRhelEdgeInstaller, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAwsS3, Options: AWSS3UploadRequestOptions{}, }, @@ -1105,7 +1102,7 @@ func TestComposeCustomizations(t *testing.T) { Ostree: &OSTree{ Ref: strptr("edge/ref"), }, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAwsS3, Options: AWSS3UploadRequestOptions{}, }, @@ -1169,7 +1166,7 @@ func TestComposeCustomizations(t *testing.T) { Url: strptr("https://ostree.srv/"), Parent: strptr("test/edge/ref2"), }, - UploadRequest: UploadRequest{ + UploadRequest: &UploadRequest{ Type: UploadTypesAwsS3, Options: AWSS3UploadRequestOptions{}, },