diff --git a/pkg/frontend/clustermanager_delete.go b/pkg/frontend/clustermanager_delete.go deleted file mode 100644 index aac3974f5bf..00000000000 --- a/pkg/frontend/clustermanager_delete.go +++ /dev/null @@ -1,67 +0,0 @@ -package frontend - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -import ( - "context" - "net/http" - - "github.com/go-chi/chi/v5" - "github.com/sirupsen/logrus" - - "github.com/Azure/ARO-RP/pkg/api" - "github.com/Azure/ARO-RP/pkg/database/cosmosdb" - "github.com/Azure/ARO-RP/pkg/frontend/middleware" -) - -func (f *frontend) deleteClusterManagerConfiguration(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry) - var err error - - apiVersion, ocmResourceType := r.URL.Query().Get(api.APIVersionKey), chi.URLParam(r, "ocmResourceType") - - err = f.validateOcmResourceType(apiVersion, ocmResourceType) - if err != nil { - api.WriteError(w, http.StatusBadRequest, api.CloudErrorCodeInvalidResourceType, "", err.Error()) - return - } - - err = f._deleteClusterManagerConfigurationDocument(ctx, log, r) - - switch { - case cosmosdb.IsErrorStatusCode(err, http.StatusNotFound): - err = statusCodeError(http.StatusNoContent) - case err == nil: - err = statusCodeError(http.StatusOK) - } - - reply(log, w, nil, nil, err) -} - -func (f *frontend) _deleteClusterManagerConfigurationDocument(ctx context.Context, log *logrus.Entry, r *http.Request) error { - _, err := f.validateSubscriptionState(ctx, r.URL.Path, api.SubscriptionStateRegistered, api.SubscriptionStateSuspended, api.SubscriptionStateWarned) - if err != nil { - return err - } - - resourceType, resourceName, ocmResourceType, ocmResourceName, resourceGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName"), chi.URLParam(r, "resourceGroupName") - doc, err := f.dbClusterManagerConfiguration.Get(ctx, r.URL.Path) - switch { - case cosmosdb.IsErrorStatusCode(err, http.StatusNotFound): - return api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s/%s/%s' under resource group '%s' was not found.", - resourceType, resourceName, ocmResourceType, ocmResourceName, resourceGroupName) - case err != nil: - return err - } - - // Right now we are going to assume that the backend will delete the document, we will just mark for deletion. - doc.Deleting = true - err = cosmosdb.RetryOnPreconditionFailed(func() error { - var err error - _, err = f.dbClusterManagerConfiguration.Update(ctx, doc) - return err - }) - return err -} diff --git a/pkg/frontend/clustermanager_delete_test.go b/pkg/frontend/clustermanager_delete_test.go deleted file mode 100644 index 4d592bef272..00000000000 --- a/pkg/frontend/clustermanager_delete_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package frontend - -import ( - "context" - "fmt" - "net/http" - "testing" - - "github.com/Azure/ARO-RP/pkg/api" - "github.com/Azure/ARO-RP/pkg/env" - "github.com/Azure/ARO-RP/pkg/metrics/noop" - testdatabase "github.com/Azure/ARO-RP/test/database" -) - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -func TestDeleteClusterManagerConfiguration(t *testing.T) { - ctx := context.Background() - - mockSubscriptionId := "00000000-0000-0000-0000-000000000000" - tenantId := "11111111-1111-1111-1111-111111111111" - resourcePayload := "eyAKICAiYXBpVmVyc2lvbiI6ICJoaXZlLm9wZW5zaGlmdC5pby92MSIsCiAgImtpbmQiOiAiU3luY1NldCIsCiAgIm1ldGFkYXRhIjogewogICAgIm5hbWUiOiAic2FtcGxlIiwKICAgICJuYW1lc3BhY2UiOiAiYXJvLWY2MGFlOGEyLWJjYTEtNDk4Ny05MDU2LWYyZjZhMTgzN2NhYSIKICB9LAogICJzcGVjIjogewogICAgImNsdXN0ZXJEZXBsb3ltZW50UmVmcyI6IFtdLAogICAgInJlc291cmNlcyI6IFsKICAgICAgewogICAgICAgICJhcGlWZXJzaW9uIjogInYxIiwKICAgICAgICAia2luZCI6ICJDb25maWdNYXAiLAogICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgICJuYW1lIjogIm15Y29uZmlnbWFwIgogICAgICAgIH0KICAgICAgfQogICAgXQogIH0KfQo=" - - type test struct { - name string - ocmResourceType string - ocmResourceName string - clusterName string - apiVersion string - fixture func(*testdatabase.Fixture, *test, string) - wantStatusCode int - wantError string - } - createSingleDocument := func(f *testdatabase.Fixture, tt *test, resourceKey string) { - f.AddSubscriptionDocuments(&api.SubscriptionDocument{ - ID: mockSubscriptionId, - Subscription: &api.Subscription{ - State: api.SubscriptionStateRegistered, - Properties: &api.SubscriptionProperties{ - TenantID: tenantId, - }, - }, - }) - f.AddClusterManagerConfigurationDocuments( - &api.ClusterManagerConfigurationDocument{ - ID: mockSubscriptionId, - Key: resourceKey, - SyncSet: &api.SyncSet{ - Properties: api.SyncSetProperties{ - Resources: resourcePayload, - }, - }, - }, - ) - } - - for _, tt := range []*test{ - { - name: "single syncset", - ocmResourceType: "syncSet", - ocmResourceName: "deleteSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: createSingleDocument, - wantStatusCode: http.StatusOK, - }, - { - name: "does not exist", - ocmResourceType: "syncSet", - ocmResourceName: "deleteSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: func(f *testdatabase.Fixture, tt *test, resourceKey string) { - f.AddSubscriptionDocuments(&api.SubscriptionDocument{ - ID: mockSubscriptionId, - Subscription: &api.Subscription{ - State: api.SubscriptionStateRegistered, - Properties: &api.SubscriptionProperties{ - TenantID: tenantId, - }, - }, - }) - }, - wantStatusCode: http.StatusNotFound, - wantError: "404: ResourceNotFound: : The Resource 'openshiftclusters/resourcename/syncset/deletesyncset' under resource group 'resourcegroup' was not found.", - }, - { - name: "unsupported api version", - ocmResourceType: "syncSet", - ocmResourceName: "deleteSyncSet", - clusterName: "myCluster", - apiVersion: "2022-04-01", - fixture: createSingleDocument, - wantStatusCode: http.StatusBadRequest, - wantError: "400: InvalidResourceType: : the resource type 'syncset' is not valid for api version '2022-04-01'", - }, - { - name: "unsupported resource type", - ocmResourceType: "unsupported", - ocmResourceName: "deleteSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: createSingleDocument, - wantStatusCode: http.StatusBadRequest, - wantError: "400: InvalidResourceType: : the resource type 'unsupported' is not valid for api version '2022-09-04'", - }, - } { - t.Run(tt.name, func(t *testing.T) { - ti := newTestInfraWithFeatures(t, map[env.Feature]bool{env.FeatureRequireD2sV3Workers: false, env.FeatureDisableReadinessDelay: false, env.FeatureEnableOCMEndpoints: true}).WithClusterManagerConfigurations().WithSubscriptions() - defer ti.done() - - resourceKey := fmt.Sprintf("/subscriptions/%s/resourcegroups/resourcegroup/providers/microsoft.redhatopenshift/openshiftclusters/resourcename/%s/%s", - mockSubscriptionId, - tt.ocmResourceType, - tt.ocmResourceName) - - err := ti.buildFixtures(func(f *testdatabase.Fixture) { tt.fixture(f, tt, resourceKey) }) - if err != nil { - t.Fatal(err) - } - - f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, nil, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil) - if err != nil { - t.Fatal(err) - } - - go f.Run(ctx, nil, nil) - - resp, b, err := ti.request(http.MethodDelete, - fmt.Sprintf("https://server%s?api-version=%s", - resourceKey, - tt.apiVersion, - ), - nil, nil) - if err != nil { - t.Fatalf("%s: %s", err, string(b)) - } - - err = validateResponse(resp, b, tt.wantStatusCode, tt.wantError, "") - if err != nil { - t.Errorf("%s: %s", err, string(b)) - } - }) - } -} diff --git a/pkg/frontend/clustermanager_get.go b/pkg/frontend/clustermanager_get.go deleted file mode 100644 index 5f65dc85df5..00000000000 --- a/pkg/frontend/clustermanager_get.go +++ /dev/null @@ -1,115 +0,0 @@ -package frontend - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/go-chi/chi/v5" - "github.com/sirupsen/logrus" - - "github.com/Azure/ARO-RP/pkg/api" - "github.com/Azure/ARO-RP/pkg/database/cosmosdb" - "github.com/Azure/ARO-RP/pkg/frontend/middleware" -) - -func (f *frontend) getClusterManagerConfiguration(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry) - - ocmResourceType := chi.URLParam(r, "ocmResourceType") - - var ( - b []byte - err error - ) - - apiVersion := r.URL.Query().Get(api.APIVersionKey) - - err = f.validateOcmResourceType(apiVersion, ocmResourceType) - if err != nil { - api.WriteError(w, http.StatusBadRequest, api.CloudErrorCodeInvalidResourceType, "", err.Error()) - return - } - - switch ocmResourceType { - case "syncset": - b, err = f._getSyncSetConfiguration(ctx, log, r, f.apis[apiVersion].SyncSetConverter) - case "machinepool": - b, err = f._getMachinePoolConfiguration(ctx, log, r, f.apis[apiVersion].MachinePoolConverter) - case "syncidentityprovider": - b, err = f._getSyncIdentityProviderConfiguration(ctx, log, r, f.apis[apiVersion].SyncIdentityProviderConverter) - case "secret": - b, err = f._getSecretConfiguration(ctx, log, r, f.apis[apiVersion].SecretConverter) - default: - return - } - - reply(log, w, nil, b, err) -} - -func (f *frontend) _getSyncSetConfiguration(ctx context.Context, log *logrus.Entry, r *http.Request, converter api.SyncSetConverter) ([]byte, error) { - resType, resName, ocmResType, ocmResName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName"), chi.URLParam(r, "resourceGroupName") - doc, err := f.validateResourceForGet(ctx, resType, resName, ocmResType, ocmResName, resGroupName, r.URL.Path, r) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(doc.SyncSet) - return json.MarshalIndent(ext, "", " ") -} - -func (f *frontend) _getMachinePoolConfiguration(ctx context.Context, log *logrus.Entry, r *http.Request, converter api.MachinePoolConverter) ([]byte, error) { - resType, resName, ocmResType, ocmResName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName"), chi.URLParam(r, "resourceGroupName") - doc, err := f.validateResourceForGet(ctx, resType, resName, ocmResType, ocmResName, resGroupName, r.URL.Path, r) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(doc.MachinePool) - return json.MarshalIndent(ext, "", " ") -} - -func (f *frontend) _getSyncIdentityProviderConfiguration(ctx context.Context, log *logrus.Entry, r *http.Request, converter api.SyncIdentityProviderConverter) ([]byte, error) { - resType, resName, ocmResType, ocmResName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName"), chi.URLParam(r, "resourceGroupName") - doc, err := f.validateResourceForGet(ctx, resType, resName, ocmResType, ocmResName, resGroupName, r.URL.Path, r) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(doc.SyncIdentityProvider) - return json.MarshalIndent(ext, "", " ") -} - -func (f *frontend) _getSecretConfiguration(ctx context.Context, log *logrus.Entry, r *http.Request, converter api.SecretConverter) ([]byte, error) { - resType, resName, ocmResType, ocmResName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName"), chi.URLParam(r, "resourceGroupName") - doc, err := f.validateResourceForGet(ctx, resType, resName, ocmResType, ocmResName, resGroupName, r.URL.Path, r) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(doc.Secret) - return json.MarshalIndent(ext, "", " ") -} - -func (f *frontend) validateResourceForGet(ctx context.Context, resType, resName, ocmResType, ocmResName, resGroupName, path string, r *http.Request) (*api.ClusterManagerConfigurationDocument, error) { - doc, err := f.dbClusterManagerConfiguration.Get(ctx, r.URL.Path) - if err != nil { - switch { - case cosmosdb.IsErrorStatusCode(err, http.StatusNotFound): - return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s/%s/%s' under resource group '%s' was not found.", - resType, resName, ocmResType, ocmResName, resGroupName) - default: - return nil, err - } - } - - if doc.Deleting { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeRequestNotAllowed, "", "Request is not allowed on a resource marked for deletion.") - } - - return doc, nil -} diff --git a/pkg/frontend/clustermanager_get_test.go b/pkg/frontend/clustermanager_get_test.go deleted file mode 100644 index 66f6e1ac95c..00000000000 --- a/pkg/frontend/clustermanager_get_test.go +++ /dev/null @@ -1,149 +0,0 @@ -package frontend - -import ( - "context" - "fmt" - "net/http" - "testing" - - "github.com/Azure/ARO-RP/pkg/api" - v20220904 "github.com/Azure/ARO-RP/pkg/api/v20220904" - "github.com/Azure/ARO-RP/pkg/env" - "github.com/Azure/ARO-RP/pkg/metrics/noop" - testdatabase "github.com/Azure/ARO-RP/test/database" -) - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -func TestGetClusterManagerConfiguration(t *testing.T) { - ctx := context.Background() - - mockSubscriptionId := "00000000-0000-0000-0000-000000000000" - resourcePayload := "eyAKICAiYXBpVmVyc2lvbiI6ICJoaXZlLm9wZW5zaGlmdC5pby92MSIsCiAgImtpbmQiOiAiU3luY1NldCIsCiAgIm1ldGFkYXRhIjogewogICAgIm5hbWUiOiAic2FtcGxlIiwKICAgICJuYW1lc3BhY2UiOiAiYXJvLWY2MGFlOGEyLWJjYTEtNDk4Ny05MDU2LWYyZjZhMTgzN2NhYSIKICB9LAogICJzcGVjIjogewogICAgImNsdXN0ZXJEZXBsb3ltZW50UmVmcyI6IFtdLAogICAgInJlc291cmNlcyI6IFsKICAgICAgewogICAgICAgICJhcGlWZXJzaW9uIjogInYxIiwKICAgICAgICAia2luZCI6ICJDb25maWdNYXAiLAogICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgICJuYW1lIjogIm15Y29uZmlnbWFwIgogICAgICAgIH0KICAgICAgfQogICAgXQogIH0KfQo=" - - type test struct { - name string - ocmResourceType string - ocmResourceName string - clusterName string - apiVersion string - fixture func(*testdatabase.Fixture, *test, string) - wantStatusCode int - wantResponse *v20220904.SyncSet - wantError string - } - createSingleDocument := func(f *testdatabase.Fixture, tt *test, resourceKey string) { - f.AddClusterManagerConfigurationDocuments( - &api.ClusterManagerConfigurationDocument{ - ID: mockSubscriptionId, - Key: resourceKey, - SyncSet: &api.SyncSet{ - Name: tt.ocmResourceName, - Properties: api.SyncSetProperties{ - Resources: resourcePayload, - }, - }, - }, - ) - } - - for _, tt := range []*test{ - { - name: "single syncset", - ocmResourceType: "syncSet", - ocmResourceName: "mySyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: createSingleDocument, - wantStatusCode: http.StatusOK, - wantResponse: &v20220904.SyncSet{ - Name: "mySyncSet", - Properties: v20220904.SyncSetProperties{ - Resources: resourcePayload, - }, - }, - }, - { - name: "syncset is deleting", - ocmResourceType: "syncSet", - ocmResourceName: "myDeletingSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: func(f *testdatabase.Fixture, tt *test, resourceKey string) { - f.AddClusterManagerConfigurationDocuments( - &api.ClusterManagerConfigurationDocument{ - ID: mockSubscriptionId, - Key: resourceKey, - Deleting: true, - SyncSet: &api.SyncSet{ - Name: tt.ocmResourceName, - Properties: api.SyncSetProperties{ - Resources: resourcePayload, - }, - }, - }, - ) - }, - wantStatusCode: http.StatusBadRequest, - wantError: "400: RequestNotAllowed: : Request is not allowed on a resource marked for deletion.", - }, - { - name: "wrong version", - ocmResourceType: "syncset", - ocmResourceName: "mySyncSet", - clusterName: "myCluster", - apiVersion: "2022-04-01", - fixture: createSingleDocument, - wantStatusCode: http.StatusBadRequest, - wantError: "400: InvalidResourceType: : the resource type 'syncset' is not valid for api version '2022-04-01'", - }, - { - name: "unsupported resource type", - ocmResourceType: "unsupported", - ocmResourceName: "invalidResourceType", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: createSingleDocument, - wantStatusCode: http.StatusBadRequest, - wantError: "400: InvalidResourceType: : the resource type 'unsupported' is not valid for api version '2022-09-04'", - }, - } { - t.Run(tt.name, func(t *testing.T) { - ti := newTestInfraWithFeatures(t, map[env.Feature]bool{env.FeatureRequireD2sV3Workers: false, env.FeatureDisableReadinessDelay: false, env.FeatureEnableOCMEndpoints: true}).WithClusterManagerConfigurations() - defer ti.done() - - resourceKey := fmt.Sprintf("/subscriptions/%s/resourcegroups/resourcegroup/providers/microsoft.redhatopenshift/openshiftclusters/resourcename/%s/%s", - mockSubscriptionId, - tt.ocmResourceType, - tt.ocmResourceName) - - err := ti.buildFixtures(func(f *testdatabase.Fixture) { tt.fixture(f, tt, resourceKey) }) - if err != nil { - t.Fatal(err) - } - - f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, nil, nil, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil) - if err != nil { - t.Fatal(err) - } - - go f.Run(ctx, nil, nil) - - resp, b, err := ti.request(http.MethodGet, - fmt.Sprintf("https://server%s?api-version=%s", - resourceKey, - tt.apiVersion, - ), - nil, nil) - if err != nil { - t.Fatalf("%s: %s", err, string(b)) - } - - err = validateResponse(resp, b, tt.wantStatusCode, tt.wantError, tt.wantResponse) - if err != nil { - t.Errorf("%s: %s", err, string(b)) - } - }) - } -} diff --git a/pkg/frontend/clustermanager_putorpatch.go b/pkg/frontend/clustermanager_putorpatch.go deleted file mode 100644 index 257af4f2b1d..00000000000 --- a/pkg/frontend/clustermanager_putorpatch.go +++ /dev/null @@ -1,480 +0,0 @@ -package frontend - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/go-chi/chi/v5" - "github.com/sirupsen/logrus" - - "github.com/Azure/ARO-RP/pkg/api" - "github.com/Azure/ARO-RP/pkg/database/cosmosdb" - "github.com/Azure/ARO-RP/pkg/frontend/middleware" - "github.com/Azure/ARO-RP/pkg/util/arm" -) - -func (f *frontend) putOrPatchClusterManagerConfiguration(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry) - - var ( - header http.Header - b []byte - err error - ) - - apiVersion, ocmResourceType := r.URL.Query().Get(api.APIVersionKey), chi.URLParam(r, "ocmResourceType") - - err = f.validateOcmResourceType(apiVersion, ocmResourceType) - if err != nil { - api.WriteError(w, http.StatusBadRequest, api.CloudErrorCodeInvalidResourceType, "", err.Error()) - return - } - - err = cosmosdb.RetryOnPreconditionFailed(func() error { - var err error - switch ocmResourceType { - case "syncset": - b, err = f._putOrPatchSyncSet(ctx, log, r, &header, f.apis[apiVersion].SyncSetConverter, f.apis[apiVersion].ClusterManagerStaticValidator) - case "machinepool": - b, err = f._putOrPatchMachinePool(ctx, log, r, &header, f.apis[apiVersion].MachinePoolConverter, f.apis[apiVersion].ClusterManagerStaticValidator) - case "syncidentityprovider": - b, err = f._putOrPatchSyncIdentityProvider(ctx, log, r, &header, f.apis[apiVersion].SyncIdentityProviderConverter, f.apis[apiVersion].ClusterManagerStaticValidator) - case "secret": - b, err = f._putOrPatchSecret(ctx, log, r, &header, f.apis[apiVersion].SecretConverter, f.apis[apiVersion].ClusterManagerStaticValidator) - } - return err - }) - - reply(log, w, header, b, err) -} - -func (f *frontend) _putOrPatchSyncSet(ctx context.Context, log *logrus.Entry, r *http.Request, header *http.Header, converter api.SyncSetConverter, staticValidator api.ClusterManagerStaticValidator) ([]byte, error) { - body := r.Context().Value(middleware.ContextKeyBody).([]byte) - correlationData := r.Context().Value(middleware.ContextKeyCorrelationData).(*api.CorrelationData) - systemData, _ := r.Context().Value(middleware.ContextKeySystemData).(*api.SystemData) // don't panic - resType, resName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "resourceGroupName") - ocmResourceType, ocmResourceName := chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName") - originalPath, err := f.extractOriginalPath(ctx, r, resType, resName, resGroupName) - if err != nil { - return nil, err - } - - ocmdoc, err := f.dbClusterManagerConfiguration.Get(ctx, r.URL.Path) - if err != nil && !cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) { - return nil, err - } else if cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) && r.Method == http.MethodPatch { - return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s/%s/%s' under resource group '%s' was not found.", - resType, resName, ocmResourceType, ocmResourceName, resGroupName) - } - - var resources string - err = json.Unmarshal(body, &resources) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content was invalid and could not be deserialized: %q.", err) - } - - err = staticValidator.Static(resources, ocmResourceType) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The 'Kind' in the request payload does not match 'Kind' in the request path: %q.", err) - } - - isCreate := ocmdoc == nil - uuid := f.dbClusterManagerConfiguration.NewUUID() - if isCreate { - ocmdoc = &api.ClusterManagerConfigurationDocument{ - ID: uuid, - Key: r.URL.Path, - } - ocmdoc.SyncSet = &api.SyncSet{ - Name: ocmResourceName, - Type: "Microsoft.RedHatOpenShift/SyncSet", - ID: originalPath, - Properties: api.SyncSetProperties{ - Resources: resources, - }, - } - - var newdoc *api.ClusterManagerConfigurationDocument - err = cosmosdb.RetryOnPreconditionFailed(func() error { - newdoc, err = f.dbClusterManagerConfiguration.Create(ctx, ocmdoc) - return err - }) - ocmdoc = newdoc - } else { - if ocmdoc.Deleting { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeRequestNotAllowed, "", "Request is not allowed on a resource marked for deletion.") - } - ocmdoc.SyncSet.Properties.Resources = resources - } - - ocmdoc.CorrelationData = correlationData - f.systemDataSyncSetEnricher(ocmdoc, systemData) - - ocmdoc, err = f.dbClusterManagerConfiguration.Update(ctx, ocmdoc) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(ocmdoc.SyncSet) - b, err := json.MarshalIndent(ext, "", " ") - return b, err -} - -func (f *frontend) _putOrPatchMachinePool(ctx context.Context, log *logrus.Entry, r *http.Request, header *http.Header, converter api.MachinePoolConverter, staticValidator api.ClusterManagerStaticValidator) ([]byte, error) { - body := r.Context().Value(middleware.ContextKeyBody).([]byte) - correlationData := r.Context().Value(middleware.ContextKeyCorrelationData).(*api.CorrelationData) - systemData, _ := r.Context().Value(middleware.ContextKeySystemData).(*api.SystemData) // don't panic - resType, resName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "resourceGroupName") - ocmResourceType, ocmResourceName := chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName") - - originalPath, err := f.extractOriginalPath(ctx, r, resType, resName, resGroupName) - if err != nil { - return nil, err - } - - ocmdoc, err := f.dbClusterManagerConfiguration.Get(ctx, r.URL.Path) - if err != nil && !cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) { - return nil, err - } else if cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) && r.Method == http.MethodPatch { - return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s/%s/%s' under resource group '%s' was not found.", - resType, resName, ocmResourceType, ocmResourceName, resGroupName) - } - - var resources string - err = json.Unmarshal(body, &resources) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content was invalid and could not be deserialized: %q.", err) - } - - err = staticValidator.Static(resources, ocmResourceType) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The 'Kind' in the request payload does not match 'Kind' in the request path: %q.", err) - } - - isCreate := ocmdoc == nil - uuid := f.dbClusterManagerConfiguration.NewUUID() - if isCreate { - ocmdoc = &api.ClusterManagerConfigurationDocument{ - ID: uuid, - Key: r.URL.Path, - } - ocmdoc.MachinePool = &api.MachinePool{ - Name: ocmResourceName, - Type: "Microsoft.RedHatOpenShift/MachinePool", - ID: originalPath, - Properties: api.MachinePoolProperties{ - Resources: resources, - }, - } - - var newdoc *api.ClusterManagerConfigurationDocument - err = cosmosdb.RetryOnPreconditionFailed(func() error { - newdoc, err = f.dbClusterManagerConfiguration.Create(ctx, ocmdoc) - return err - }) - ocmdoc = newdoc - } else { - if ocmdoc.Deleting { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeRequestNotAllowed, "", "Request is not allowed on a resource marked for deletion.") - } - ocmdoc.MachinePool.Properties.Resources = resources - } - - ocmdoc.CorrelationData = correlationData - f.systemDataMachinePoolEnricher(ocmdoc, systemData) - - ocmdoc, err = f.dbClusterManagerConfiguration.Update(ctx, ocmdoc) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(ocmdoc.MachinePool) - b, err := json.MarshalIndent(ext, "", " ") - return b, err -} - -func (f *frontend) _putOrPatchSyncIdentityProvider(ctx context.Context, log *logrus.Entry, r *http.Request, header *http.Header, converter api.SyncIdentityProviderConverter, staticValidator api.ClusterManagerStaticValidator) ([]byte, error) { - body := r.Context().Value(middleware.ContextKeyBody).([]byte) - correlationData := r.Context().Value(middleware.ContextKeyCorrelationData).(*api.CorrelationData) - systemData, _ := r.Context().Value(middleware.ContextKeySystemData).(*api.SystemData) // don't panic - resType, resName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "resourceGroupName") - ocmResourceType, ocmResourceName := chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName") - - originalPath, err := f.extractOriginalPath(ctx, r, resType, resName, resGroupName) - if err != nil { - return nil, err - } - - ocmdoc, err := f.dbClusterManagerConfiguration.Get(ctx, r.URL.Path) - if err != nil && !cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) { - return nil, err - } else if cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) && r.Method == http.MethodPatch { - return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s/%s/%s' under resource group '%s' was not found.", - resType, resName, ocmResourceType, ocmResourceName, resGroupName) - } - - var resources string - err = json.Unmarshal(body, &resources) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content was invalid and could not be deserialized: %q.", err) - } - - err = staticValidator.Static(resources, ocmResourceType) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The 'Kind' in the request payload does not match 'Kind' in the request path: %q.", err) - } - - isCreate := ocmdoc == nil - uuid := f.dbClusterManagerConfiguration.NewUUID() - if isCreate { - ocmdoc = &api.ClusterManagerConfigurationDocument{ - ID: uuid, - Key: r.URL.Path, - } - ocmdoc.SyncIdentityProvider = &api.SyncIdentityProvider{ - Name: ocmResourceName, - Type: "Microsoft.RedHatOpenShift/SyncIdentityProvider", - ID: originalPath, - Properties: api.SyncIdentityProviderProperties{ - Resources: resources, - }, - } - - var newdoc *api.ClusterManagerConfigurationDocument - err = cosmosdb.RetryOnPreconditionFailed(func() error { - newdoc, err = f.dbClusterManagerConfiguration.Create(ctx, ocmdoc) - return err - }) - ocmdoc = newdoc - } else { - if ocmdoc.Deleting { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeRequestNotAllowed, "", "Request is not allowed on a resource marked for deletion.") - } - ocmdoc.SyncIdentityProvider.Properties.Resources = resources - } - - ocmdoc.CorrelationData = correlationData - f.systemDataSyncIdentityProviderEnricher(ocmdoc, systemData) - - ocmdoc, err = f.dbClusterManagerConfiguration.Update(ctx, ocmdoc) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(ocmdoc.SyncIdentityProvider) - b, err := json.MarshalIndent(ext, "", " ") - return b, err -} - -func (f *frontend) _putOrPatchSecret(ctx context.Context, log *logrus.Entry, r *http.Request, header *http.Header, converter api.SecretConverter, staticValidator api.ClusterManagerStaticValidator) ([]byte, error) { - body := r.Context().Value(middleware.ContextKeyBody).([]byte) - correlationData := r.Context().Value(middleware.ContextKeyCorrelationData).(*api.CorrelationData) - systemData, _ := r.Context().Value(middleware.ContextKeySystemData).(*api.SystemData) // don't panic - resType, resName, resGroupName := chi.URLParam(r, "resourceType"), chi.URLParam(r, "resourceName"), chi.URLParam(r, "resourceGroupName") - ocmResourceType, ocmResourceName := chi.URLParam(r, "ocmResourceType"), chi.URLParam(r, "ocmResourceName") - - originalPath, err := f.extractOriginalPath(ctx, r, resType, resName, resGroupName) - if err != nil { - return nil, err - } - - ocmdoc, err := f.dbClusterManagerConfiguration.Get(ctx, r.URL.Path) - if err != nil && !cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) { - return nil, err - } else if cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) && r.Method == http.MethodPatch { - return nil, api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s/%s/%s' under resource group '%s' was not found.", - resType, resName, ocmResourceType, ocmResourceName, resGroupName) - } - - var resources string - err = json.Unmarshal(body, &resources) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content was invalid and could not be deserialized: %q.", err) - } - - err = staticValidator.Static(resources, ocmResourceType) - if err != nil { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The 'Kind' in the request payload does not match 'Kind' in the request path: %q.", err) - } - - isCreate := ocmdoc == nil - uuid := f.dbClusterManagerConfiguration.NewUUID() - if isCreate { - ocmdoc = &api.ClusterManagerConfigurationDocument{ - ID: uuid, - Key: r.URL.Path, - } - ocmdoc.Secret = &api.Secret{ - Name: ocmResourceName, - Type: "Microsoft.RedHatOpenShift/Secret", - ID: originalPath, - Properties: api.SecretProperties{ - SecretResources: api.SecureString(resources), - }, - } - - var newdoc *api.ClusterManagerConfigurationDocument - err = cosmosdb.RetryOnPreconditionFailed(func() error { - newdoc, err = f.dbClusterManagerConfiguration.Create(ctx, ocmdoc) - return err - }) - ocmdoc = newdoc - } else { - if ocmdoc.Deleting { - return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeRequestNotAllowed, "", "Request is not allowed on a resource marked for deletion.") - } - ocmdoc.Secret.Properties.SecretResources = api.SecureString(resources) - } - - ocmdoc.CorrelationData = correlationData - f.systemDataSecretEnricher(ocmdoc, systemData) - - ocmdoc, err = f.dbClusterManagerConfiguration.Update(ctx, ocmdoc) - if err != nil { - return nil, err - } - - ext := converter.ToExternal(ocmdoc.Secret) - b, err := json.MarshalIndent(ext, "", " ") - return b, err -} - -func (f *frontend) extractOriginalPath(ctx context.Context, r *http.Request, resType, resName, resGroupName string) (string, error) { - _, err := f.validateSubscriptionState(ctx, r.URL.Path, api.SubscriptionStateRegistered) - if err != nil { - return "", err - } - - originalPath := r.Context().Value(middleware.ContextKeyOriginalPath).(string) - armResource, err := arm.ParseArmResourceId(originalPath) - if err != nil { - return "", err - } - - ocp, err := f.dbOpenShiftClusters.Get(ctx, armResource.ParentResource()) - if err != nil && !cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) { - return "", err - } - - if ocp == nil || cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) { - return "", api.NewCloudError(http.StatusNotFound, api.CloudErrorCodeResourceNotFound, "", "The Resource '%s/%s' under resource group '%s' was not found.", resType, resName, resGroupName) - } - - return originalPath, err -} - -// TODO once we hit go1.18 we can refactor to use generics for any document using systemData -// enrichClusterManagerSystemData will selectively overwrite systemData fields based on -// arm inputs -func enrichSyncSetSystemData(doc *api.ClusterManagerConfigurationDocument, systemData *api.SystemData) { - if systemData == nil { - return - } - if doc.SyncSet.SystemData == nil { - doc.SyncSet.SystemData = &api.SystemData{} - } - if systemData.CreatedAt != nil { - doc.SyncSet.SystemData.CreatedAt = systemData.CreatedAt - } - if systemData.CreatedBy != "" { - doc.SyncSet.SystemData.CreatedBy = systemData.CreatedBy - } - if systemData.CreatedByType != "" { - doc.SyncSet.SystemData.CreatedByType = systemData.CreatedByType - } - if systemData.LastModifiedAt != nil { - doc.SyncSet.SystemData.LastModifiedAt = systemData.LastModifiedAt - } - if systemData.LastModifiedBy != "" { - doc.SyncSet.SystemData.LastModifiedBy = systemData.LastModifiedBy - } - if systemData.LastModifiedByType != "" { - doc.SyncSet.SystemData.LastModifiedByType = systemData.LastModifiedByType - } -} - -func enrichMachinePoolSystemData(doc *api.ClusterManagerConfigurationDocument, systemData *api.SystemData) { - if systemData == nil { - return - } - if doc.MachinePool.SystemData == nil { - doc.MachinePool.SystemData = &api.SystemData{} - } - if systemData.CreatedAt != nil { - doc.MachinePool.SystemData.CreatedAt = systemData.CreatedAt - } - if systemData.CreatedBy != "" { - doc.MachinePool.SystemData.CreatedBy = systemData.CreatedBy - } - if systemData.CreatedByType != "" { - doc.MachinePool.SystemData.CreatedByType = systemData.CreatedByType - } - if systemData.LastModifiedAt != nil { - doc.MachinePool.SystemData.LastModifiedAt = systemData.LastModifiedAt - } - if systemData.LastModifiedBy != "" { - doc.MachinePool.SystemData.LastModifiedBy = systemData.LastModifiedBy - } - if systemData.LastModifiedByType != "" { - doc.MachinePool.SystemData.LastModifiedByType = systemData.LastModifiedByType - } -} - -func enrichSyncIdentityProviderSystemData(doc *api.ClusterManagerConfigurationDocument, systemData *api.SystemData) { - if systemData == nil { - return - } - if doc.SyncIdentityProvider.SystemData == nil { - doc.SyncIdentityProvider.SystemData = &api.SystemData{} - } - if systemData.CreatedAt != nil { - doc.SyncIdentityProvider.SystemData.CreatedAt = systemData.CreatedAt - } - if systemData.CreatedBy != "" { - doc.SyncIdentityProvider.SystemData.CreatedBy = systemData.CreatedBy - } - if systemData.CreatedByType != "" { - doc.SyncIdentityProvider.SystemData.CreatedByType = systemData.CreatedByType - } - if systemData.LastModifiedAt != nil { - doc.SyncIdentityProvider.SystemData.LastModifiedAt = systemData.LastModifiedAt - } - if systemData.LastModifiedBy != "" { - doc.SyncIdentityProvider.SystemData.LastModifiedBy = systemData.LastModifiedBy - } - if systemData.LastModifiedByType != "" { - doc.SyncIdentityProvider.SystemData.LastModifiedByType = systemData.LastModifiedByType - } -} - -func enrichSecretSystemData(doc *api.ClusterManagerConfigurationDocument, systemData *api.SystemData) { - if systemData == nil { - return - } - if doc.Secret.SystemData == nil { - doc.Secret.SystemData = &api.SystemData{} - } - if systemData.CreatedAt != nil { - doc.Secret.SystemData.CreatedAt = systemData.CreatedAt - } - if systemData.CreatedBy != "" { - doc.Secret.SystemData.CreatedBy = systemData.CreatedBy - } - if systemData.CreatedByType != "" { - doc.Secret.SystemData.CreatedByType = systemData.CreatedByType - } - if systemData.LastModifiedAt != nil { - doc.Secret.SystemData.LastModifiedAt = systemData.LastModifiedAt - } - if systemData.LastModifiedBy != "" { - doc.Secret.SystemData.LastModifiedBy = systemData.LastModifiedBy - } - if systemData.LastModifiedByType != "" { - doc.Secret.SystemData.LastModifiedByType = systemData.LastModifiedByType - } -} diff --git a/pkg/frontend/clustermanager_putorpatch_test.go b/pkg/frontend/clustermanager_putorpatch_test.go deleted file mode 100644 index 29d661f17c6..00000000000 --- a/pkg/frontend/clustermanager_putorpatch_test.go +++ /dev/null @@ -1,308 +0,0 @@ -package frontend - -import ( - "context" - "fmt" - "net/http" - "strings" - "testing" - "time" - - "github.com/Azure/ARO-RP/pkg/api" - v20220904 "github.com/Azure/ARO-RP/pkg/api/v20220904" - "github.com/Azure/ARO-RP/pkg/env" - "github.com/Azure/ARO-RP/pkg/metrics/noop" - testdatabase "github.com/Azure/ARO-RP/test/database" -) - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -func TestPutOrPatchClusterManagerConfiguration(t *testing.T) { - ctx := context.Background() - - mockSubscriptionId := "00000000-0000-0000-0000-000000000000" - tenantId := "11111111-1111-1111-1111-111111111111" - resourcePayload := "eyAKICAiYXBpVmVyc2lvbiI6ICJoaXZlLm9wZW5zaGlmdC5pby92MSIsCiAgImtpbmQiOiAiU3luY1NldCIsCiAgIm1ldGFkYXRhIjogewogICAgIm5hbWUiOiAic2FtcGxlIiwKICAgICJuYW1lc3BhY2UiOiAiYXJvLWY2MGFlOGEyLWJjYTEtNDk4Ny05MDU2LWYyZjZhMTgzN2NhYSIKICB9LAogICJzcGVjIjogewogICAgImNsdXN0ZXJEZXBsb3ltZW50UmVmcyI6IFtdLAogICAgInJlc291cmNlcyI6IFsKICAgICAgewogICAgICAgICJhcGlWZXJzaW9uIjogInYxIiwKICAgICAgICAia2luZCI6ICJDb25maWdNYXAiLAogICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgICJuYW1lIjogIm15Y29uZmlnbWFwIgogICAgICAgIH0KICAgICAgfQogICAgXQogIH0KfQo=" - modifiedPayload := "eyAKICAiYXBpVmVyc2lvbiI6ICJoaXZlLm9wZW5zaGlmdC5pby92MSIsCiAgImtpbmQiOiAiU3luY1NldCIsCiAgIm1ldGFkYXRhIjogewogICAgIm5hbWUiOiAibW9kaWZpZWQtc2FtcGxlIiwKICAgICJuYW1lc3BhY2UiOiAiYXJvLWY2MGFlOGEyLWJjYTEtNDk4Ny05MDU2LWYyZjZhMTgzN2NhYSIKICB9LAogICJzcGVjIjogewogICAgImNsdXN0ZXJEZXBsb3ltZW50UmVmcyI6IFtdLAogICAgInJlc291cmNlcyI6IFsKICAgICAgewogICAgICAgICJhcGlWZXJzaW9uIjogInYxIiwKICAgICAgICAia2luZCI6ICJDb25maWdNYXAiLAogICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgICJuYW1lIjogIm15Y29uZmlnbWFwIgogICAgICAgIH0KICAgICAgfQogICAgXQogIH0KfQo=" - - type test struct { - name string - ocmResourceType string - ocmResourceName string - clusterName string - apiVersion string - fixture func(*testdatabase.Fixture, *test, string) - requestMethod string - requestBody string - wantStatusCode int - wantResponse *v20220904.SyncSet - wantError string - } - createSingleDocument := func(f *testdatabase.Fixture, tt *test, resourceKey string) { - f.AddSubscriptionDocuments(&api.SubscriptionDocument{ - ID: mockSubscriptionId, - Subscription: &api.Subscription{ - State: api.SubscriptionStateRegistered, - Properties: &api.SubscriptionProperties{ - TenantID: tenantId, - }, - }, - }) - f.AddOpenShiftClusterDocuments(&api.OpenShiftClusterDocument{ - Key: strings.ToLower(testdatabase.GetResourcePath(mockSubscriptionId, "resourceName")), - OpenShiftCluster: &api.OpenShiftCluster{ - ID: testdatabase.GetResourcePath(mockSubscriptionId, "resourceName"), - Properties: api.OpenShiftClusterProperties{ - ClusterProfile: api.ClusterProfile{ - ResourceGroupID: fmt.Sprintf("/subscriptions/%s/resourcegroups/%s", mockSubscriptionId, "rg01"), - }, - }, - }, - }) - f.AddClusterManagerConfigurationDocuments( - &api.ClusterManagerConfigurationDocument{ - ID: mockSubscriptionId, - Key: resourceKey, - SyncSet: &api.SyncSet{ - Name: tt.ocmResourceName, - Properties: api.SyncSetProperties{ - Resources: resourcePayload, - }, - }, - }, - ) - } - noDocuments := func(f *testdatabase.Fixture, tt *test, resourceKey string) { - f.AddSubscriptionDocuments(&api.SubscriptionDocument{ - ID: mockSubscriptionId, - Subscription: &api.Subscription{ - State: api.SubscriptionStateRegistered, - Properties: &api.SubscriptionProperties{ - TenantID: tenantId, - }, - }, - }) - f.AddOpenShiftClusterDocuments(&api.OpenShiftClusterDocument{ - Key: strings.ToLower(testdatabase.GetResourcePath(mockSubscriptionId, "resourceName")), - OpenShiftCluster: &api.OpenShiftCluster{ - ID: testdatabase.GetResourcePath(mockSubscriptionId, "resourceName"), - Properties: api.OpenShiftClusterProperties{ - ClusterProfile: api.ClusterProfile{ - ResourceGroupID: fmt.Sprintf("/subscriptions/%s/resourcegroups/%s", mockSubscriptionId, tt.clusterName), - }, - }, - }, - }) - } - - for _, tt := range []*test{ - { - name: "single syncset - put", - ocmResourceType: "syncSet", - ocmResourceName: "putSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: createSingleDocument, - requestMethod: http.MethodPut, - requestBody: modifiedPayload, - wantStatusCode: http.StatusOK, - wantResponse: &v20220904.SyncSet{ - Name: "putSyncSet", - Properties: v20220904.SyncSetProperties{ - Resources: modifiedPayload, - }, - }, - }, - { - name: "single syncset - patch", - ocmResourceType: "syncSet", - ocmResourceName: "patchSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: createSingleDocument, - requestMethod: http.MethodPatch, - requestBody: modifiedPayload, - wantStatusCode: http.StatusOK, - wantResponse: &v20220904.SyncSet{ - Name: "patchSyncSet", - Properties: v20220904.SyncSetProperties{ - Resources: modifiedPayload, - }, - }, - }, - { - name: "single syncset - put create", - ocmResourceType: "syncSet", - ocmResourceName: "putNewSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: noDocuments, - requestMethod: http.MethodPut, - requestBody: modifiedPayload, - wantStatusCode: http.StatusOK, - wantResponse: &v20220904.SyncSet{ - Name: "putnewsyncset", - Type: "Microsoft.RedHatOpenShift/SyncSet", - ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/resourcegroup/providers/microsoft.redhatopenshift/openshiftclusters/resourcename/syncSet/putNewSyncSet", - Properties: v20220904.SyncSetProperties{ - Resources: modifiedPayload, - }, - }, - }, - { - name: "patching nonexistent syncset", - ocmResourceType: "syncSet", - ocmResourceName: "patchNewSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: noDocuments, - requestMethod: http.MethodPatch, - requestBody: modifiedPayload, - wantStatusCode: http.StatusNotFound, - wantError: "404: ResourceNotFound: : The Resource 'openshiftclusters/resourcename/syncset/patchnewsyncset' under resource group 'resourcegroup' was not found.", - }, - { - name: "unsupported api version", - ocmResourceType: "syncset", - ocmResourceName: "patchSyncSet", - clusterName: "myCluster", - apiVersion: "2022-04-01", - fixture: createSingleDocument, - requestMethod: http.MethodPatch, - requestBody: modifiedPayload, - wantStatusCode: http.StatusBadRequest, - wantError: "400: InvalidResourceType: : the resource type 'syncset' is not valid for api version '2022-04-01'", - }, - { - name: "unsupported resource type", - ocmResourceType: "unsupported", - ocmResourceName: "patchSyncSet", - clusterName: "myCluster", - apiVersion: "2022-09-04", - fixture: createSingleDocument, - requestMethod: http.MethodPatch, - requestBody: modifiedPayload, - wantStatusCode: http.StatusBadRequest, - wantError: "400: InvalidResourceType: : the resource type 'unsupported' is not valid for api version '2022-09-04'", - }, - } { - t.Run(tt.name, func(t *testing.T) { - ti := newTestInfraWithFeatures(t, map[env.Feature]bool{env.FeatureRequireD2sV3Workers: false, env.FeatureDisableReadinessDelay: false, env.FeatureEnableOCMEndpoints: true}).WithClusterManagerConfigurations().WithSubscriptions().WithOpenShiftClusters() - defer ti.done() - - resourceKey := fmt.Sprintf("/subscriptions/%s/resourcegroups/resourcegroup/providers/microsoft.redhatopenshift/openshiftclusters/resourcename/%s/%s", - mockSubscriptionId, - tt.ocmResourceType, - tt.ocmResourceName) - - err := ti.buildFixtures(func(f *testdatabase.Fixture) { tt.fixture(f, tt, resourceKey) }) - if err != nil { - t.Fatal(err) - } - - f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil, nil) - if err != nil { - t.Fatal(err) - } - - go f.Run(ctx, nil, nil) - - resp, b, err := ti.request(tt.requestMethod, - fmt.Sprintf("https://server%s?api-version=%s", - resourceKey, - tt.apiVersion, - ), - http.Header{ - "Content-Type": []string{"application/json"}, - }, tt.requestBody) - if err != nil { - t.Fatalf("%s: %s", err, string(b)) - } - - err = validateResponse(resp, b, tt.wantStatusCode, tt.wantError, tt.wantResponse) - if err != nil { - t.Errorf("%s: %s", err, string(b)) - } - }) - } -} - -var populatedSystemData = api.SystemData{ - LastModifiedAt: &time.Time{}, - LastModifiedBy: "test-user", - LastModifiedByType: api.CreatedByTypeUser, - CreatedAt: &time.Time{}, - CreatedBy: "test-user", - CreatedByType: api.CreatedByTypeUser, -} - -func TestEnrichSyncSetSystemData(t *testing.T) { - doc := api.ClusterManagerConfigurationDocument{ - SyncSet: &api.SyncSet{}, - } - - enrichSyncSetSystemData(&doc, &populatedSystemData) - - if err := compareSystemData(*doc.SyncSet.SystemData, populatedSystemData); err != nil { - t.Fatal(err) - } -} - -func TestEnrichSyncIdentityProviderSystemData(t *testing.T) { - doc := api.ClusterManagerConfigurationDocument{ - SyncIdentityProvider: &api.SyncIdentityProvider{}, - } - - enrichSyncIdentityProviderSystemData(&doc, &populatedSystemData) - - if err := compareSystemData(*doc.SyncIdentityProvider.SystemData, populatedSystemData); err != nil { - t.Fatal(err) - } -} - -func TestEnrichMachinePoolSystemData(t *testing.T) { - doc := api.ClusterManagerConfigurationDocument{ - MachinePool: &api.MachinePool{}, - } - - enrichMachinePoolSystemData(&doc, &populatedSystemData) - - if err := compareSystemData(*doc.MachinePool.SystemData, populatedSystemData); err != nil { - t.Fatal(err) - } -} - -func TestEnrichSecretSystemData(t *testing.T) { - doc := api.ClusterManagerConfigurationDocument{ - Secret: &api.Secret{}, - } - - enrichSecretSystemData(&doc, &populatedSystemData) - - if err := compareSystemData(*doc.Secret.SystemData, populatedSystemData); err != nil { - t.Fatal(err) - } -} - -func compareSystemData(docSystemData, expectedSystemData api.SystemData) error { - if docSystemData.CreatedAt == nil || docSystemData.CreatedAt != expectedSystemData.CreatedAt { - return fmt.Errorf("CreatedAt was %q expected %q", docSystemData.CreatedAt, expectedSystemData.CreatedAt) - } - if docSystemData.CreatedBy == "" || docSystemData.CreatedBy != expectedSystemData.CreatedBy { - return fmt.Errorf("CreatedBy was %q expected %q", docSystemData.CreatedBy, expectedSystemData.CreatedBy) - } - if docSystemData.CreatedByType == "" || docSystemData.CreatedByType != expectedSystemData.CreatedByType { - return fmt.Errorf("CreatedByType was %q expected %q", docSystemData.CreatedByType, expectedSystemData.CreatedByType) - } - if docSystemData.LastModifiedAt == nil || docSystemData.LastModifiedAt != expectedSystemData.LastModifiedAt { - return fmt.Errorf("LastModifiedAt was %q expected %q", docSystemData.LastModifiedAt, expectedSystemData.LastModifiedAt) - } - if docSystemData.LastModifiedBy == "" || docSystemData.LastModifiedBy != expectedSystemData.LastModifiedBy { - return fmt.Errorf("LastModifiedBy was %q expected %q", docSystemData.LastModifiedBy, expectedSystemData.LastModifiedBy) - } - if docSystemData.LastModifiedByType == "" || docSystemData.LastModifiedByType != expectedSystemData.LastModifiedByType { - return fmt.Errorf("LastModifiedByType was %q expected %q", docSystemData.LastModifiedByType, expectedSystemData.LastModifiedByType) - } - return nil -} diff --git a/pkg/frontend/clustermanager_type.go b/pkg/frontend/clustermanager_type.go deleted file mode 100644 index 70538f1f4ae..00000000000 --- a/pkg/frontend/clustermanager_type.go +++ /dev/null @@ -1,35 +0,0 @@ -package frontend - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -import ( - "fmt" -) - -func (f *frontend) validateOcmResourceType(apiVersion, ocmResourceType string) error { - badRequestError := fmt.Errorf("the resource type '%s' is not valid for api version '%s'", ocmResourceType, apiVersion) - - switch ocmResourceType { - case "syncset": - if f.apis[apiVersion].SyncSetConverter == nil { - return badRequestError - } - case "machinepool": - if f.apis[apiVersion].MachinePoolConverter == nil { - return badRequestError - } - case "syncidentityprovider": - if f.apis[apiVersion].SyncIdentityProviderConverter == nil { - return badRequestError - } - case "secret": - if f.apis[apiVersion].SecretConverter == nil { - return badRequestError - } - default: - return badRequestError - } - - return nil -} diff --git a/pkg/frontend/clustermanager_type_test.go b/pkg/frontend/clustermanager_type_test.go deleted file mode 100644 index f8d6ba76f9a..00000000000 --- a/pkg/frontend/clustermanager_type_test.go +++ /dev/null @@ -1,158 +0,0 @@ -package frontend - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -import ( - "testing" - - "github.com/golang/mock/gomock" - - "github.com/Azure/ARO-RP/pkg/api" - mock_api "github.com/Azure/ARO-RP/pkg/util/mocks/api" -) - -func TestValidateOcmResourceType(t *testing.T) { - controller := gomock.NewController(t) - defer controller.Finish() - - for _, tt := range []struct { - name string - vars map[string]string - ocmResourceType string - syncSetConverter api.SyncSetConverter - machinePoolConverter api.MachinePoolConverter - syncIdentityProviderConverter api.SyncIdentityProviderConverter - secretConverter api.SecretConverter - err string - }{ - { - name: "syncset - resource type is valid", - ocmResourceType: "syncset", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - syncSetConverter: mock_api.NewMockSyncSetConverter(controller), - err: "", - }, - { - name: "syncset - resource type is invalid", - ocmResourceType: "invalid", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - syncSetConverter: mock_api.NewMockSyncSetConverter(controller), - err: "the resource type 'invalid' is not valid for api version '2022-09-04'", - }, - { - name: "syncset - converter is nil", - ocmResourceType: "syncset", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - syncSetConverter: nil, - err: "the resource type 'syncset' is not valid for api version '2022-09-04'", - }, - { - name: "machinepool - resource type is valid", - ocmResourceType: "machinepool", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - machinePoolConverter: mock_api.NewMockMachinePoolConverter(controller), - err: "", - }, - { - name: "machinepool - resource type is invalid", - ocmResourceType: "invalid", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - machinePoolConverter: mock_api.NewMockMachinePoolConverter(controller), - err: "the resource type 'invalid' is not valid for api version '2022-09-04'", - }, - { - name: "machinepool - converter is nil", - ocmResourceType: "machinepool", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - machinePoolConverter: nil, - err: "the resource type 'machinepool' is not valid for api version '2022-09-04'", - }, - { - name: "syncidentityprovider - resource type is valid", - ocmResourceType: "syncidentityprovider", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - syncIdentityProviderConverter: mock_api.NewMockSyncIdentityProviderConverter(controller), - err: "", - }, - { - name: "syncidentityprovider - resource type is invalid", - ocmResourceType: "invalid", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - syncIdentityProviderConverter: mock_api.NewMockSyncIdentityProviderConverter(controller), - err: "the resource type 'invalid' is not valid for api version '2022-09-04'", - }, - { - name: "syncidentityprovider - converter is nil", - ocmResourceType: "syncidentityprovider", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - syncIdentityProviderConverter: nil, - err: "the resource type 'syncidentityprovider' is not valid for api version '2022-09-04'", - }, - { - name: "secret - resource type is valid", - ocmResourceType: "secret", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - secretConverter: mock_api.NewMockSecretConverter(controller), - err: "", - }, - { - name: "secret - resource type is invalid", - ocmResourceType: "invalid", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - secretConverter: mock_api.NewMockSecretConverter(controller), - err: "the resource type 'invalid' is not valid for api version '2022-09-04'", - }, - { - name: "secret - converter is nil", - ocmResourceType: "secret", - vars: map[string]string{ - "resourceProviderNamespace": "microsoft.redhatopenshift", - }, - secretConverter: nil, - err: "the resource type 'secret' is not valid for api version '2022-09-04'", - }, - } { - t.Run(tt.name, func(t *testing.T) { - f := &frontend{ - apis: map[string]*api.Version{ - "2022-09-04": { - SyncSetConverter: tt.syncSetConverter, - MachinePoolConverter: tt.machinePoolConverter, - SyncIdentityProviderConverter: tt.syncIdentityProviderConverter, - SecretConverter: tt.secretConverter, - }, - }, - } - - err := f.validateOcmResourceType("2022-09-04", tt.ocmResourceType) - if err != nil { - if err.Error() != tt.err { - t.Errorf("wanted '%v', got '%v'", tt.err, err) - } - } - }) - } -} diff --git a/pkg/frontend/frontend.go b/pkg/frontend/frontend.go index b127c381631..2c34dd77373 100644 --- a/pkg/frontend/frontend.go +++ b/pkg/frontend/frontend.go @@ -100,11 +100,6 @@ type frontend struct { now func() time.Time systemDataClusterDocEnricher func(*api.OpenShiftClusterDocument, *api.SystemData) - systemDataSyncSetEnricher func(*api.ClusterManagerConfigurationDocument, *api.SystemData) - systemDataMachinePoolEnricher func(*api.ClusterManagerConfigurationDocument, *api.SystemData) - systemDataSyncIdentityProviderEnricher func(*api.ClusterManagerConfigurationDocument, *api.SystemData) - systemDataSecretEnricher func(*api.ClusterManagerConfigurationDocument, *api.SystemData) - streamResponder StreamResponder } @@ -188,11 +183,6 @@ func NewFrontend(ctx context.Context, now: time.Now, systemDataClusterDocEnricher: enrichClusterSystemData, - systemDataSyncSetEnricher: enrichSyncSetSystemData, - systemDataMachinePoolEnricher: enrichMachinePoolSystemData, - systemDataSyncIdentityProviderEnricher: enrichSyncIdentityProviderSystemData, - systemDataSecretEnricher: enrichSecretSystemData, - streamResponder: defaultResponder{}, } @@ -245,18 +235,6 @@ func (f *frontend) chiAuthenticatedRoutes(router chi.Router) { r.Route("/{resourceName}", func(r chi.Router) { r.With(f.apiVersionMiddleware.ValidateAPIVersion).Route("/", func(r chi.Router) { - // With API version check - if f.env.FeatureIsSet(env.FeatureEnableOCMEndpoints) { - r.Route("/{ocmResourceType}", - func(r chi.Router) { - r.Delete("/{ocmResourceName}", f.deleteClusterManagerConfiguration) - r.Get("/{ocmResourceName}", f.getClusterManagerConfiguration) - r.Patch("/{ocmResourceName}", f.putOrPatchClusterManagerConfiguration) - r.Put("/{ocmResourceName}", f.putOrPatchClusterManagerConfiguration) - }, - ) - } - r.Delete("/", f.deleteOpenShiftCluster) r.Get("/", f.getOpenShiftCluster) r.Patch("/", f.putOrPatchOpenShiftCluster)