Skip to content

Commit

Permalink
Merge pull request #1461 from innodreamer/master
Browse files Browse the repository at this point in the history
[KT Cloud Classic/VPC] Enhance Supported RegionZone / VM Image / VM Sepc Info
  • Loading branch information
powerkimhub authored Feb 7, 2025
2 parents 976dc25 + 0a3aca1 commit 37f35ea
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 208 deletions.
4 changes: 2 additions & 2 deletions cloud-control-manager/cloud-driver/drivers/ktcloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ $GOPATH/src/github.com/cloud-barista/ktcloud/ktcloud/main/
<p><br>

​ O VM 생성을 위한 VMImage ID, VMSpec ID 결정 관련
- 해당 zone에서 지원하는 VM Image(KT Cloud의 Template) 목록중 사용하고자 하는 운영체제(OS)에 대한 Image ID 값을 찾은 뒤, VM Spec 목록에서 추가 정보로 제공하는 'SupportingImage(Template)ID'에서 그 Image ID와 같은 VM Spec을 찾아 해당 Image ID를 지원하는 VMSpec ID를 사용해야함.
- 위와 같이 해당 VMImage를 지원하는 VMSpec ID를 사용해야하는데, 그렇지 않은 경우 KT Cloud에서는 error message로 "general error"를 return함.
- 해당 zone에서 지원하는 VM Image(KT Cloud의 Template) 목록중 사용하고자 하는 운영체제(OS)에 대한 Image ID 값을 찾은 뒤, VM Spec 목록에서 추가 정보로 제공하는 'CorrespondingImageIds'에서 그 Image ID와 같은 ID를 찾아 해당 Image ID를 지원하는 VMSpec ID를 지정하여 VM을 생성해야함.
- 위와 같이 해당 VM Image를 지원하는 VMSpec ID를 사용해야하는데, 그렇지 않은 경우 KT Cloud에서는 error message로 "general error"를 return함.
<p><br>

​ O Security Group 설정시 주의해야할 사항으로, 본 드라이버는 inbound rule만 지원하고, protocol별 rule이 중복되지 않아야함.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
// KT Cloud Image Handler
//
// by ETRI, 2021.05.
// Updated by ETRI, 2025.02.

package resources

