Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Preflight Update Checks #3365

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions pkg/api/preflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,8 @@ type PreflightRequest struct {

// ValidationResult is the validation result to return in the deployment preflight response body
type ValidationResult struct {
Status ValidationStatus `json:"status"`
Error *ManagementErrorWithDetails `json:"error,omitempty"`
}

type ManagementErrorWithDetails struct {
// Code - The error code returned from the server.
Code *string `json:"code,omitempty"`
// Message - The error message returned from the server.
Message *string `json:"message,omitempty"`
// Target - The target of the error.
Target *string `json:"target,omitempty"`
// Details - Validation error.
Details *[]ManagementErrorWithDetails `json:"details,omitempty"`
Status ValidationStatus `json:"status"`
Error *CloudErrorBody `json:"error,omitempty"`
bennerv marked this conversation as resolved.
Show resolved Hide resolved
}

// ResourceTypeMeta is the Typemeta inside request body of preflight
Expand Down
16 changes: 16 additions & 0 deletions pkg/api/subscriptiondocument_example.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package api

// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.

func ExampleSubscriptionDocument() *SubscriptionDocument {
return &SubscriptionDocument{
ID: "00000000-0000-0000-0000-000000000000",
Subscription: &Subscription{
State: SubscriptionStateRegistered,
Properties: &SubscriptionProperties{
TenantID: "11111111-1111-1111-1111-111111111111",
},
},
}
}
84 changes: 56 additions & 28 deletions pkg/frontend/openshiftcluster_preflightvalidation.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (
"net/http"
mociarain marked this conversation as resolved.
Show resolved Hide resolved
"strings"

"github.com/Azure/go-autorest/autorest/to"
"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/env"
"github.com/Azure/ARO-RP/pkg/frontend/middleware"
)
Expand All @@ -36,8 +36,8 @@ func (f *frontend) preflightValidation(w http.ResponseWriter, r *http.Request) {
if err != nil {
b = marshalValidationResult(api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.ManagementErrorWithDetails{
Message: to.StringPtr(err.Error()),
Error: &api.CloudErrorBody{
Message: err.Error(),
},
})
reply(log, w, header, b, statusCodeError(http.StatusOK))
Expand All @@ -48,13 +48,20 @@ func (f *frontend) preflightValidation(w http.ResponseWriter, r *http.Request) {
typeMeta := api.ResourceTypeMeta{}
if err := json.Unmarshal(raw, &typeMeta); err != nil {
// failing to parse the preflight body is not considered a validation failure. continue
log.Warningf("bad request. Failed to unmarshal ResourceTypeMeta: %s", err)
continue
log.Warningf("preflight validation failed with bad request. Failed to unmarshal ResourceTypeMeta: %s", err)
b = marshalValidationResult(api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.CloudErrorBody{
Message: err.Error(),
},
})
reply(log, w, header, b, statusCodeError(http.StatusOK))
return
}
if strings.EqualFold(typeMeta.Type, "Microsoft.RedHatOpenShift/openShiftClusters") {
res := f._preflightValidation(ctx, log, raw, typeMeta.APIVersion, typeMeta.Id)
res := f._preflightValidation(ctx, log, raw, typeMeta.APIVersion, strings.ToLower(typeMeta.Id))
if res.Status == api.ValidationStatusFailed {
log.Warningf("preflight validation failed")
log.Warningf("preflight validation failed with err: '%s'", res.Error.Message)
b = marshalValidationResult(res)
reply(log, w, header, b, statusCodeError(http.StatusOK))
return
Expand All @@ -68,6 +75,18 @@ func (f *frontend) preflightValidation(w http.ResponseWriter, r *http.Request) {
}

func (f *frontend) _preflightValidation(ctx context.Context, log *logrus.Entry, raw json.RawMessage, apiVersion string, resourceID string) api.ValidationResult {
log.Infof("running preflight validation on resource: %s", resourceID)
doc, err := f.dbOpenShiftClusters.Get(ctx, resourceID)
isCreate := cosmosdb.IsErrorStatusCode(err, http.StatusNotFound)
if err != nil && !isCreate {
log.Warning(err.Error())
return api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.CloudErrorBody{
Message: "400: Cluster not found for resourceID: " + resourceID,
},
}
}
// unmarshal raw to OpenShiftCluster type
oc := &api.OpenShiftCluster{}
oc.Properties.ProvisioningState = api.ProvisioningStateSucceeded
Expand All @@ -79,35 +98,44 @@ func (f *frontend) _preflightValidation(ctx context.Context, log *logrus.Entry,
converter := f.apis[apiVersion].OpenShiftClusterConverter
staticValidator := f.apis[apiVersion].OpenShiftClusterStaticValidator
ext := converter.ToExternal(oc)
if err := json.Unmarshal(raw, &ext); err != nil {
if err = json.Unmarshal(raw, &ext); err != nil {
log.Warning(err.Error())
return api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.ManagementErrorWithDetails{
Message: to.StringPtr(err.Error()),
Error: &api.CloudErrorBody{
Message: api.CloudErrorCodeInternalServerError,
},
}
}

converter.ToInternal(ext, oc)
if err := staticValidator.Static(ext, nil, f.env.Location(), f.env.Domain(), f.env.FeatureIsSet(env.FeatureRequireD2sV3Workers), resourceID); err != nil {
return api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.ManagementErrorWithDetails{
Message: to.StringPtr(err.Error()),
},
if isCreate {
converter.ToInternal(ext, oc)
if err = staticValidator.Static(ext, nil, f.env.Location(), f.env.Domain(), f.env.FeatureIsSet(env.FeatureRequireD2sV3Workers), resourceID); err != nil {
return api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.CloudErrorBody{
Message: err.Error(),
},
}
}
}

if err := f.validateInstallVersion(ctx, oc); err != nil {
return api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.ManagementErrorWithDetails{
Code: to.StringPtr(api.CloudErrorCodeInvalidParameter),
Message: to.StringPtr(err.Error()),
},
if err := f.validateInstallVersion(ctx, oc); err != nil {
return api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.CloudErrorBody{
Code: api.CloudErrorCodeInvalidParameter,
Message: err.Error(),
},
}
}
} else {
if err := staticValidator.Static(ext, doc.OpenShiftCluster, f.env.Location(), f.env.Domain(), f.env.FeatureIsSet(env.FeatureRequireD2sV3Workers), resourceID); err != nil {
return api.ValidationResult{
Status: api.ValidationStatusFailed,
Error: &api.CloudErrorBody{
Message: err.Error(),
},
}
}
}

return validationSuccess
}

Expand Down
Loading
Loading