You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: cluster_create.go
    path of file: ./repos/pipeline/src/api
    
    the code of the file until where you have to start completion: // Copyright Â© 2018 Banzai Cloud
//
// 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 api

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"emperror.dev/errors"
	"github.com/gin-gonic/gin"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"

	"github.com/banzaicloud/pipeline/.gen/pipeline/pipeline"
	ginutils "github.com/banzaicloud/pipeline/internal/platform/gin/utils"
	pkgCluster "github.com/banzaicloud/pipeline/pkg/cluster"
	pkgCommon "github.com/banzaicloud/pipeline/pkg/common"
	pkgErrors "github.com/banzaicloud/pipeline/pkg/errors"
	clusterAPI "github.com/banzaicloud/pipeline/src/api/cluster"
	"github.com/banzaicloud/pipeline/src/auth"
	"github.com/banzaicloud/pipeline/src/cluster"
	"github.com/banzaicloud/pipeline/src/secret"
)

func decodeRequest(input map[string]interface{}, output interface{}) error {
	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		Result:  output,
		TagName: "json",
	})
	if err != nil {
		return err
	}

	return decoder.Decode(input)
}

func (a *ClusterAPI) parseRequest(ctx *gin.Context, body map[string]interface{}, req interface{}) bool {
	if err := decodeRequest(body, req); err != nil {
		err = errors.WrapIff(err, "failed to parse request into %T", req)

		a.errorHandler.Handle(err)
		pkgCommon.ErrorResponseWithStatus(ctx, http.StatusBadRequest, err)

		return false
	}
	return true
}

func isInputValidationError(err error) bool {
	var e interface {
		InputValidationError() bool
	}

	return errors.As(err, &e) && e.InputValidationError()
}

func (a *ClusterAPI) handleCreationError(ctx *gin.Context, err error) {
	a.errorHandler.Handle(err)

	status := http.StatusInternalServerError
	if isInputValidationError(err) || isInvalid(err) {
		status = http.StatusBadRequest
	}
	pkgCommon.ErrorResponseWithStatus(ctx, status, err)
}

