func MiddlewareValidateSubscriptionState()

in frontend/pkg/frontend/middleware_validatesubscription.go [35:114]


func MiddlewareValidateSubscriptionState(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	ctx := r.Context()
	logger := LoggerFromContext(ctx)

	dbClient, err := DBClientFromContext(ctx)
	if err != nil {
		logger.Error(err.Error())
		arm.WriteInternalServerError(w)
		return
	}

	subscriptionId := r.PathValue(PathSegmentSubscriptionID)
	if subscriptionId == "" {
		arm.WriteError(
			w, http.StatusBadRequest,
			arm.CloudErrorCodeInvalidParameter, "",
			SubscriptionMissingMessage,
			PathSegmentSubscriptionID)
		return
	}

	// TODO: Ideally, we don't want to have to hit the database in this middleware
	// Currently, we are using the database to retrieve the subscription's tenantID and state
	subscription, err := dbClient.GetSubscriptionDoc(ctx, subscriptionId)
	if err != nil {
		arm.WriteError(
			w, http.StatusBadRequest,
			arm.CloudErrorCodeInvalidSubscriptionState, "",
			UnregisteredSubscriptionStateMessage,
			subscriptionId)
		return
	}

	// For subscription-scoped requests, ARM will provide the tenant ID
	// in a "x-ms-home-tenant-id" header. But in test environments this
	// header may not be present, in which case we can try to fudge it
	// from the SubscriptionDocument.
	if r.Header.Get(arm.HeaderNameHomeTenantID) == "" {
		if subscription.Properties != nil &&
			subscription.Properties.TenantId != nil {
			r.Header.Set(
				arm.HeaderNameHomeTenantID,
				*subscription.Properties.TenantId)
		}
	}

	span := trace.SpanFromContext(ctx)
	span.SetAttributes(
		tracing.SubscriptionStateKey.String(string(subscription.State)),
	)

	switch subscription.State {
	case arm.SubscriptionStateRegistered:
		next(w, r)
	case arm.SubscriptionStateUnregistered:
		arm.WriteError(
			w, http.StatusBadRequest,
			arm.CloudErrorCodeInvalidSubscriptionState, "",
			UnregisteredSubscriptionStateMessage,
			subscriptionId)
	case arm.SubscriptionStateWarned, arm.SubscriptionStateSuspended:
		if r.Method != http.MethodGet && r.Method != http.MethodDelete {
			arm.WriteError(w, http.StatusConflict,
				arm.CloudErrorCodeInvalidSubscriptionState, "",
				InvalidSubscriptionStateMessage,
				subscription.State)
			return
		}
		next(w, r)
	case arm.SubscriptionStateDeleted:
		arm.WriteError(
			w, http.StatusBadRequest,
			arm.CloudErrorCodeInvalidSubscriptionState, "",
			InvalidSubscriptionStateMessage,
			subscription.State)
	default:
		logger.Error(fmt.Sprintf("unsupported subscription state %q", subscription.State))
		arm.WriteInternalServerError(w)
	}
}