From f8e07dea9da26a03d1e98f6abbde380da469b13d Mon Sep 17 00:00:00 2001 From: innodreamer Date: Wed, 5 Feb 2025 19:07:25 +0900 Subject: [PATCH 1/2] Update CheckWindowsImage() and isPublicImage() --- .../drivers/ncp/resources/ImageHandler.go | 50 ++++++++++++++----- .../drivers/ncp/resources/MyImageHandler.go | 41 ++------------- .../drivers/ncp/resources/VMHandler.go | 18 ++++--- 3 files changed, 53 insertions(+), 56 deletions(-) diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go index 82e69a16a..e978c4ec8 100644 --- a/cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go @@ -39,7 +39,6 @@ func init() { func (imageHandler *NcpImageHandler) GetImage(imageIID irs.IID) (irs.ImageInfo, error) { cblogger.Info("NCP Classic Cloud Driver: called GetImage()!!") - InitLog() callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Zone, call.VMIMAGE, imageIID.SystemId, "GetImage()") @@ -63,7 +62,6 @@ func (imageHandler *NcpImageHandler) GetImage(imageIID irs.IID) (irs.ImageInfo, func (imageHandler *NcpImageHandler) ListImage() ([]*irs.ImageInfo, error) { cblogger.Info("NCP Classic Cloud Driver: called ListImage()!") - InitLog() callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Zone, call.VMIMAGE, "ListImage()", "ListImage()") @@ -185,7 +183,6 @@ func (imageHandler *NcpImageHandler) CreateImage(imageReqInfo irs.ImageReqInfo) func (imageHandler *NcpImageHandler) CheckWindowsImage(imageIID irs.IID) (bool, error) { cblogger.Info("NCP Classic Cloud Driver: called CheckWindowsImage()") - InitLog() callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Region, call.MYIMAGE, imageIID.SystemId, "CheckWindowsImage()") @@ -196,21 +193,21 @@ func (imageHandler *NcpImageHandler) CheckWindowsImage(imageIID irs.IID) (bool, return false, newErr } - myImageHandler := NcpMyImageHandler{ - RegionInfo: imageHandler.RegionInfo, - VMClient: imageHandler.VMClient, - } - myImagePlatform, err := myImageHandler.GetOriginImageOSPlatform(imageIID) + ncpImageInfo, err := imageHandler.GetNcpImageInfo(imageIID) if err != nil { - newErr := fmt.Errorf("Failed to Get MyImage Info. [%v]", err.Error()) + newErr := fmt.Errorf("Failed to Get the Image Info from NCP : [%v]", err) cblogger.Error(newErr.Error()) LoggingError(callLogInfo, newErr) return false, newErr - } - + } + isWindowsImage := false - if strings.Contains(myImagePlatform, "WINDOWS") { - isWindowsImage = true + if ncpImageInfo.ProductType != nil { + if ncpImageInfo.ProductType.Code != nil { + if strings.EqualFold(*ncpImageInfo.ProductType.Code, "WINNT") { + isWindowsImage = true + } + } } return isWindowsImage, nil } @@ -272,3 +269,30 @@ func (imageHandler *NcpImageHandler) GetNcpImageInfo(imageIID irs.IID) (*server. cblogger.Info("Succeeded in Getting NCP Image info.") return result.ProductList[0], nil } + +func (imageHandler *NcpImageHandler) isPublicImage(imageIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called isPublicImage()") + InitLog() + callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Region, call.MYIMAGE, imageIID.SystemId, "isPublicImage()") // HisCall logging + + if strings.EqualFold(imageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Image SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + ncpImageInfo, err := imageHandler.GetNcpImageInfo(imageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Image Info from NCP : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, nil // Caution!! + } else { + isPublicImage := false + if strings.EqualFold(*ncpImageInfo.ProductCode, imageIID.SystemId) { + isPublicImage = true + } + return isPublicImage, nil + } +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go index 21c036491..c201d68c2 100644 --- a/cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go @@ -400,17 +400,17 @@ func (myImageHandler *NcpMyImageHandler) GetOriginImageOSPlatform(imageIID irs.I return "", newErr } - isPublicImage, err := myImageHandler.isPublicImage(imageIID) + imageHandler := NcpImageHandler{ + RegionInfo: myImageHandler.RegionInfo, + VMClient: myImageHandler.VMClient, + } + isPublicImage, err := imageHandler.isPublicImage(imageIID) if err != nil { newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) cblogger.Error(newErr.Error()) return "", newErr } if isPublicImage { - imageHandler := NcpImageHandler{ - RegionInfo: myImageHandler.RegionInfo, - VMClient: myImageHandler.VMClient, - } ncpImageInfo, err := imageHandler.GetNcpImageInfo(imageIID) if err != nil { newErr := fmt.Errorf("Failed to Get the Image Info from NCP : [%v]", err) @@ -464,37 +464,6 @@ func (myImageHandler *NcpMyImageHandler) GetOriginImageOSPlatform(imageIID irs.I } } -func (myImageHandler *NcpMyImageHandler) isPublicImage(imageIID irs.IID) (bool, error) { - cblogger.Info("NCP Classic Cloud Driver: called isPublicImage()") - InitLog() - callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, imageIID.SystemId, "isPublicImage()") // HisCall logging - - if strings.EqualFold(imageIID.SystemId, "") { - newErr := fmt.Errorf("Invalid Image SystemId!!") - cblogger.Error(newErr.Error()) - LoggingError(callLogInfo, newErr) - return false, newErr - } - - imageHandler := NcpImageHandler{ - RegionInfo: myImageHandler.RegionInfo, - VMClient: myImageHandler.VMClient, - } - ncpImageInfo, err := imageHandler.GetNcpImageInfo(imageIID) - if err != nil { - newErr := fmt.Errorf("Failed to Get the Image Info from NCP : [%v]", err) - cblogger.Error(newErr.Error()) - LoggingError(callLogInfo, newErr) - return false, nil // Caution!! - } else { - isPublicImage := false - if strings.EqualFold(*ncpImageInfo.ProductCode, imageIID.SystemId) { - isPublicImage = true - } - return isPublicImage, nil - } -} - func (myImageHandler *NcpMyImageHandler) ListIID() ([]*irs.IID, error) { cblogger.Info("NCP Classic Cloud Driver: called myImageHandler ListIID()") InitLog() diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go index 96cd6a1b7..006290147 100644 --- a/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go @@ -121,11 +121,11 @@ func (vmHandler *NcpVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, err var initUserData *string if vmReqInfo.ImageType == irs.PublicImage || vmReqInfo.ImageType == "" || vmReqInfo.ImageType == "default" { - myImageHandler := NcpMyImageHandler{ + imageHandler := NcpImageHandler{ RegionInfo: vmHandler.RegionInfo, VMClient: vmHandler.VMClient, } - isPublicImage, err := myImageHandler.isPublicImage(vmReqInfo.ImageIID) + isPublicImage, err := imageHandler.isPublicImage(vmReqInfo.ImageIID) if err != nil { newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) cblogger.Error(newErr.Error()) @@ -139,7 +139,7 @@ func (vmHandler *NcpVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, err publicImageId = vmReqInfo.ImageIID.SystemId } - isPublicWindowsImage, err := myImageHandler.CheckWindowsImage(vmReqInfo.ImageIID) + isPublicWindowsImage, err := imageHandler.CheckWindowsImage(vmReqInfo.ImageIID) if err != nil { rtnErr := logAndReturnError(callLogInfo, "Failed to Check Whether the Image is MS Windows Image : ", err) return irs.VMInfo{}, rtnErr @@ -160,11 +160,11 @@ func (vmHandler *NcpVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, err } } } else { - myImageHandler := NcpMyImageHandler{ + imageHandler := NcpImageHandler{ RegionInfo: vmHandler.RegionInfo, VMClient: vmHandler.VMClient, } - isPublicImage, err := myImageHandler.isPublicImage(vmReqInfo.ImageIID) + isPublicImage, err := imageHandler.isPublicImage(vmReqInfo.ImageIID) if err != nil { newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) cblogger.Error(newErr.Error()) @@ -178,6 +178,10 @@ func (vmHandler *NcpVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, err myImageId = vmReqInfo.ImageIID.SystemId } + myImageHandler := NcpMyImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } isMyWindowsImage, err := myImageHandler.CheckWindowsImage(vmReqInfo.ImageIID) if err != nil { rtnErr := logAndReturnError(callLogInfo, "Failed to Check Whether My Image is MS Windows Image : ", err) @@ -445,7 +449,7 @@ func (vmHandler *NcpVMHandler) mappingServerInfo(NcpInstance *server.ServerInsta }, } - myImageHandler := NcpMyImageHandler{ + imageHandler := NcpImageHandler{ RegionInfo: vmHandler.RegionInfo, VMClient: vmHandler.VMClient, } @@ -454,7 +458,7 @@ func (vmHandler *NcpVMHandler) mappingServerInfo(NcpInstance *server.ServerInsta vmInfo.ImageIId.SystemId = *NcpInstance.ServerDescription // Note!! : Since MyImage ID is not included in the 'NcpInstance' info vmInfo.ImageIId.NameId = *NcpInstance.ServerDescription - isPublicImage, err := myImageHandler.isPublicImage(irs.IID{SystemId: *NcpInstance.ServerDescription}) // Caution!! : Not '*NcpInstance.ServerImageProductCode' + isPublicImage, err := imageHandler.isPublicImage(irs.IID{SystemId: *NcpInstance.ServerDescription}) // Caution!! : Not '*NcpInstance.ServerImageProductCode' if err != nil { newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) return irs.VMInfo{}, newErr From 9675bad56ce57b3c9ba6834362b11b8f10b5ebe5 Mon Sep 17 00:00:00 2001 From: innodreamer Date: Wed, 5 Feb 2025 19:09:48 +0900 Subject: [PATCH 2/2] Enhance Supported VM Spec Info. and, Deduplicate VM Spec info list --- .../drivers/ncp/resources/VMSpecHandler.go | 136 ++++++++++++------ 1 file changed, 89 insertions(+), 47 deletions(-) diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go index 2bb704f75..1bafd0e2a 100644 --- a/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "strconv" + // "github.com/davecgh/go-spew/spew" "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" @@ -76,11 +77,12 @@ func (vmSpecHandler *NcpVMSpecHandler) ListVMSpec() ([]*irs.VMSpecInfo, error) { } // Note : var vmProductList []*server.Product //NCP Product(Spec) Info. - var vmSpecInfoList []*irs.VMSpecInfo //Cloud-Barista Spec Info. - + var vmSpecInfoMap = make(map[string]*irs.VMSpecInfo) // Map to track unique VMSpec Info. + var vmSpecInfoList []*irs.VMSpecInfo // List to return unique VMSpec Info. + for _, image := range imageListResult { - cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) - + cblogger.Infof("# Lookup by NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + vmSpecReq := server.GetServerProductListRequest{ RegionNo: regionNo, ZoneNo: zoneNo, @@ -94,15 +96,36 @@ func (vmSpecHandler *NcpVMSpecHandler) ListVMSpec() ([]*irs.VMSpecInfo, error) { return nil, err } else { cblogger.Info("Succeeded in Getting VMSpec list!!") - cblogger.Infof("기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) - cblogger.Infof("에 대해 조회된 VMSpec 정보 수 : [%d]", len(result.ProductList)) + cblogger.Infof("Lookup by NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + cblogger.Infof("Number of VMSpec info looked up : [%d]", len(result.ProductList)) } - + for _, product := range result.ProductList { - vmSpecInfo := MappingVMSpecInfo(ncpRegion, image.IId.SystemId, *product) - vmSpecInfoList = append(vmSpecInfoList, &vmSpecInfo) + vmSpecInfo := mappingVMSpecInfo(ncpRegion, *product) + if existingSpec, exists := vmSpecInfoMap[vmSpecInfo.Name]; exists { + // If the VMSpec already exists, add the image ID to the related images list in KeyValueList + for i, kv := range existingSpec.KeyValueList { + if kv.Key == "RelatedImages" { + existingSpec.KeyValueList[i].Value += "," + image.IId.SystemId + break + } + } + } else { + // If the VMSpec is new, add it to the map and initialize the related images list in KeyValueList + vmSpecInfo.KeyValueList = append(vmSpecInfo.KeyValueList, irs.KeyValue{ + Key: "RelatedImages", + Value: image.IId.SystemId, + }) + vmSpecInfoMap[vmSpecInfo.Name] = &vmSpecInfo + } } } + + // Convert the map to a list + for _, specInfo := range vmSpecInfoMap { + vmSpecInfoList = append(vmSpecInfoList, specInfo) + } + cblogger.Infof("# 총 VMSpec 수 : [%d]", len(vmSpecInfoList)) return vmSpecInfoList, err } @@ -144,7 +167,7 @@ func (vmSpecHandler *NcpVMSpecHandler) GetVMSpec(Name string) (irs.VMSpecInfo, e imgListResult, err := imgHandler.ListImage() if err != nil { - cblogger.Infof("Failed to Find Image list!! : ", err) + cblogger.Infof("Failed to Find Image list!! : [%v]", err) return irs.VMSpecInfo{}, errors.New("Failed to Find Image list!!") } else { cblogger.Info("Succeeded in Getting Image list!!") @@ -154,7 +177,7 @@ func (vmSpecHandler *NcpVMSpecHandler) GetVMSpec(Name string) (irs.VMSpecInfo, e } for _, image := range imgListResult { - cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + cblogger.Infof("# Lookup by NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) specReq := server.GetServerProductListRequest{ RegionNo: regionNo, @@ -175,7 +198,7 @@ func (vmSpecHandler *NcpVMSpecHandler) GetVMSpec(Name string) (irs.VMSpecInfo, e // spew.Dump(result) if len(result.ProductList) > 0 { - specInfo := MappingVMSpecInfo(ncpRegion, image.IId.SystemId, *result.ProductList[0]) + specInfo := mappingVMSpecInfo(ncpRegion, *result.ProductList[0]) return specInfo, nil } } @@ -226,10 +249,12 @@ func (vmSpecHandler *NcpVMSpecHandler) ListOrgVMSpec() (string, error) { // spew.Dump(imageListResult) } - var productList []*server.Product //NCP Product(Spec) Info. + var vmSpecInfoMap = make(map[string]*irs.VMSpecInfo) // Map to track unique VMSpec Info. + var vmSpecInfoList []*irs.VMSpecInfo // List to return unique VMSpec Info. + for _, image := range imageListResult { - cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) - + cblogger.Infof("# Lookup by NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + vmSpecReq := server.GetServerProductListRequest{ RegionNo: regionNo, ZoneNo: zoneNo, @@ -243,17 +268,38 @@ func (vmSpecHandler *NcpVMSpecHandler) ListOrgVMSpec() (string, error) { return "", err } else { cblogger.Info("Succeeded in Getting VMSpec list!!") - cblogger.Infof("기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) - cblogger.Infof("에 대해 조회된 VMSpec 정보 수 : [%d]", len(result.ProductList)) - } - + cblogger.Infof("Lookup by NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + cblogger.Infof("Number of VMSpec info looked up : [%d]", len(result.ProductList)) + } + for _, product := range result.ProductList { - productList = append(productList, product) + vmSpecInfo := mappingVMSpecInfo(ncpRegion, *product) + if existingSpec, exists := vmSpecInfoMap[vmSpecInfo.Name]; exists { + // If the VMSpec already exists, add the image ID to the related images list in KeyValueList + for i, kv := range existingSpec.KeyValueList { + if kv.Key == "RelatedImages" { + existingSpec.KeyValueList[i].Value += "," + image.IId.SystemId + break + } + } + } else { + // If the VMSpec is new, add it to the map and initialize the related images list in KeyValueList + vmSpecInfo.KeyValueList = append(vmSpecInfo.KeyValueList, irs.KeyValue{ + Key: "RelatedImages", + Value: image.IId.SystemId, + }) + vmSpecInfoMap[vmSpecInfo.Name] = &vmSpecInfo + } } } - cblogger.Infof("# 총 VMSpec 수 : [%d]", len(productList)) + + // Convert the map to a list + for _, specInfo := range vmSpecInfoMap { + vmSpecInfoList = append(vmSpecInfoList, specInfo) + } + // cblogger.Infof("# VMSpec Count : [%d]", len(vmSpecInfoList)) - jsonString, jsonErr := ConvertJsonString(productList) + jsonString, jsonErr := ConvertJsonString(vmSpecInfoList) if jsonErr != nil { cblogger.Error(jsonErr) return "", jsonErr @@ -308,7 +354,7 @@ func (vmSpecHandler *NcpVMSpecHandler) GetOrgVMSpec(Name string) (string, error) } for _, image := range imgListResult { - cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + cblogger.Infof("# Lookup by NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) specReq := server.GetServerProductListRequest{ RegionNo: regionNo, @@ -341,39 +387,35 @@ func (vmSpecHandler *NcpVMSpecHandler) GetOrgVMSpec(Name string) (string, error) return "", nil } -func MappingVMSpecInfo(Region string, ImageId string, NcpVMSpec server.Product) irs.VMSpecInfo { +func mappingVMSpecInfo(region string, vmSpec server.Product) irs.VMSpecInfo { // server ProductList type : []*Product - cblogger.Infof("*** Mapping VMSpecInfo : Region: [%s] / SpecName: [%s]", Region, *NcpVMSpec.ProductCode) + cblogger.Infof("*** Mapping VMSpecInfo : Region: [%s] / SpecName: [%s]", region, *vmSpec.ProductCode) // spew.Dump(vmSpec) - // vmSpec에 리전 정보는 없기 때문에 받은 리전 정보로 기입 - // NOTE 주의 : vmSpec.ProductCode -> specName 으로 + // Since there is no region information in vmSpec, use the region information provided to the function + // NOTE: Caution: vmSpec.ProductCode -> specName vmSpecInfo := irs.VMSpecInfo{ - Region: Region, - //Name: *NcpVMSpec.ProductName, - Name: *NcpVMSpec.ProductCode, - // int32 to string 변환 : String(), int64 to string 변환 : strconv.Itoa() - VCpu: irs.VCpuInfo{Count: String(*NcpVMSpec.CpuCount), Clock: "N/A"}, + Region: region, + // Name: *vmSpec.ProductName, + Name: *vmSpec.ProductCode, + // int32 to string : String(), int64 to string : strconv.Itoa() + VCpu: irs.VCpuInfo{Count: String(*vmSpec.CpuCount), Clock: "-1"}, - // server.Product에 GPU 정보는 없음. - Gpu: []irs.GpuInfo{{Count: "N/A", Model: "N/A"}}, + // 'server.Product' does not contain GPU information. + Gpu: []irs.GpuInfo{{Count: "-1", Mfr: "NA", Model: "NA", Mem: "-1"}}, + Mem: strconv.FormatFloat(float64(*vmSpec.MemorySize)/(1024*1024), 'f', 0, 64), + Disk: strconv.FormatFloat(float64(*vmSpec.BaseBlockStorageSize)/(1024*1024*1024), 'f', 0, 64), KeyValueList: []irs.KeyValue{ + {Key: "ProductType", Value: *vmSpec.ProductType.CodeName}, + {Key: "InfraResourceType", Value: *vmSpec.InfraResourceType.CodeName}, + {Key: "DiskType", Value: *vmSpec.DiskType.CodeName}, + {Key: "ProductDescription", Value: *vmSpec.ProductDescription}, + {Key: "GenerationCode", Value: *vmSpec.GenerationCode}, // {Key: "ProductName", Value: *vmSpec.ProductName}, //This is same to 'ProductDescription'. - {Key: "ProductType", Value: *NcpVMSpec.ProductType.CodeName}, - {Key: "InfraResourceType", Value: *NcpVMSpec.InfraResourceType.CodeName}, - // {Key: "PlatformType", Value: *NcpVMSpec.PlatformType.CodeName}, //This makes "invalid memory address or nil pointer dereference" error - {Key: "BaseBlockStorageSize(GB)", Value: strconv.FormatFloat(float64(*NcpVMSpec.BaseBlockStorageSize)/(1024*1024*1024), 'f', 0, 64)}, - {Key: "DiskType", Value: *NcpVMSpec.DiskType.CodeName}, - {Key: "ProductDescription", Value: *NcpVMSpec.ProductDescription}, - {Key: "SupportingImageSystemId", Value: ImageId}, - {Key: "NCPGenerationCode", Value: *NcpVMSpec.GenerationCode}, - {Key: "NCP Region", Value: Region}, + // {Key: "PlatformType", Value: *vmSpec.PlatformType.CodeName}, //This makes "invalid memory address or nil pointer dereference" error }, } - - // vmSpecInfo.Mem = strconv.FormatFloat(float64(*vmSpec.MemorySize)*1024, 'f', 0, 64) // GB->MB로 변환 - vmSpecInfo.Mem = strconv.FormatFloat(float64(*NcpVMSpec.MemorySize)/(1024*1024), 'f', 0, 64) - + // Mem : strconv.FormatFloat(float64(*vmSpec.MemorySize)*1024, 'f', 0, 64) // GB -> MB return vmSpecInfo }