func (c *LcmControllerV2) InstantiateV2() {
	log.Info("Application instantiation request received.")
	clientIp := c.Ctx.Input.IP()
	err := util.ValidateSrcAddress(clientIp)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, util.ClientIpaddressInvalid, util.ErrCodeIPInvalid)
		return
	}
	c.displayReceivedMsg(clientIp)
	accessToken := c.Ctx.Request.Header.Get(util.AccessToken)
	var req models.InstantiateRequest
	err = json.Unmarshal(c.Ctx.Input.RequestBody, &req)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, err.Error(), util.ErrCodeInvalidRequest)
		return
	}
	if req.Parameters == nil {
		req.Parameters = make(map[string]string)
	}
	bKey := *(*[]byte)(unsafe.Pointer(&accessToken))
	appInsId, tenantId, hostIp, packageId, appName, err := c.ValidateToken(accessToken, req, clientIp)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	originVar, err := util.ValidateName(req.Origin, util.NameRegex)
	if err != nil || !originVar {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.BadRequest, util.OriginIsInvalid, util.ErrCodeAppNameInvalid)
		return
	}
	appParams := &models.AppInfoParams{
		AppInstanceId: appInsId,
		MecHost:       hostIp,
		TenantId:      tenantId,
		AppPackageId:  packageId,
		AppName:       appName,
		ClientIP:      clientIp,
		AccessToken:   accessToken,
	}
	DoPrepareParams(c, appParams, bKey)
	DoInstantiate(c, appParams, bKey, req)
}
@Title Instantiate application
@Description Instantiate application
@Param   hostIp          body 	string	true   "hostIp"
@Param   appName         body 	string	true   "appName"
@Param   packageId       body 	string	true   "packageId"
@Param   tenantId        path 	string	true   "tenantId"
@Param   appInstanceId   path 	string	true   "appInstanceId"
@Param   access_token    header      string  true   "access token"
@Success 200 ok
@Failure 400 bad request
@router /tenants/:tenantId/app_instances/:appInstanceId/instantiate [post]
package controllers
import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"lcmcontroller/config"
	"lcmcontroller/models"
	"lcmcontroller/pkg/pluginAdapter"
	"lcmcontroller/util"
	"mime/multipart"
	"os"
	"path"
	"path/filepath"
	"strings"
	"unsafe"
	"github.com/ghodss/yaml"
	log "github.com/sirupsen/logrus"
)
type LcmControllerV2 struct {
	BaseController
}
func (c *LcmControllerV2) UploadConfigV2() {
	log.Info("Add configuration request received.")
	clientIp := c.Ctx.Input.IP()
	err := util.ValidateSrcAddress(clientIp)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, util.ClientIpaddressInvalid, util.ErrCodeIPInvalid)
		return
	}
	c.displayReceivedMsg(clientIp)
	accessToken := c.Ctx.Request.Header.Get(util.AccessToken)
	bKey := *(*[]byte)(unsafe.Pointer(&accessToken))
	_, err = c.IsPermitted(accessToken, clientIp)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	hostIp, vim, file, err := c.GetInputParametersForUploadCfg(clientIp)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	hostInfoRec := &models.MecHost{
		MecHostId: hostIp,
	}
	readErr := c.Db.ReadData(hostInfoRec, util.HostIp)
	if readErr != nil {
		c.HandleForErrorCode(clientIp, util.StatusNotFound,
			util.MecHostRecDoesNotExist, util.ErrCodeHostNotExist)
		return
	}
	pluginInfo := util.GetPluginInfo(vim)
	client, err := pluginAdapter.GetClient(pluginInfo)
	if err != nil {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, util.FailedToGetClient,
			util.ErrCodeFailedGetPlugin)
		return
	}
	adapter := pluginAdapter.NewPluginAdapter(pluginInfo, client)
	_, err = adapter.UploadConfig(file, hostIp, accessToken)
	util.ClearByteArray(bKey)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, util.PluginErrorReport,
			util.ErrCodePluginReportFailed)
		return
	}
	hostInfoRec.ConfigUploadStatus = "Uploaded"
	err = c.Db.InsertOrUpdateData(hostInfoRec, util.HostIp)
	if err != nil && err.Error() != util.LastInsertIdNotSupported {
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, util.InsertDBWithError,
			util.ErrCodeInsertDataFailed)
		log.Error("Failed to save mec host info record to database.")
		return
	}
	c.handleLoggingForSuccess(nil, clientIp, util.UploadConfigSuccess)
}
func (c *LcmControllerV2) UploadPackageV2() {
	log.Info("Upload application package request received.")
	clientIp := c.Ctx.Input.IP()
	err := util.ValidateSrcAddress(clientIp)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, util.ClientIpaddressInvalid, util.ErrCodeIPInvalid)
		return
	}
	c.displayReceivedMsg(clientIp)
	accessToken := c.Ctx.Request.Header.Get(util.AccessToken)
	bKey := *(*[]byte)(unsafe.Pointer(&accessToken))
	defer util.ClearByteArray(bKey)
	_, err = c.IsPermitted(accessToken, clientIp)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	appId, packageId, tenantId, err := c.GetInputParametersForUploadPkg(clientIp)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	origin, err := c.GetOrigin(clientIp)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	file, header, err := c.GetFile("package")
	if err != nil {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.BadRequest, "Upload config file error",
			util.ErrCodeFileCanNotRead)
		return
	}
	err = util.ValidateFileExtensionCsar(header.Filename)
	if err != nil || len(header.Filename) > util.MaxFileNameSize {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.BadRequest,
			"File shouldn't contains any extension or filename is larger than max size",
			util.ErrCodeFailedToSaveFile)
		return
	}
	err = util.ValidateFileSize(header.Size, util.MaxAppPackageFile)
	if err != nil {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.BadRequest, "File size is larger than max size", util.ErrCodeFileToBig)
		return
	}
	pkgFilePath, err := c.SaveApplicationPackage(clientIp, tenantId, packageId, header, file)
	if err != nil {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, err.Error(),
			util.ErrCodeFailedToSaveFile)
		return
	}
	pkgDir, err := extractCsarPackage(pkgFilePath)
	if err != nil {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, err.Error(),
			util.ErrCodeFailedToExtract)
		return
	}
	pkgDetails, err := c.GetPackageDetailsFromPackage(clientIp, pkgDir)
	if err != nil {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.BadRequest, util.GetPackageDetailsFailed, util.ErrCodeFailedGetDetails)
		return
	}
	err = c.InsertOrUpdateTenantRecord(clientIp, tenantId)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	err = c.InsertOrUpdateAppPkgRecord(appId, clientIp, tenantId, packageId, pkgDetails, origin)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	appPkgResp := &models.AppPackageResponse{
		AppId:     appId,
		PackageId: packageId,
	}
	c.handleLoggingForSuccess(appPkgResp, clientIp, util.UploadPackageSuccess)
}
func (c *LcmControllerV2) handleLoggingForSuccess(object interface{}, clientIp string, msg string) {
	log.Info("Response for ClientIP [" + clientIp + util.Operation + c.Ctx.Request.Method + "]" +
		util.Resource + c.Ctx.Input.URL() + "] Result [Success: " + msg + ".]")
	returnContent := handleSuccessReturn(object, msg)
	c.Data["json"] = returnContent
	c.Ctx.ResponseWriter.WriteHeader(util.SuccessCode)
	c.ServeJSON()
}
func (c *LcmControllerV2) GetInputParametersForUploadPkg(clientIp string) (string, string, string, error) {
	appId, err := c.GetAppId(clientIp)
	if err != nil {
		return "", "", "", err
	}
	if len(appId) == 0 {
		appId = util.GenerateUUID()
	}
	packageId, err := c.GetPackageId(clientIp)
	if err != nil {
		return "", "", "", err
	}
	if len(packageId) == 0 {
		packageId = appId + util.GenerateUUID()
	}
	tenantId, err := c.GetTenantId(clientIp)
	if err != nil {
		return "", "", "", err
	}
	return appId, packageId, tenantId, nil
}
func (c *LcmControllerV2) GetAppId(clientIp string) (string, error) {
	appId := c.GetString("appId")
	if appId != "" {
		if len(appId) > 32 {
			c.HandleForErrorCode(clientIp, util.BadRequest, util.AppIdIsNotValid, util.ErrCodeAppIdInvalid)
			return "", errors.New("app id length exceeds max limit")
		}
		return appId, nil
	}
	return "", nil
}
func (c *LcmControllerV2) GetPackageId(clientIp string) (string, error) {
	packageId := c.GetString("packageId")
	if packageId != "" {
		if len(packageId) > 64 {
			c.HandleForErrorCode(clientIp, util.BadRequest, util.PackageIdIsInvalid, util.ErrCodePackageIdInvalid)
			return "", errors.New("package id length exceeds max limit")
		}
		return packageId, nil
	}
	return "", nil
}
func (c *LcmControllerV2) GetOrigin(clientIp string) (string, error) {
	origin := c.GetString("origin")
	originVar, err := util.ValidateName(origin, util.NameRegex)
	if err != nil || !originVar {
		c.HandleForErrorCode(clientIp, util.BadRequest, util.OriginIsInvalid, util.ErrCodeOriginInvalid)
		return "", errors.New(util.OriginIsInvalid)
	}
	return origin, nil
}
func (c *LcmControllerV2) SaveApplicationPackage(clientIp string, tenantId string, packageId string,
	header *multipart.FileHeader, file multipart.File) (string, error) {
	err := createDirectory(PackageFolderPath + tenantId)
	if err != nil {
		return "", err
	}
	err = createDirectory(PackageFolderPath + tenantId + "/" + packageId)
	if err != nil {
		return "", err
	}
	pkgPath := PackageFolderPath + tenantId + "/" + packageId + "/" + packageId + ".csar"
	err = c.CreatePackagePath(pkgPath, clientIp, file)
	if err != nil {
		return "", err
	}
	return pkgPath, nil
}
func (c *LcmControllerV2) CreatePackagePath(pkgPath string, clientIp string, file multipart.File) error {
	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, file); err != nil {
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, "Failed to copy csar file",
			util.ErrCodeFailedToSaveFile)
		return err
	}
	newFile, err := os.Create(pkgPath)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, "Failed to create package path",
			util.ErrCodeFailedToSaveFile)
		return err
	}
	defer newFile.Close()
	if _, err := newFile.Write(buf.Bytes()); err != nil {
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, "Failed to write csar file",
			util.ErrCodeFailedToSaveFile)
		return err
	}
	return nil
}
func (c *LcmControllerV2) GetUrlPackageId(clientIp string) (string, error) {
	packageId := c.Ctx.Input.Param(":packageId")
	if packageId != "" {
		if len(packageId) > 64 {
			c.HandleForErrorCode(clientIp, util.BadRequest, util.PackageIdIsInvalid, util.ErrCodePackageIdInvalid)
			return "", errors.New("invalid package id")
		}
		return packageId, nil
	}
	return "", nil
}
func (c *LcmControllerV2) GetPackageDetailsFromPackage(clientIp string,
	packageDir string) (models.AppPkgDetails, error) {
	var pkgDetails models.AppPkgDetails
	mf, err := c.GetFileContainsExtension(packageDir, ".mf")
	if err != nil {
		log.Error("failed to find mf file, check if mf file exist.")
		c.HandleForErrorCode(clientIp, util.BadRequest, "failed to find mf file, check if mf file exist.",
			util.ErrCodeFailedGetDetails)
		return pkgDetails, errors.New("failed to find mf file")
	}
	mfYaml, err := os.Open(mf)
	if err != nil {
		log.Error(util.FailedToReadMfFile)
		return pkgDetails, errors.New(util.FailedToReadMfFile)
	}
	defer mfYaml.Close()
	mfFileBytes, err := readMfBytes(mfYaml)
	if err != nil {
		log.Error(util.FailedToAnalysisMfFile)
		return pkgDetails, errors.New(util.FailedToCovertYamlToJson)
	}
	data, err := yaml.YAMLToJSON(mfFileBytes)
	if err != nil {
		log.Error(util.FailedToCovertYamlToJson + ", pls check mf file if struct is not correct.")
		return pkgDetails, errors.New(util.FailedToCovertYamlToJson)
	}
	err = json.Unmarshal(data, &pkgDetails)
	if err != nil {
		log.Error(util.UnMarshalError + ", pls check if app version or desc was incorrectly set to a number.")
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, util.UnMarshalError,
			util.ErrCodeFailedGetDetails)
		return pkgDetails, err
	}
	return pkgDetails, nil
}
func (c *LcmControllerV2) GetFileContainsExtension(pkgDir string, ext string) (string, error) {
	data, err := os.Open(pkgDir)
	if err != nil {
		log.Error(util.FailedToFindAppPackage)
		return "", errors.New(util.FailedToFindAppPackage)
	}
	defer data.Close()
	files, err := data.Readdir(-1)
	if err != nil {
		log.Error(util.FailedToReadAppPackage)
		return "", errors.New(util.FailedToReadAppPackage)
	}
	for _, file := range files {
		if file.Mode().IsRegular() && filepath.Ext(file.Name()) == ext {
			return pkgDir + "/" + file.Name(), nil
		}
	}
	log.Error(util.FileNameNotFound + ext)
	return "", errors.New(util.FileNameNotFound + ext)
}
func (c *LcmControllerV2) GetInputParametersForUploadCfg(clientIp string) (hostIp string,
	vim string, file multipart.File, err error) {
	hostIp, err = c.GetHostIP(clientIp)
	if err != nil {
		return hostIp, vim, file, err
	}
	vim, err = c.GetVim(clientIp, hostIp)
	if err != nil {
		return hostIp, vim, file, err
	}
	file, header, err := c.GetFile("configFile")
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, "Upload config file error",
			util.ErrCodeFileCanNotRead)
		return hostIp, vim, file, err
	}
	err = util.ValidateFileExtensionEmpty(header.Filename)
	if err != nil || len(header.Filename) > util.MaxFileNameSize {
		c.HandleForErrorCode(clientIp, util.BadRequest,
			"File shouldn't contains any extension or filename is larger than max size",
			util.ErrCodeFileNameTooLang)
		return hostIp, vim, file, err
	}
	err = util.ValidateFileSize(header.Size, util.MaxConfigFile)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, "File size is larger than max size",
			util.ErrCodeFileToBig)
		return hostIp, vim, file, err
	}
	err = c.ValidateYamlFile(clientIp, file)
	if err != nil {
		return hostIp, vim, file, err
	}
	_, err = file.Seek(0, 0)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, err.Error(), util.ErrCodeFailedToSaveFile)
		return hostIp, vim, file, err
	}
	return hostIp, vim, file, nil
}
func (c *LcmControllerV2) ValidateYamlFile(clientIp string, file multipart.File) error {
	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, file); err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, "Failed to copy file into buffer",
			util.ErrCodeFailedToSaveFile)
		return err
	}
	_, err := yaml.YAMLToJSON(buf.Bytes())
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, "KubeConfig file validation is failed",
			util.ErrCodeFileCanNotRead)
		return err
	}
	return nil
}
func (c *LcmControllerV2) RemoveConfigV2() {
	log.Info("Delete configuration request received.")
	clientIp := c.Ctx.Input.IP()
	err := util.ValidateSrcAddress(clientIp)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, util.ClientIpaddressInvalid, util.ErrCodeIPInvalid)
		return
	}
	c.displayReceivedMsg(clientIp)
	name, err := c.GetUserName(clientIp)
	if err != nil {
		return
	}
	key, err := c.GetKey(clientIp)
	if err != nil {
		return
	}
	accessToken := c.Ctx.Request.Header.Get(util.AccessToken)
	if accessToken != "" {
		err = util.ValidateAccessToken(accessToken, []string{util.MecmTenantRole, util.MecmAdminRole}, "")
		if err != nil {
			c.HandleLoggingForTokenFailure(clientIp, err.Error())
			return
		}
	} else {
		if name != "" && key != "" {
			err = c.validateCredentials(clientIp, name, key)
			if err != nil {
				return
			}
		}
	}
	bKey := *(*[]byte)(unsafe.Pointer(&accessToken))
	hostIp, vim, hostInfoRec, err := c.GetInputParametersForRemoveCfg(clientIp)
	if err != nil {
		util.ClearByteArray(bKey)
		return
	}
	pluginInfo := util.GetPluginInfo(vim)
	client, err := pluginAdapter.GetClient(pluginInfo)
	if err != nil {
		util.ClearByteArray(bKey)
		c.HandleForErrorCode(clientIp, util.StatusInternalServerError, util.FailedToGetClient,
			util.ErrCodeFailedGetPlugin)
		return
	}
	adapter := pluginAdapter.NewPluginAdapter(pluginInfo, client)
	_, err = adapter.RemoveConfig(hostIp, accessToken)
	util.ClearByteArray(bKey)
	if err != nil {
		c.HandleLoggingForFailure(clientIp, err.Error())
		return
	}
	hostInfoRec.ConfigUploadStatus = ""
	err = c.Db.InsertOrUpdateData(hostInfoRec, util.HostIp)
	if err != nil && err.Error() != util.LastInsertIdNotSupported {
		log.Error("Failed to save mec host info record to database.")
		return
	}
	c.handleLoggingForSuccess(nil, clientIp, "Remove config is successful")
}
func (c *LcmControllerV2) GetVim(clientIp string, hostIp string) (string, error) {
	mecHostInfoRec, err := c.GetMecHostInfoRecord(hostIp, clientIp)
	if err != nil {
		return "", err
	}
	vim := mecHostInfoRec.Vim
	if vim == "" {
		log.Info("Setting plugin to default value which is k8s, as no VIM is mentioned explicitly")
		vim = "k8s"
	}
	return vim, nil
}
func (c *LcmControllerV2) GetInputParametersForRemoveCfg(clientIp string) (string, string, *models.MecHost, error) {
	hostIp, err := c.GetHostIP(clientIp)
	if err != nil {
		return "", "", &models.MecHost{}, err
	}
	hostInfoRec := &models.MecHost{
		MecHostId: hostIp,
	}
	readErr := c.Db.ReadData(hostInfoRec, util.HostIp)
	if readErr != nil {
		c.HandleForErrorCode(clientIp, util.StatusNotFound,
			util.MecHostRecDoesNotExist, util.ErrCodeHostNotExist)
		return "", "", hostInfoRec, err
	}
	vim, err := c.GetVim(clientIp, hostIp)
	if err != nil {
		return "", "", hostInfoRec, err
	}
	return hostIp, vim, hostInfoRec, err
}
func (c *LcmControllerV2) GetHostIP(clientIp string) (string, error) {
	hostIp := c.GetString("hostIp")
	err := util.ValidateIpv4Address(hostIp)
	if err != nil {
		c.HandleForErrorCode(clientIp, util.BadRequest, util.HostIpIsInvalid, util.ErrCodeMecHostInvalid)
		return "", err
	}
	return hostIp, nil
}