ARO-RP/pkg/frontend/openshiftcluster_putorpatch.go

205 строки
6.2 KiB
Go
Исходник Обычный вид История

2019-10-16 06:29:17 +03:00
package frontend
2019-12-17 04:16:50 +03:00
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
2019-10-16 06:29:17 +03:00
import (
2020-01-06 18:26:31 +03:00
"context"
2019-10-16 06:29:17 +03:00
"encoding/json"
2019-11-28 19:31:37 +03:00
"fmt"
2019-10-16 06:29:17 +03:00
"net/http"
"net/url"
2020-01-10 20:42:48 +03:00
"strings"
2019-10-16 06:29:17 +03:00
"github.com/Azure/go-autorest/autorest/azure"
2019-10-16 06:29:17 +03:00
"github.com/gorilla/mux"
uuid "github.com/satori/go.uuid"
"github.com/sirupsen/logrus"
2019-12-17 04:26:21 +03:00
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/api/admin"
2019-12-17 04:26:21 +03:00
"github.com/Azure/ARO-RP/pkg/database/cosmosdb"
"github.com/Azure/ARO-RP/pkg/frontend/middleware"
2020-02-24 17:52:11 +03:00
"github.com/Azure/ARO-RP/pkg/util/version"
2019-10-16 06:29:17 +03:00
)
func (f *frontend) putOrPatchOpenShiftCluster(w http.ResponseWriter, r *http.Request) {
2020-01-06 18:26:31 +03:00
ctx := r.Context()
log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry)
2019-10-16 06:29:17 +03:00
vars := mux.Vars(r)
var header http.Header
2019-10-16 06:29:17 +03:00
var b []byte
err := cosmosdb.RetryOnPreconditionFailed(func() error {
var err error
b, err = f._putOrPatchOpenShiftCluster(ctx, r, &header, f.apis[vars["api-version"]].OpenShiftClusterConverter(), f.apis[vars["api-version"]].OpenShiftClusterStaticValidator(f.env.Location(), r.URL.Path))
2019-10-16 06:29:17 +03:00
return err
})
2019-12-03 00:57:05 +03:00
reply(log, w, header, b, err)
2019-10-16 06:29:17 +03:00
}
func (f *frontend) _putOrPatchOpenShiftCluster(ctx context.Context, r *http.Request, header *http.Header, converter api.OpenShiftClusterConverter, staticValidator api.OpenShiftClusterStaticValidator) ([]byte, error) {
body := r.Context().Value(middleware.ContextKeyBody).([]byte)
2019-12-03 00:57:05 +03:00
2020-01-06 18:26:31 +03:00
subdoc, err := f.validateSubscriptionState(ctx, r.URL.Path, api.SubscriptionStateRegistered)
2019-11-29 03:24:09 +03:00
if err != nil {
return nil, err
2019-11-29 03:24:09 +03:00
}
2020-01-06 18:26:31 +03:00
doc, err := f.db.OpenShiftClusters.Get(ctx, r.URL.Path)
if err != nil && !cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) {
return nil, err
2019-10-16 06:29:17 +03:00
}
isCreate := doc == nil
if isCreate {
originalPath := r.Context().Value(middleware.ContextKeyOriginalPath).(string)
originalR, err := azure.ParseResourceID(originalPath)
2019-10-16 06:29:17 +03:00
if err != nil {
return nil, err
2019-10-16 06:29:17 +03:00
}
doc = &api.OpenShiftClusterDocument{
ID: uuid.NewV4().String(),
2019-12-22 03:59:54 +03:00
Key: r.URL.Path,
OpenShiftCluster: &api.OpenShiftCluster{
ID: originalPath,
Name: originalR.ResourceName,
2019-12-05 16:30:51 +03:00
Type: originalR.Provider + "/" + originalR.ResourceType,
2019-10-16 06:29:17 +03:00
Properties: api.Properties{
ProvisioningState: api.ProvisioningStateSucceeded,
2020-02-24 17:52:11 +03:00
ClusterProfile: api.ClusterProfile{
Version: version.OpenShiftVersion,
},
ServicePrincipalProfile: api.ServicePrincipalProfile{
TenantID: subdoc.Subscription.Properties.TenantID,
},
2019-10-16 06:29:17 +03:00
},
},
}
}
2019-10-16 06:29:17 +03:00
err = validateTerminalProvisioningState(doc.OpenShiftCluster.Properties.ProvisioningState)
if err != nil {
return nil, err
}
if doc.OpenShiftCluster.Properties.ProvisioningState == api.ProvisioningStateFailed {
switch doc.OpenShiftCluster.Properties.FailedProvisioningState {
case api.ProvisioningStateCreating:
return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeRequestNotAllowed, "", "Request is not allowed on cluster whose creation failed. Delete the cluster.")
case api.ProvisioningStateUpdating:
doc.OpenShiftCluster.Properties.FailedProvisioningState = "" // allow
case api.ProvisioningStateDeleting:
return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeRequestNotAllowed, "", "Request is not allowed on cluster whose deletion failed. Delete the cluster.")
default:
return nil, fmt.Errorf("unexpected failedProvisioningState %q", doc.OpenShiftCluster.Properties.FailedProvisioningState)
2019-10-16 06:29:17 +03:00
}
}
var ext interface{}
switch r.Method {
case http.MethodPut:
ext = converter.ToExternal(&api.OpenShiftCluster{
ID: doc.OpenShiftCluster.ID,
Name: doc.OpenShiftCluster.Name,
Type: doc.OpenShiftCluster.Type,
Properties: api.Properties{
ProvisioningState: doc.OpenShiftCluster.Properties.ProvisioningState,
2020-02-24 17:52:11 +03:00
ClusterProfile: api.ClusterProfile{
Version: doc.OpenShiftCluster.Properties.ClusterProfile.Version,
},
},
})
case http.MethodPatch:
ext = converter.ToExternal(doc.OpenShiftCluster)
}
2019-12-03 00:57:05 +03:00
err = json.Unmarshal(body, &ext)
2019-10-16 06:29:17 +03:00
if err != nil {
return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content was invalid and could not be deserialized: %q.", err)
2019-10-16 06:29:17 +03:00
}
if isCreate {
err = staticValidator.Static(ext, nil)
} else {
err = staticValidator.Static(ext, doc.OpenShiftCluster)
}
2019-10-16 06:29:17 +03:00
if err != nil {
return nil, err
2019-10-16 06:29:17 +03:00
}
oldID, oldName, oldType := doc.OpenShiftCluster.ID, doc.OpenShiftCluster.Name, doc.OpenShiftCluster.Type
converter.ToInternal(ext, doc.OpenShiftCluster)
doc.OpenShiftCluster.ID, doc.OpenShiftCluster.Name, doc.OpenShiftCluster.Type = oldID, oldName, oldType
2019-12-03 06:14:00 +03:00
if isCreate {
2020-01-10 20:42:48 +03:00
doc.ClusterResourceGroupIDKey = strings.ToLower(doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID)
doc.ClientIDKey = strings.ToLower(doc.OpenShiftCluster.Properties.ServicePrincipalProfile.ClientID)
2019-12-03 06:14:00 +03:00
doc.OpenShiftCluster.Properties.ProvisioningState = api.ProvisioningStateCreating
2020-01-18 19:33:08 +03:00
doc.Bucket, err = f.bucketAllocator.Allocate()
if err != nil {
return nil, err
}
2019-12-03 06:14:00 +03:00
} else {
2020-01-24 14:19:56 +03:00
// TODO: Get rid of the special case
vars := mux.Vars(r)
if vars["api-version"] == admin.APIVersion {
2020-01-24 14:19:56 +03:00
doc.OpenShiftCluster.Properties.ProvisioningState = api.ProvisioningStateAdminUpdating
} else {
doc.OpenShiftCluster.Properties.ProvisioningState = api.ProvisioningStateUpdating
}
2019-12-03 06:14:00 +03:00
doc.Dequeues = 0
}
err = f.ocDynamicValidator.Dynamic(r.Context(), doc.OpenShiftCluster)
if err != nil {
return nil, err
}
2020-01-06 18:26:31 +03:00
doc.AsyncOperationID, err = f.newAsyncOperation(ctx, r, doc)
if err != nil {
return nil, err
}
u, err := url.Parse(r.Header.Get("Referer"))
if err != nil {
return nil, err
}
u.Path = f.operationsPath(r, doc.AsyncOperationID)
*header = http.Header{
"Azure-AsyncOperation": []string{u.String()},
}
if isCreate {
2020-01-10 20:42:48 +03:00
newdoc, err := f.db.OpenShiftClusters.Create(ctx, doc)
if cosmosdb.IsErrorStatusCode(err, http.StatusPreconditionFailed) {
return nil, f.validateOpenShiftUniqueKey(ctx, doc)
2020-01-10 20:42:48 +03:00
}
doc = newdoc
} else {
2020-01-06 18:26:31 +03:00
doc, err = f.db.OpenShiftClusters.Update(ctx, doc)
2019-10-16 06:29:17 +03:00
}
if err != nil {
return nil, err
2019-10-16 06:29:17 +03:00
}
2019-11-18 06:07:44 +03:00
doc.OpenShiftCluster.Properties.ServicePrincipalProfile.ClientSecret = ""
2019-10-16 06:29:17 +03:00
b, err := json.MarshalIndent(converter.ToExternal(doc.OpenShiftCluster), "", " ")
2019-11-12 19:34:18 +03:00
if err != nil {
return nil, err
2019-11-12 19:34:18 +03:00
}
if isCreate {
err = statusCodeError(http.StatusCreated)
}
return b, err
2019-10-16 06:29:17 +03:00
}