internal/api/arm/preflight.go (73 lines of code) (raw):

// Copyright 2025 Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package arm import ( "encoding/json" "net/http" "path" ) // See https://learn.microsoft.com/en-us/rest/api/datareplication/deployment-preflight/deployment-preflight?view=rest-datareplication-2021-02-16-preview&tabs=Go // DeploymentPreflight represents the body of a deployment preflight request. // We use a RawMessage slice here because preflight validation is best effort. // So if one resource cannot be unmarshaled we move on to the next instead of // failing the whole operation. type DeploymentPreflight struct { Resources []json.RawMessage `json:"resources"` } // UnmarshalDeploymentPreflight unmarshals JSON-encoded data and returns // either a DeploymentPreflight instance or an appropriate CloudError with // a 200 OK HTTP status code. func UnmarshalDeploymentPreflight(data []byte) (*DeploymentPreflight, *CloudError) { deploymentPreflight := &DeploymentPreflight{} err := json.Unmarshal(data, deploymentPreflight) if err != nil { cloudError := NewInvalidRequestContentError(err) // Status code for preflight content errors must always be OK. cloudError.StatusCode = http.StatusOK return nil, cloudError } return deploymentPreflight, nil } // DeploymentPreflightResource represents a desired resource in a deployment preflight request. type DeploymentPreflightResource struct { Name string `json:"name" validate:"required"` Type string `json:"type" validate:"required"` Location string `json:"location" validate:"required"` APIVersion string `json:"apiVersion,omitempty" validate:"required,api_version"` // Preserve other tracked resource fields as raw data. Properties json.RawMessage `json:"properties,omitempty"` SystemData json.RawMessage `json:"systemData,omitempty"` Tags json.RawMessage `json:"tags,omitempty"` } // Convert discards the APIVersion, marshals itself back to raw JSON, // and then unmarshals the raw JSON to the given value, which should // be an extension of the TrackedResource type. func (r *DeploymentPreflightResource) Convert(v any) error { var clone = *r // Omit APIVersion from the clone. clone.APIVersion = "" data, err := json.Marshal(&clone) if err != nil { return err } return json.Unmarshal(data, v) } // ResourceID returns a resource ID string for the resource. func (r *DeploymentPreflightResource) ResourceID(subscriptionID, resourceGroup string) string { return path.Join("/subscriptions", subscriptionID, "resourcegroups", resourceGroup, "providers", r.Type, r.Name) } // DeploymentPreflightStatus is used in a DeploymentPreflightResponse. type DeploymentPreflightStatus string const ( DeploymentPreflightStatusSucceeded DeploymentPreflightStatus = "Succeeded" DeploymentPreflightStatusFailed DeploymentPreflightStatus = "Failed" ) // DeploymentPreflightResponse represents the JSON response structure // for a deployment preflight request. type DeploymentPreflightResponse struct { Status DeploymentPreflightStatus `json:"status"` Error *CloudErrorBody `json:"error,omitempty"` } // WriteDeploymentPreflightResponse writes an appropriately structured // response body to a deployment preflight request using the given error // slice. An empty error slice indicates successful validation. func WriteDeploymentPreflightResponse(w http.ResponseWriter, preflightErrors []CloudErrorBody) { var response *DeploymentPreflightResponse switch len(preflightErrors) { case 0: response = &DeploymentPreflightResponse{ Status: DeploymentPreflightStatusSucceeded, } case 1: response = &DeploymentPreflightResponse{ Status: DeploymentPreflightStatusFailed, Error: &preflightErrors[0], } default: response = &DeploymentPreflightResponse{ Status: DeploymentPreflightStatusFailed, Error: &CloudErrorBody{ Code: CloudErrorCodeMultipleErrorsOccurred, Message: "Preflight validation failed on multiple resources", Details: preflightErrors, }, } } _, _ = WriteJSONResponse(w, http.StatusOK, response) }