Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 1396 metadata vmspec for tencent #1413

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 247 additions & 41 deletions cloud-control-manager/cloud-driver/drivers/gcp/resources/ImageHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ package resources
import (
"context"
"errors"
"regexp"
"strconv"
"strings"

call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log"
idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces"
irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources"
"github.com/sirupsen/logrus"
compute "google.golang.org/api/compute/v1"
)

Expand All @@ -30,6 +32,23 @@ type GCPImageHandler struct {
Credential idrv.CredentialInfo
}

var arrImageProjectList = []string{
"gce-uefi-images", // 보안 VM을 지원하는 이미지

//보안 VM을 지원하지 않는 이미지들
"centos-cloud",
"cos-cloud",
"coreos-cloud",
"debian-cloud",
"rhel-cloud",
"rhel-sap-cloud",
"suse-cloud",
"suse-sap-cloud",
"ubuntu-os-cloud",
"windows-cloud",
"windows-sql-cloud",
}

/*
이미지를 생성할 때 GCP 같은 경우는 내가 생성한 이미지에서만 리스트를 가져 올 수 있다.
퍼블릭 이미지를 가져 올 수 없다.
Expand Down Expand Up @@ -76,26 +95,17 @@ func (imageHandler *GCPImageHandler) ListImage() ([]*irs.ImageInfo, error) {
*/