import (
"errors"
"fmt"
"strings"

//"github.com/davecgh/go-spew/spew"
"regexp"
// "github.com/davecgh/go-spew/spew"

ktsdk "github.com/cloud-barista/ktcloud-sdk-go"

Expand All @@ -36,55 +37,37 @@ func init() {
}

// <Note> 'Image' in KT Cloud API manual means an image created for Volume or Snapshot of VM stopped state.

func (imageHandler *KtCloudImageHandler) GetImage(imageIID irs.IID) (irs.ImageInfo, error) {
cblogger.Info("KT Cloud cloud driver: called GetImage()!!")
// cblogger.Infof("KT Cloud image ID(Templateid) : [%s]", imageIID.SystemId)
// cblogger.Info("imageHandler.RegionInfo.Zone : ", zoneId)

if strings.EqualFold(imageIID.SystemId, "") {
newErr := fmt.Errorf("Invalid Image SystemId!!")
cblogger.Error(newErr.Error())
return irs.ImageInfo{}, newErr
}

var resultImageInfo irs.ImageInfo
zoneId := imageHandler.RegionInfo.Zone

cblogger.Infof("KT Cloud image ID(Templateid) : [%s]", imageIID.SystemId)
cblogger.Info("imageHandler.RegionInfo.Zone : ", zoneId)

// Caution!! : KT Cloud searches by 'zoneId' when searching Image info/VMSpc info.
result, err := imageHandler.Client.ListAvailableProductTypes(zoneId)
// Note!!) Use ListImage() to search within the organized image list information
imageListResult, err := imageHandler.ListImage()
if err != nil {
cblogger.Error("Failed to Get List of Available Product Types: %s", err)
return irs.ImageInfo{}, err
}

if len(result.Listavailableproducttypesresponse.ProductTypes) < 1 {
return irs.ImageInfo{}, errors.New("Failed to Get Any Product Types!!")
newErr := fmt.Errorf("Failed to Get the VMSpec info list!! : [%v]", err)
cblogger.Error(newErr.Error())
return irs.ImageInfo{}, newErr
}

var foundImgId string
for _, productType := range result.Listavailableproducttypesresponse.ProductTypes {
// cblogger.Info("# Search criteria of Image Template ID : ", imageIID.SystemId)
if strings.EqualFold(productType.TemplateId, imageIID.SystemId) {
foundImgId = productType.TemplateId
resultImageInfo = mappingImageInfo(productType)
break
for _, image := range imageListResult {
if strings.EqualFold(image.Name, imageIID.SystemId) {
return *image, nil
}
}
if strings.EqualFold(foundImgId, "") {
return irs.ImageInfo{}, fmt.Errorf("Failed to Find Any Image(Template) info with the ID.")
}
return resultImageInfo, nil
return irs.ImageInfo{}, errors.New("Failed to find the VM Image info : '" + imageIID.SystemId)
}

func (imageHandler *KtCloudImageHandler) ListImage() ([]*irs.ImageInfo, error) {
cblogger.Info("KT Cloud cloud driver: called ListImage()!")

var vmImageList []*irs.ImageInfo
zoneId := imageHandler.RegionInfo.Zone

result, err := imageHandler.Client.ListAvailableProductTypes(zoneId)
result, err := imageHandler.Client.ListAvailableProductTypes(imageHandler.RegionInfo.Zone)
if err != nil {
cblogger.Error("Failed to Get List of Available Product Types: %s", err)
return []*irs.ImageInfo{}, err
Expand All @@ -94,35 +77,79 @@ func (imageHandler *KtCloudImageHandler) ListImage() ([]*irs.ImageInfo, error) {
if len(result.Listavailableproducttypesresponse.ProductTypes) < 1 {
return []*irs.ImageInfo{}, errors.New("Failed to Find Product Types!!")
}

// ### In order to remove the list of identical duplicates over and over again
tempID := ""
var vmImageInfoMap = make(map[string]*irs.ImageInfo) // Map to track unique VMSpec Info.
for _, productType := range result.Listavailableproducttypesresponse.ProductTypes {
// if (tempID == "") || (productType.Templateid != tempID) {
if productType.TemplateId != tempID {
imageInfo := mappingImageInfo(productType)
vmImageList = append(vmImageList, &imageInfo)

tempID = productType.TemplateId
// cblogger.Infof("\nImage Template Id : " + tempID)
// ### Caution!!) If the diskofferingid value exists, additional data disks are created.(=> So Not include to image list for 'Correct RootDiskSize')
if strings.EqualFold(productType.DiskOfferingId, "") {
imageInfo := mappingImageInfo(&productType)
if _, exists := vmImageInfoMap[imageInfo.Name]; exists {
// break
} else {
vmImageInfoMap[imageInfo.Name] = &imageInfo
}
}
}
cblogger.Info("# Supported Image Product Count : ", len(vmImageList))
return vmImageList, nil

// Convert the map to a list
var vmImageInfoList []*irs.ImageInfo
for _, imageInfo := range vmImageInfoMap {
vmImageInfoList = append(vmImageInfoList, imageInfo)
}
// cblogger.Info("# Supported Image Product Count : ", len(vmImageInfoList))
return vmImageInfoList, nil
}

func mappingImageInfo(ktServerProductType ktsdk.ProductTypes) irs.ImageInfo {
cblogger.Info("KT Cloud Cloud Driver: called mappingImageInfo()!")
func mappingImageInfo(productType *ktsdk.ProductTypes) irs.ImageInfo {
// cblogger.Info("KT Cloud Cloud Driver: called mappingImageInfo()!")
// cblogger.Info("\n\n### productType : ")
// spew.Dump(productType)
// cblogger.Info("\n")

var osPlatform irs.OSPlatform
if productType.TemplateDesc != "" {
if strings.Contains(productType.TemplateDesc, "WIN ") {
osPlatform = irs.Windows
} else {
osPlatform = irs.Linux_UNIX
}
} else {
osPlatform = irs.PlatformNA
}

var imageStatus irs.ImageStatus
if productType.ProductState != "" {
if strings.EqualFold(productType.ProductState, "available") {
imageStatus = irs.ImageAvailable
} else {
imageStatus = irs.ImageUnavailable
}
} else {
imageStatus = irs.ImageNA
}

diskSize := getImageDiskSize(productType.DiskOfferingDesc)

imageInfo := irs.ImageInfo{
// NOTE!! : TemplateId -> Image Name (TemplateId as Image Name)
IId: irs.IID{ktServerProductType.TemplateId, ktServerProductType.TemplateId},
GuestOS: ktServerProductType.TemplateDesc,
Status: ktServerProductType.ProductState,
IId: irs.IID{NameId: productType.TemplateId, SystemId: productType.TemplateId},
GuestOS: productType.TemplateDesc,
Status: productType.ProductState,

Name: productType.TemplateId,
OSArchitecture: irs.ArchitectureNA,
OSPlatform: osPlatform,
OSDistribution: productType.TemplateDesc,
OSDiskType: "NA",
OSDiskSizeInGB: diskSize,
ImageStatus: imageStatus,
}

// Since KT Cloud has different supported images for each zone, zone information is also presented.
keyValueList := []irs.KeyValue{
{Key: "Zone", Value: ktServerProductType.ZoneDesc},
{Key: "ProductType", Value: productType.Product},
{Key: "Zone", Value: productType.ZoneDesc},
}
imageInfo.KeyValueList = keyValueList
return imageInfo
Expand Down Expand Up @@ -199,3 +226,18 @@ func (imageHandler *KtCloudImageHandler) getKTProductType(imageIID irs.IID) (*kt
}
return nil, nil
}

func getImageDiskSize(sizeGB string) (string) {
// sizeGB Ex : "100GB"
re := regexp.MustCompile(`(\d+)GB`)
matches := re.FindStringSubmatch(sizeGB) // Find the match

var diskSize string
if len(matches) > 1 {
diskSize = matches[1] // Extract only the numeric part
}
if strings.EqualFold(diskSize, "") {
diskSize = "-1"
}
return diskSize // diskSize Ex : "100"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// KT Cloud RegionZone Handler
//
// Created by ETRI, 2023.10.
// Updated by ETRI, 2025.02.
//==================================================================================================

package resources
Expand Down Expand Up @@ -39,10 +40,10 @@ type KtRegionInfo struct {
func getSupportedRegions() []KtRegionInfo {
regionInfoList := []KtRegionInfo {
{ RegionCode: "KOR-Seoul",
RegionName: "서울",
RegionName: "Seoul",
},
{ RegionCode: "KOR-Central",
RegionName: "천안",
RegionName: "Cheonan",
},
}
return regionInfoList
Expand Down Expand Up @@ -78,6 +79,7 @@ func (regionZoneHandler *KtCloudRegionZoneHandler) ListRegionZone() ([]*irs.Regi
regionZoneInfo := irs.RegionZoneInfo{
Name: region.RegionCode,
DisplayName: region.RegionName,
CSPDisplayName: region.RegionName,
}

zoneInfoList, err := regionZoneHandler.getZoneInfoList(region.RegionCode)
Expand Down Expand Up @@ -129,6 +131,7 @@ func (regionZoneHandler KtCloudRegionZoneHandler) GetRegionZone(regionCode strin
regionZoneInfo = irs.RegionZoneInfo {
Name: region.RegionCode,
DisplayName: region.RegionName,
CSPDisplayName: region.RegionName,
}
break
}
Expand Down Expand Up @@ -235,6 +238,7 @@ func (regionZoneHandler KtCloudRegionZoneHandler) getZoneInfoList(regionCode str
zoneInfo := irs.ZoneInfo{
Name: zone.ID,
DisplayName: zone.Name,
CSPDisplayName: zone.Name,
}
if strings.EqualFold(zone.AllocationState, "Enabled") {
zoneInfo.Status = irs.ZoneAvailable
Expand Down
Loading

0 comments on commit 37f35ea

Please sign in to comment.