// CreateCluster creates a K8S cluster in the cloud.
func (a *ClusterAPI) CreateCluster(c *gin.Context) {
	a.logger.Info("Cluster creation started")

	ctx := ginutils.Context(context.Background(), c)

	orgID := auth.GetCurrentOrganization(c.Request).ID
	userID := auth.GetCurrentUser(c.Request).ID

	var requestBody map[string]interface{}
	if err := c.ShouldBindJSON(&requestBody); err != nil {
		a.errorHandler.Handle(err)
		pkgCommon.ErrorResponseWithStatus(c, http.StatusBadRequest, err)
		return
	}
	if _, ok := requestBody["type"]; !ok {
		a.logger.Info("request body did not match v2 structure, trying legacy path")
		var createClusterRequest pkgCluster.CreateClusterRequest
		if !a.parseRequest(c, requestBody, &createClusterRequest) {
			return
		}

		if createClusterRequest.SecretId == "" && len(createClusterRequest.SecretIds) == 0 {
			if createClusterRequest.SecretName == "" {
				c.JSON(http.StatusBadRequest, pkgCommon.ErrorResponse{
					Code:    http.StatusBadRequest,
					Message: "either secretId or secretName has to be set",
		
    
func (a *ClusterAPI) CreateCluster(c *gin.Context) {
	a.logger.Info("Cluster creation started")

	ctx := ginutils.Context(context.Background(), c)

	orgID := auth.GetCurrentOrganization(c.Request).ID
	userID := auth.GetCurrentUser(c.Request).ID

	var requestBody map[string]interface{}
	if err := c.ShouldBindJSON(&requestBody); err != nil {
		a.errorHandler.Handle(err)
		pkgCommon.ErrorResponseWithStatus(c, http.StatusBadRequest, err)
		return
	}
	if _, ok := requestBody["type"]; !ok {
		a.logger.Info("request body did not match v2 structure, trying legacy path")
		var createClusterRequest pkgCluster.CreateClusterRequest
		if !a.parseRequest(c, requestBody, &createClusterRequest) {
			return
		}

		if createClusterRequest.SecretId == "" && len(createClusterRequest.SecretIds) == 0 {
			if createClusterRequest.SecretName == "" {
				c.JSON(http.StatusBadRequest, pkgCommon.ErrorResponse{
					Code:    http.StatusBadRequest,
					Message: "either secretId or secretName has to be set",
				})
				return
			}

			createClusterRequest.SecretId = secret.GenerateSecretIDFromName(createClusterRequest.SecretName)
		}

		existingCluster, err := a.clusterManager.GetClusterByName(ctx, orgID, createClusterRequest.Name)
		if err != nil && !isNotFoundError(err) {
			c.JSON(http.StatusInternalServerError, pkgCommon.ErrorResponse{
				Code:    http.StatusInternalServerError,
				Message: "check if the cluster already exists failed",
				Error:   err.Error(),
			})

			return
		} else if err != nil && isNotFoundError(err) {
			a.logger.Info("cluster does not exist yet, creating")
		}

		if existingCluster != nil {
			statusResponse, err := existingCluster.GetStatus()
			if err != nil {
				c.JSON(http.StatusInternalServerError, err)
				return
			}

			switch statusResponse.Status {
			case pkgCluster.Creating:
				c.JSON(http.StatusCreated, pkgCommon.BanzaiResponse{
					StatusCode: http.StatusCreated,
					Message:    cluster.ErrAlreadyExists.Error(),
				})
				return
			case pkgCluster.Deleting:
				c.JSON(http.StatusConflict, pkgCommon.ErrorResponse{
					Code:    http.StatusConflict,
					Message: cluster.ErrAlreadyExists.Error(),
					Error:   cluster.ErrAlreadyExists.Error(),
				})
				return
			default:
				c.JSON(http.StatusConflict, pkgCommon.ErrorResponse{
					Code:    http.StatusBadRequest,
					Message: cluster.ErrAlreadyExists.Error(),
					Error:   cluster.ErrAlreadyExists.Error(),
				})
				return
			}
		}

		commonCluster, errorResponse := a.createCluster(ctx, &createClusterRequest, orgID, userID, createClusterRequest.PostHooks)
		if errorResponse != nil {
			c.JSON(errorResponse.Code, errorResponse)
			return
		}

		c.JSON(http.StatusAccepted, pkgCluster.CreateClusterResponse{
			Name:       commonCluster.GetName(),
			ResourceID: commonCluster.GetID(),
		})
		return
	}

	var createClusterRequestBase pipeline.CreateClusterRequestBase
	if !a.parseRequest(c, requestBody, &createClusterRequestBase) {
		return
	}

	secretID := createClusterRequestBase.SecretId
	if secretID == "" {
		if createClusterRequestBase.SecretName != "" {
			secretID = secret.GenerateSecretIDFromName(createClusterRequestBase.SecretName)
		} else {
			ginutils.ReplyWithErrorResponse(c, &pkgCommon.ErrorResponse{
				Code:    http.StatusBadRequest,
				Message: "either secret ID or name is required",
				Error:   "no secret specified",
			})
			return
		}
	}

	var cluster interface {
		GetID() uint
		GetName() string
	}

	switch createClusterRequestBase.Type {
	case clusterAPI.PKEOnVsphere:
		var req clusterAPI.CreatePKEOnVsphereClusterRequest
		if ok := a.parseRequest(c, requestBody, &req); !ok {
			return
		}
		req.SecretId = secretID
		// TODO legacy posthook support if needed
		params := req.ToVspherePKEClusterCreationParams(orgID, userID)
		a.logger.Infof("request: %+v\n\n\nparams: %+v\n\n", req, params)
		vsphereCluster, err := a.clusterCreators.PKEOnVsphere.Create(ctx, params)
		if err = errors.WrapIf(err, "failed to create cluster from request"); err != nil {
			a.handleCreationError(c, err)
			return
		}
		cluster = vsphereCluster
	case clusterAPI.PKEOnAzure:
		var req clusterAPI.CreatePKEOnAzureClusterRequest
		if ok := a.parseRequest(c, requestBody, &req); !ok {
			return
		}
		req.SecretId = secretID
		params := req.ToAzurePKEClusterCreationParams(orgID, userID)
		azurePKECluster, err := a.clusterCreators.PKEOnAzure.Create(ctx, params)
		if err = errors.WrapIf(err, "failed to create cluster from request"); err != nil {
			a.handleCreationError(c, err)
			return
		}
		cluster = azurePKECluster
	default:
		ginutils.ReplyWithErrorResponse(c, &pkgCommon.ErrorResponse{
			Code:    http.StatusBadRequest,
			Message: fmt.Sprintf("unknown cluster type: %s", createClusterRequestBase.Type),
		})
		return
	}

	c.JSON(http.StatusAccepted, pkgCluster.CreateClusterResponse{
		Name:       cluster.GetName(),
		ResourceID: cluster.GetID(),
	})
}