// 리스트의 경우 Name 기반으로 조회해서 처리하기에는 너무 느리기 때문에 직접 컨버팅함.
// filter := "NOT deprecated:*" 적용
// 아래와 같이 deprecated가 있는 image는 다른 image로 대체된 것임
//
// "deprecated": {
// "state": "DEPRECATED",
// "replacement": "https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-2204-jammy-v20241218"
// },
func (imageHandler *GCPImageHandler) ListImage() ([]*irs.ImageInfo, error) {
cblogger.Debug("Retrieve All VM Images")

//https://cloud.google.com/compute/docs/images?hl=ko
arrImageProjectList := []string{
"gce-uefi-images", // 보안 VM을 지원하는 이미지

//보안 VM을 지원하지 않는 이미지들
"centos-cloud",
"cos-cloud",
"coreos-cloud",
"debian-cloud",
"rhel-cloud",
"rhel-sap-cloud",
"suse-cloud",
"suse-sap-cloud",
"ubuntu-os-cloud",
"windows-cloud",
"windows-sql-cloud",
}

var imageList []*irs.ImageInfo

Expand All @@ -120,6 +130,8 @@ func (imageHandler *GCPImageHandler) ListImage() ([]*irs.ImageInfo, error) {
for _, projectId := range arrImageProjectList {
cblogger.Infof("Processing image list owned by [%s] project", projectId)

// filter := "NOT deprecated:*" // deprecated가 있는 항목은 다른 image로 대체된 것임
// req = imageHandler.Client.Images.List(projectId).Filter(filter)
//첫번째 호출
req = imageHandler.Client.Images.List(projectId)
res, err = req.Do()
Expand Down Expand Up @@ -260,6 +272,77 @@ func (imageHandler *GCPImageHandler) GetImage(imageIID irs.IID) (irs.ImageInfo,
return imageInfo, nil
}

// getImage by name
//
// ubuntu-1204-precise-v20141031 // OBSOLETE -> rejected, error
// ubuntu-1804-bionic-v20220505 //DEPRECATED -> create but worning
// ubuntu-2204-jammy-v20241218 // ACTIVE
func (imageHandler *GCPImageHandler) GetImageN(imageName string) (irs.ImageInfo, error) {
projectId := ""
imageInfo := irs.ImageInfo{}

cblogger.SetLevel(logrus.InfoLevel)

targetOs := strings.Split(imageName, "-")[0]
cblogger.Debug("targetOs = ", targetOs)

// logger for HisCall
callogger := call.GetLogger("HISCALL")
callLogInfo := call.CLOUDLOGSCHEMA{
CloudOS: call.GCP,
RegionZone: imageHandler.Region.Zone,
ResourceType: call.VMIMAGE,
ResourceName: imageName,
CloudOSAPI: "Images.Get()",
ElapsedTime: "",
ErrorMSG: "",
}
callLogStart := call.Start()

// ubuntu, window ....
for _, imgageProjectId := range arrImageProjectList {
if strings.Contains(imgageProjectId, targetOs) {
projectId = imgageProjectId
break
}
}
cblogger.Debug("projectId = ", projectId)
// if found
if projectId != "" {
gcpImage, err := imageHandler.Client.Images.Get(projectId, imageName).Do()
callLogInfo.ElapsedTime = call.Elapsed(callLogStart)
if err != nil {
callLogInfo.ErrorMSG = err.Error()
callogger.Info(call.String(callLogInfo))
cblogger.Info("try to get image by projectId ", projectId)
}

if gcpImage != nil {
imageInfo = mappingImageInfo(gcpImage)
return imageInfo, nil
}
}

callogger.Info("image not found at specific project url. try all project.")
// if not. query all
for _, imgageProjectId := range arrImageProjectList {
gcpImage, err := imageHandler.Client.Images.Get(imgageProjectId, imageName).Do()
callLogInfo.ElapsedTime = call.Elapsed(callLogStart)
if err != nil {
callLogInfo.ErrorMSG = err.Error()
callogger.Info(call.String(callLogInfo))
cblogger.Info("try to get image by all projectId ", projectId)
continue
}
imageInfo = mappingImageInfo(gcpImage)
return imageInfo, nil
}

// not found Image
return imageInfo, errors.New("Image not found." + imageName)

}

// 이슈 #239에 의해 Name 기반에서 URL 기반으로 로직 변경
// 전체 목록에서 이미지 정보를 조회 함. - 위의 GetImage()로 검색되지 않는 경우가 발생하면 이 함수를 이용할 것.
func (imageHandler *GCPImageHandler) GetImageByUrl(imageIID irs.IID) (irs.ImageInfo, error) {
Expand Down Expand Up @@ -619,41 +702,164 @@ func (imageHandler *GCPImageHandler) FindImageInfo(projectId string, reqImageNam
}
*/

// @TODO : 나중에 시스템아이디 값 변경해야 함.(현재 이미지 핸들러는 이름 기반으로 변경되어 있기 때문...)
func mappingImageInfo(imageInfo *compute.Image) irs.ImageInfo {
//lArr := strings.Split(imageInfo.Licenses[0], "/")
//os := lArr[len(lArr)-1]

//cblogger.Info("===================================")

imageList := irs.ImageInfo{
IId: irs.IID{
NameId: imageInfo.SelfLink,
//NameId: imageInfo.Name, //2020-07-23 이미지 핸들러는 아직 생성 기능을 지원하지 않기 때문에 NameId대신 SystemId로 통일
//SystemId: imageInfo.Name, //자체 기능 구현을 위해 Name 기반으로 리턴함. - 2020-05-14 다음 버전에 적용 예정
SystemId: imageInfo.SelfLink, //2020-05-14 카푸치노는 VM 생성시 URL 방식을 사용하기 때문에 임의로 맞춤(이미지 핸들러의 다른 함수에는 적용 못함)
//SystemId: strconv.FormatUint(imageInfo.Id, 10), //이 값으로는 VM생성 안됨.
//"description": "Canonical, Ubuntu, 12.04 LTS, amd64 precise image built on 2016-03-02",
//"description": "Microsoft, Windows Server, version 1709 Core for Containers (Beta), Server Core, x64 built on 2017-12-12",
//"description": "Canonical, Ubuntu, 18.04 LTS, amd64 bionic image built on 2022-05-05, supports Shielded VM features",

//SystemId: imageInfo.SourceImage, //imageInfo.SourceImage의 경우 공백("")인 경우가 있음
},
//Id: strconv.FormatUint(imageInfo.Id, 10),
//Id: imageInfo.SelfLink,
//Name: imageInfo.Name,
GuestOS: imageInfo.Family,
Status: imageInfo.Status,
KeyValueList: []irs.KeyValue{
{"Name", imageInfo.Name},
{"SourceImage", imageInfo.SourceImage}, // VM생성 시에는 SourceImage나 SelfLink 값을 이용해야 함.
{"SourceType", imageInfo.SourceType},
{"SelfLink", imageInfo.SelfLink},
//{"GuestOsFeature", imageInfo.GuestOsFeatures[0].Type}, //Data가 없는 경우가 있어서 필요한 경우 체크해야 함.
{"Family", imageInfo.Family},
{"DiskSizeGb", strconv.FormatInt(imageInfo.DiskSizeGb, 10)},
},
distribution := extractOsDistribution(imageInfo)
imageStatus := extractImageAvailability(imageInfo)

if imageInfo.Deprecated != nil {
gcpImageState := imageInfo.Deprecated.State
distribution = distribution + ". ImageState : " + gcpImageState
if imageInfo.Deprecated.Replacement != "" {
gcpImageReplacement := imageInfo.Deprecated.Replacement
distribution = distribution + ", Replacement : " + gcpImageReplacement
}
}

// 2024-12-23 ImageInfo changed for meta. IID, GuestOS, Status deprecated.
returnImageInfo := irs.ImageInfo{
// IId: irs.IID{
// NameId: imageInfo.SelfLink,
// SystemId: imageInfo.SelfLink,
// },
// GuestOS: imageInfo.Family,
// Status: imageInfo.Status,

Name: imageInfo.Name,
OSArchitecture: extractOsArchitecture(imageInfo),
OSPlatform: extractOsPlatform(imageInfo), // imageInfo.Description
OSDistribution: distribution,
OSDiskType: "NA",
OSDiskSizeInGB: strconv.FormatInt(imageInfo.DiskSizeGb, 10),
ImageStatus: imageStatus,
}

imageInfo.ShieldedInstanceInitialState = nil // 너무 길어 임시로 주석처리함.
convertKeyValueList, err := ConvertKeyValueList(imageInfo)
if err != nil {
returnImageInfo.KeyValueList = nil
cblogger.Error(err)
}
returnImageInfo.KeyValueList = convertKeyValueList

return returnImageInfo

}

// OS Platform (contains description or family, name)
// "name": "ubuntu-1804-bionic-arm64-v20220712",
func extractOsPlatform(orgImage *compute.Image) irs.OSPlatform {
platformInfo := orgImage.Name

osPlatform := irs.PlatformNA
if strings.Contains(strings.ToLower(platformInfo), "windows") {
osPlatform = irs.Windows
} else if strings.Contains(strings.ToLower(platformInfo), "ubuntu") ||
strings.Contains(strings.ToLower(platformInfo), "linux") ||
strings.Contains(strings.ToLower(platformInfo), "centos") ||
strings.Contains(strings.ToLower(platformInfo), "debian") ||
strings.Contains(strings.ToLower(platformInfo), "fedora") ||
strings.Contains(strings.ToLower(platformInfo), "rhel") ||
strings.Contains(strings.ToLower(platformInfo), "rocky") ||
strings.Contains(strings.ToLower(platformInfo), "unix") {
osPlatform = irs.Linux_UNIX
}

// "centos-cloud",
// "cos-cloud",
// "coreos-cloud",
// "debian-cloud",
// "rhel-cloud",
// "rhel-sap-cloud",
// "suse-cloud",
// "suse-sap-cloud",
// "ubuntu-os-cloud",
// "windows-cloud",
// "windows-sql-cloud",
return osPlatform
}

// OS Architecture
// 2024-12 MAC OS not supported(ARM64, X86_64 from compute.Image)
func extractOsArchitecture(orgImage *compute.Image) irs.OSArchitecture {
// if Architecture exists
if orgImage.Architecture != "" {
arch := strings.ToLower(orgImage.Architecture)
switch arch {
case "arm64":
return irs.OSArchitecture(orgImage.Architecture)
case "x86_64", "amd64":
return irs.OSArchitecture(orgImage.Architecture)
}
}

return imageList
//
description := orgImage.Description
archRegex := regexp.MustCompile(`(?i)\b(mac|x64|amd64|x86|arm64|arm)\b`)

archMatch := archRegex.FindString(description)

osArchitecture := irs.ArchitectureNA
switch archMatch {
case "arm64":
if strings.Contains(strings.ToLower(description), "mac") {
osArchitecture = irs.ARM64_MAC
} else {
osArchitecture = irs.ARM64
}
case "x64", "amd64":
if strings.Contains(strings.ToLower(description), "mac") {
osArchitecture = irs.X86_64_MAC
} else {
osArchitecture = irs.X86_64
}
default:
osArchitecture = irs.ArchitectureNA
}

return osArchitecture
}

func extractOsDistribution(orgImage *compute.Image) string {
if orgImage.Description != "" {
return orgImage.Description
} else {
return orgImage.Name
}
}

// Image Status 추출
func extractImageAvailability(orgImage *compute.Image) irs.ImageStatus {
//imageStatus := irs.ImageNA
imageStatus := irs.ImageAvailable

// Image를 만들 때 체크하는 상태로 보임.
//status := orgImage.Status
// if strings.Contains(strings.ToUpper(status), "READY") {
// imageStatus = irs.ImageAvailable
// } else if strings.Contains(strings.ToUpper(status), "FAILED") ||
// strings.Contains(strings.ToUpper(status), "PENDING") {
// imageStatus = irs.ImageUnavailable
// }

// deprecated 가 있는 경우 deprecated.state 가 ACTIVE, DEPRECATED, OBSOLETE, DELETED
// ACTIVE 는 deprecated가 없음.
// DEPRECATED인 경우 생성은 되나, warning이 발생함.
// OBSOLETE, DELETED는 생성도 안되고 error 발생함.
if orgImage.Deprecated != nil { // deprecated 필드가 nil인 경우
if orgImage.Deprecated.State == "OBSOLETE" || orgImage.Deprecated.State == "DELETED" {
imageStatus = irs.ImageUnavailable
}
}
return imageStatus
}

// windows os 여부 return
Expand Down
Loading
Loading