diff --git a/cloud-control-manager/cloud-driver/drivers/gcp/GCPDriver.go b/cloud-control-manager/cloud-driver/drivers/gcp/GCPDriver.go index 20fd1e1af..8f73d3e8a 100644 --- a/cloud-control-manager/cloud-driver/drivers/gcp/GCPDriver.go +++ b/cloud-control-manager/cloud-driver/drivers/gcp/GCPDriver.go @@ -49,6 +49,7 @@ func (GCPDriver) GetDriverCapability() idrv.DriverCapabilityInfo { drvCapabilityInfo.VPCHandler = true drvCapabilityInfo.DiskHandler = false drvCapabilityInfo.MyImageHandler = false + drvCapabilityInfo.RegionZoneHandler = false drvCapabilityInfo.ClusterHandler = true return drvCapabilityInfo @@ -89,10 +90,11 @@ func (driver *GCPDriver) ConnectCloud(connectionInfo idrv.ConnectionInfo) (icon. SecurityGroupClient: VMClient, // VNetClient: VMClient, // VNicClient: VMClient, - SubnetClient: VMClient, - VMSpecHandler: VMClient, - VPCHandler: VMClient, - ContainerClient: containerClient, + SubnetClient: VMClient, + VMSpecClient: VMClient, + VPCClient: VMClient, + RegionZoneClient: VMClient, + ContainerClient: containerClient, } //fmt.Println("################## resource ConnectionInfo ##################") @@ -173,4 +175,3 @@ func getContainerClient(credential idrv.CredentialInfo) (context.Context, *conta return ctx, containerClient, nil } - diff --git a/cloud-control-manager/cloud-driver/drivers/gcp/connect/GCP_CloudConnection.go b/cloud-control-manager/cloud-driver/drivers/gcp/connect/GCP_CloudConnection.go index 403bc842b..bcfc1d42a 100644 --- a/cloud-control-manager/cloud-driver/drivers/gcp/connect/GCP_CloudConnection.go +++ b/cloud-control-manager/cloud-driver/drivers/gcp/connect/GCP_CloudConnection.go @@ -41,8 +41,9 @@ type GCPCloudConnection struct { VNetClient *compute.Service VNicClient *compute.Service SubnetClient *compute.Service - VMSpecHandler *compute.Service - VPCHandler *compute.Service + VMSpecClient *compute.Service + VPCClient *compute.Service + RegionZoneClient *compute.Service ContainerClient *container.Service } @@ -135,3 +136,9 @@ func (cloudConn *GCPCloudConnection) CreateClusterHandler() (irs.ClusterHandler, func (cloudConn *GCPCloudConnection) CreateAnyCallHandler() (irs.AnyCallHandler, error) { return nil, errors.New("GCP Driver: not implemented") } + +func (cloudConn *GCPCloudConnection) CreateRegionZoneHandler() (irs.RegionZoneHandler, error) { + cblogger.Info("GCP Cloud Driver: called CreateRegionZoneHandler()!") + regionZoneHandler := gcprs.GCPRegionZoneHandler{cloudConn.Region, cloudConn.Ctx, cloudConn.RegionZoneClient, cloudConn.Credential} + return ®ionZoneHandler, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/gcp/main/Test_Resources.go b/cloud-control-manager/cloud-driver/drivers/gcp/main/Test_Resources.go index 68b60ca8e..1a284f1df 100644 --- a/cloud-control-manager/cloud-driver/drivers/gcp/main/Test_Resources.go +++ b/cloud-control-manager/cloud-driver/drivers/gcp/main/Test_Resources.go @@ -1793,7 +1793,71 @@ func handleMyImage() { } } -//import "path/filepath" +func handleRegionZone() { + cblogger.Debug("Start RegionZoneHandler Resource Test") + + ResourceHandler, err := testconf.GetResourceHandler("RegionZone") + if err != nil { + panic(err) + } + handler := ResourceHandler.(irs.RegionZoneHandler) + + for { + fmt.Println("RegionZoneHandler Management") + fmt.Println("0. Quit") + fmt.Println("1. RegionZone List") + fmt.Println("2. OrgRegion List") + fmt.Println("3. OrgZone List") + + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + return + + case 1: + result, err := handler.ListRegionZone() + if err != nil { + cblogger.Infof(" RegionZone 목록 조회 실패 : ", err) + } else { + cblogger.Info("RegionZone 목록 조회 결과") + cblogger.Info(result) + cblogger.Info("출력 결과 수 : ", len(result)) + spew.Dump(result) + //spew.Dump(result) + + //조회및 삭제 테스트를 위해 리스트의 첫번째 정보의 ID를 요청ID로 자동 갱신함. + // if result != nil { + // diskReqInfo.IId = result[0].IId // 조회 및 삭제를 위해 생성된 ID로 변경 + // } + } + + case 2: + result, err := handler.ListOrgRegion() + if err != nil { + cblogger.Infof("[%s] ListOrgZone 조회 실패 : ", err) + } else { + cblogger.Infof("[%s] ListOrgZone 조회 성공 : ", result) + spew.Dump(result) + } + + case 3: + result, err := handler.ListOrgZone() + if err != nil { + cblogger.Infof("[%s] ListOrgZone 조회 실패 : ", err) + } else { + cblogger.Infof("[%s] ListOrgZone 조회 성공 : ", result) + spew.Dump(result) + } + } + } + } +} func main() { cblogger.Info("GCP Resource Test") @@ -1802,10 +1866,11 @@ func main() { //handleImage() //AMI //handleKeyPair() //handleSecurity() - handleVM() + //handleVM() //handleLoadBalancer() //handleDisk() //handleMyImage() + handleRegionZone() //cblogger.Info(filepath.Join("a/b", "\\cloud-driver-libs\\.ssh-gcp\\")) //cblogger.Info(filepath.Join("\\cloud-driver-libs\\.ssh-gcp\\", "/b/c/d")) } diff --git a/cloud-control-manager/cloud-driver/drivers/gcp/main/conf/Test_Config.go b/cloud-control-manager/cloud-driver/drivers/gcp/main/conf/Test_Config.go index 3fc35164a..8dce50180 100644 --- a/cloud-control-manager/cloud-driver/drivers/gcp/main/conf/Test_Config.go +++ b/cloud-control-manager/cloud-driver/drivers/gcp/main/conf/Test_Config.go @@ -44,8 +44,8 @@ type Config struct { } // 환경변수 : GOOGLE_APPLICATION_CREDENTIALS - 인증용 .json 파일의 위치 -//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 -//(예) ImageHandler.go -> "Image" +// handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +// (예) ImageHandler.go -> "Image" func GetResourceHandler(handlerType string) (interface{}, error) { var cloudDriver idrv.CloudDriver cloudDriver = new(gcpdrv.GCPDriver) @@ -100,6 +100,8 @@ func GetResourceHandler(handlerType string) (interface{}, error) { resourceHandler, err = cloudConnection.CreateVMSpecHandler() case "VPCHandler": resourceHandler, err = cloudConnection.CreateVPCHandler() + case "RegionZone": + resourceHandler, err = cloudConnection.CreateRegionZoneHandler() } if err != nil { diff --git a/cloud-control-manager/cloud-driver/drivers/gcp/resources/CommonHandler.go b/cloud-control-manager/cloud-driver/drivers/gcp/resources/CommonHandler.go index 94b16ba51..a15807f35 100644 --- a/cloud-control-manager/cloud-driver/drivers/gcp/resources/CommonHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/gcp/resources/CommonHandler.go @@ -22,11 +22,11 @@ import ( "sync" "time" - "github.com/davecgh/go-spew/spew" cblog "github.com/cloud-barista/cb-log" 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/davecgh/go-spew/spew" "github.com/sirupsen/logrus" compute "google.golang.org/api/compute/v1" container "google.golang.org/api/container/v1" @@ -512,6 +512,46 @@ func WaitContainerOperationDone(client *container.Service, project string, regio return nil } +// region에 해당하는 zone 목록 조회 +func GetZoneListByRegion(client *compute.Service, regionUrl string) (*compute.ZoneList, error) { + projectId := "" + regionName := "" + + arrLink := strings.Split(regionUrl, "/") + if len(arrLink) > 0 { + regionName = arrLink[len(arrLink)-1] + for pos, item := range arrLink { + if strings.EqualFold(item, "projects") { + projectId = arrLink[pos+1] + break + } + } + } + cblogger.Infof("projectId : [%s] / imageName : [%s]", projectId, regionName) + if projectId == "" { + return nil, errors.New("ProjectId information not found in URL.") + } + + resp, err := client.Zones.List(projectId).Do() + + if err != nil { + cblogger.Error(err) + return nil, err + } + return resp, nil + +} + +// Available or Unavailable 로 return +// Status of the zone, either UP or DOWN. +func GetZoneStatus(status string) irs.ZoneStatus { + if status == "UP" { + return irs.ZoneAvailable + } else { + return irs.ZoneUnavailable + } +} + /* ### container operation ### (*container.Operation)(0xc0003d6a00)({ diff --git a/cloud-control-manager/cloud-driver/drivers/gcp/resources/RegionZoneHandler.go b/cloud-control-manager/cloud-driver/drivers/gcp/resources/RegionZoneHandler.go new file mode 100644 index 000000000..a74f6afd8 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/gcp/resources/RegionZoneHandler.go @@ -0,0 +1,235 @@ +package resources + +import ( + "context" + "errors" + "fmt" + "reflect" + + 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" + compute "google.golang.org/api/compute/v1" +) + +type GCPRegionZoneHandler struct { + Region idrv.RegionInfo + Ctx context.Context + Client *compute.Service + Credential idrv.CredentialInfo +} + +// required Compute Engine IAM ROLE : compute.regions.list +func (regionZoneHandler *GCPRegionZoneHandler) ListRegionZone() ([]*irs.RegionZoneInfo, error) { + var regionZoneInfoList []*irs.RegionZoneInfo + projectID := regionZoneHandler.Credential.ProjectID + //prefix := "https://www.googleapis.com/compute/v1/projects/" + projectID + //GET https://compute.googleapis.com/compute/v1/projects/{project}/regions + + // logger for HisCall + callogger := call.GetLogger("HISCALL") + callLogInfo := call.CLOUDLOGSCHEMA{ + CloudOS: call.GCP, + RegionZone: regionZoneHandler.Region.Zone, + ResourceType: call.REGIONZONE, + ResourceName: "", + CloudOSAPI: "List()", + ElapsedTime: "", + ErrorMSG: "", + } + + callLogStart := call.Start() + resp, err := regionZoneHandler.Client.Regions.List(projectID).Do() + callLogInfo.ElapsedTime = call.Elapsed(callLogStart) + callogger.Info(call.String(callLogInfo)) + if err != nil { + callLogInfo.ErrorMSG = err.Error() + cblogger.Error(err) + return regionZoneInfoList, err + } + if resp == nil { + return nil, errors.New("Not Found : Region Zone information not found") + } + + for _, item := range resp.Items { + info := irs.RegionZoneInfo{} + info.Name = item.Name + info.DisplayName = item.Name + + // ZoneList + var zoneInfoList []*irs.ZoneInfo + resultZones, err := GetZoneListByRegion(regionZoneHandler.Client, item.SelfLink) + if err != nil { + // failed to get ZoneInfo by region + } + for _, zone := range resultZones.Items { + zoneInfo := irs.ZoneInfo{} + zoneInfo.Name = zone.Name + zoneInfo.DisplayName = zone.Name + zoneInfo.Status = GetZoneStatus(zone.Status) + + zoneInfoList = append(zoneInfoList, &zoneInfo) + } + + // 가져온 결과에서 Zone 정보 추출 : Zone의 status를 찾지 못해 조회하는 것으로 변경 + // for _, zoneUrl := range item.Zones { + // // "https://www.googleapis.com/compute/v1/projects/csta-349809/zones/northamerica-northeast1-a" + // startIndex := strings.Index(zoneUrl, "/zones/") + len("/zones/") + // if startIndex < len("/zones/") { + // //fmt.Println("Invalid URL:", zoneUrl) + // cblogger.Error("Invalid URL:", zoneUrl) + // continue + // } + // zone := zoneUrl[startIndex:] + + // zoneInfo := irs.ZoneInfo{} + // zoneInfo.Name = zone + // zoneInfo.DisplayName = zone + + // zoneInfoList = append(zoneInfoList, &zoneInfo) + // } + + keyValueList := []irs.KeyValue{} + itemType := reflect.TypeOf(item) + if itemType.Kind() == reflect.Ptr { + itemType = itemType.Elem() + } + itemValue := reflect.ValueOf(item) + if itemValue.Kind() == reflect.Ptr { + itemValue = itemValue.Elem() + } + numFields := itemType.NumField() + + // 속성 이름과 값을 출력합니다. + for i := 0; i < numFields; i++ { + field := itemType.Field(i) + value := itemValue.Field(i).Interface() + + keyValue := irs.KeyValue{} + keyValue.Key = field.Name + keyValue.Value = fmt.Sprintf("%v", value) + keyValueList = append(keyValueList, keyValue) + } + info.KeyValueList = keyValueList + + regionZoneInfoList = append(regionZoneInfoList, &info) + } + + return regionZoneInfoList, nil +} +func (regionZoneHandler *GCPRegionZoneHandler) ListOrgRegion() (string, error) { + + projectID := regionZoneHandler.Credential.ProjectID + + callogger := call.GetLogger("HISCALL") + callLogInfo := call.CLOUDLOGSCHEMA{ + CloudOS: call.GCP, + RegionZone: regionZoneHandler.Region.Zone, + ResourceType: call.REGIONZONE, + ResourceName: "", + CloudOSAPI: "List()", + ElapsedTime: "", + ErrorMSG: "", + } + callLogStart := call.Start() + resp, err := regionZoneHandler.Client.Regions.List(projectID).Do() + callLogInfo.ElapsedTime = call.Elapsed(callLogStart) + + if err != nil { + callLogInfo.ErrorMSG = err.Error() + callogger.Info(call.String(callLogInfo)) + cblogger.Error(err) + return "", err + } + callogger.Info(call.String(callLogInfo)) + j, _ := resp.MarshalJSON() + + //callogger.Info(j) + return string(j), err +} +func (regionZoneHandler *GCPRegionZoneHandler) ListOrgZone() (string, error) { + projectID := regionZoneHandler.Credential.ProjectID + + callogger := call.GetLogger("HISCALL") + callLogInfo := call.CLOUDLOGSCHEMA{ + CloudOS: call.GCP, + RegionZone: regionZoneHandler.Region.Zone, + ResourceType: call.REGIONZONE, + ResourceName: "", + CloudOSAPI: "List()", + ElapsedTime: "", + ErrorMSG: "", + } + callLogStart := call.Start() + + resp, err := regionZoneHandler.Client.Zones.List(projectID).Do() + callLogInfo.ElapsedTime = call.Elapsed(callLogStart) + + if err != nil { + callLogInfo.ErrorMSG = err.Error() + callogger.Info(call.String(callLogInfo)) + cblogger.Error(err) + return "", err + } + callogger.Info(call.String(callLogInfo)) + j, _ := resp.MarshalJSON() + + //callogger.Info(j) + return string(j), err +} + +/** +// Region 조회 성공 시 result +{ + "kind": "compute#regionList", + "id": "projects/csta-349809/regions", + "items": [ + { + "kind": "compute#region", + "id": "1510", + "creationTimestamp": "1969-12-31T16:00:00.000-08:00", + "name": "europe-west8", + "description": "europe-west8", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/projects/csta-349809/zones/europe-west8-a", + "https://www.googleapis.com/compute/v1/projects/csta-349809/zones/europe-west8-b", + "https://www.googleapis.com/compute/v1/projects/csta-349809/zones/europe-west8-c" + ], + "quotas": [ + // CPUS, DISKS_TOTAL_GB ... 많아서 생략 + ], + "selfLink": "https://www.googleapis.com/compute/v1/projects/csta-349809/regions/europe-west8", + "supportsPzs": false + } + ], + "selfLink": "https://www.googleapis.com/compute/v1/projects/csta-349809/regions" +} + + +// Zone 조회 성공 시 +{ + "kind": "compute#zone", + "id": "2231", + "creationTimestamp": "1969-12-31T16:00:00.000-08:00", + "name": "us-east1-b", + "description": "us-east1-b", + "status": "UP", + "region": "https://www.googleapis.com/compute/v1/projects/csta-349809/regions/us-east1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/csta-349809/zones/us-east1-b", + "availableCpuPlatforms": [ + "Intel Broadwell", + "Intel Cascade Lake", + "AMD Genoa", + "Intel Haswell", + "Intel Ice Lake", + "Intel Ivy Bridge", + "AMD Milan", + "AMD Rome", + "Intel Sandy Bridge", + "Intel Sapphire Rapids", + "Intel Skylake" + ], + "supportsPzs": false +} +**/ diff --git a/cloud-control-manager/cloud-driver/interfaces/CloudDriver.go b/cloud-control-manager/cloud-driver/interfaces/CloudDriver.go index c1170c4b0..a1946f931 100644 --- a/cloud-control-manager/cloud-driver/interfaces/CloudDriver.go +++ b/cloud-control-manager/cloud-driver/interfaces/CloudDriver.go @@ -19,15 +19,16 @@ type DriverCapabilityInfo struct { ImageHandler bool // support: true, do not support: false VPCHandler bool // support: true, do not support: false //VNetworkHandler bool // support: true, do not support: false - SecurityHandler bool // support: true, do not support: false - KeyPairHandler bool // support: true, do not support: false - VNicHandler bool // support: true, do not support: false - PublicIPHandler bool // support: true, do not support: false - VMHandler bool // support: true, do not support: false - VMSpecHandler bool // support: true, do not support: false - DiskHandler bool // support: true, do not support: false - MyImageHandler bool // support: true, do not support: false - ClusterHandler bool // support: true, do not support: false + SecurityHandler bool // support: true, do not support: false + KeyPairHandler bool // support: true, do not support: false + VNicHandler bool // support: true, do not support: false + PublicIPHandler bool // support: true, do not support: false + VMHandler bool // support: true, do not support: false + VMSpecHandler bool // support: true, do not support: false + DiskHandler bool // support: true, do not support: false + MyImageHandler bool // support: true, do not support: false + RegionZoneHandler bool + ClusterHandler bool // support: true, do not support: false FIXED_SUBNET_CIDR bool // support: true, do not support: false VPC_CIDR bool // support: true, do not support: false diff --git a/cloud-control-manager/cloud-driver/interfaces/connect/CloudConnect.go b/cloud-control-manager/cloud-driver/interfaces/connect/CloudConnect.go index 8881997ec..e349dd046 100644 --- a/cloud-control-manager/cloud-driver/interfaces/connect/CloudConnect.go +++ b/cloud-control-manager/cloud-driver/interfaces/connect/CloudConnect.go @@ -31,6 +31,7 @@ type CloudConnection interface { CreateClusterHandler() (irs.ClusterHandler, error) CreateAnyCallHandler() (irs.AnyCallHandler, error) + CreateRegionZoneHandler() (irs.RegionZoneHandler, error) IsConnected() (bool, error) Close() error