From c2599a1ea046355cc9ca398abcf545b52940779d Mon Sep 17 00:00:00 2001 From: Sean Oh Date: Fri, 10 Nov 2023 13:40:43 +0900 Subject: [PATCH] [+NCP Conn. Driver] Add NCP Classic Driver Codes --- .gitignore | 16 +- build_all_driver_lib.sh | 2 +- .../drivers/ncp-plugin/NcpDriver-lib.go | 110 ++ .../cloud-driver/drivers/ncp-plugin/README.md | 1 + .../drivers/ncp-plugin/build_driver_lib.sh | 14 + .../cloud-driver/drivers/ncp/NcpDriver.go | 106 + .../cloud-driver/drivers/ncp/README.md | 136 ++ .../drivers/ncp/connect/NcpCloudConnection.go | 146 ++ .../drivers/ncp/main/Test_DiskHandler.go | 273 +++ .../drivers/ncp/main/Test_ImageHandler.go | 263 +++ .../drivers/ncp/main/Test_KeyPairHandler.go | 263 +++ .../drivers/ncp/main/Test_MyImageHandler.go | 231 +++ .../drivers/ncp/main/Test_NLBHandler.go | 351 ++++ .../ncp/main/Test_RegionZoneHandler.go | 253 +++ .../drivers/ncp/main/Test_SecurityHandler.go | 353 ++++ .../drivers/ncp/main/Test_VMHandler.go | 377 ++++ .../drivers/ncp/main/Test_VMSpecHandler.go | 272 +++ .../drivers/ncp/main/Test_VPCHandler.go | 270 +++ .../ncp/main/config/config.yaml.sample | 47 + .../drivers/ncp/main/goget-ncpsdk.sh | 7 + .../drivers/ncp/main/test_disk.sh | 3 + .../drivers/ncp/main/test_image.sh | 3 + .../drivers/ncp/main/test_keypair.sh | 3 + .../drivers/ncp/main/test_myimage.sh | 3 + .../cloud-driver/drivers/ncp/main/test_nlb.sh | 3 + .../drivers/ncp/main/test_region-zone.sh | 3 + .../drivers/ncp/main/test_security.sh | 3 + .../cloud-driver/drivers/ncp/main/test_vm.sh | 3 + .../drivers/ncp/main/test_vmspec.sh | 3 + .../cloud-driver/drivers/ncp/main/test_vpc.sh | 3 + .../drivers/ncp/resources/CommonNcpFunc.go | 173 ++ .../drivers/ncp/resources/DiskHandler.go | 755 ++++++++ .../drivers/ncp/resources/ImageHandler.go | 188 ++ .../drivers/ncp/resources/KeyPairHandler.go | 252 +++ .../drivers/ncp/resources/MyImageHandler.go | 501 +++++ .../drivers/ncp/resources/NLBHandler.go | 930 +++++++++ .../ncp/resources/RegionZoneHandler.go | 284 +++ .../drivers/ncp/resources/SecurityHandler.go | 301 +++ .../drivers/ncp/resources/VMHandler.go | 1715 +++++++++++++++++ .../drivers/ncp/resources/VMSpecHandler.go | 379 ++++ .../drivers/ncp/resources/VPCHandler.go | 379 ++++ go.mod | 5 +- go.sum | 27 +- 43 files changed, 9398 insertions(+), 12 deletions(-) create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp-plugin/NcpDriver-lib.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp-plugin/README.md create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp-plugin/build_driver_lib.sh create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/NcpDriver.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/README.md create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/connect/NcpCloudConnection.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_DiskHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_ImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_KeyPairHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_MyImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_NLBHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_RegionZoneHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_SecurityHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMSpecHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VPCHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/main/config/config.yaml.sample create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/goget-ncpsdk.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_disk.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_image.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_keypair.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_myimage.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_nlb.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_region-zone.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_security.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_vm.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_vmspec.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncp/main/test_vpc.sh create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/CommonNcpFunc.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/DiskHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/KeyPairHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/NLBHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/RegionZoneHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/SecurityHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncp/resources/VPCHandler.go diff --git a/.gitignore b/.gitignore index e6a270ecb..58157e57c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,13 @@ cloud-driver-libs/.ssh-gcp/* cloud-driver-libs/.ssh-aws/* cloud-driver-libs/.ssh-aliyun/* cloud-driver-libs/.ssh-tencent/* +cloud-driver-libs/.ssh-ncp/* +cloud-driver-libs/.ssh-nhn/* +cloud-driver-libs/.ssh-ktcloud/* +cloud-driver-libs/.vpc-ncp/* +cloud-driver-libs/.vpc-nhn/* +cloud-driver-libs/.vpc-kt/* +cloud-driver-libs/.securitygroup-kt/* vendor/* cloud-driver-libs/*.so @@ -43,18 +50,13 @@ interface/spctl .history/ .vscode/ -cloud-control-manager/cloud-driver/drivers/ncp/* -cloud-control-manager/cloud-driver/drivers/ncp-plugin/* - -cloud-control-manager/cloud-driver/drivers/tencent/main/conf/testConfigTencent.yaml - utils/clone-mc-meta-info/vm-image/data/* utils/clone-mc-meta-info/vm-image/test/* utils/clone-mc-meta-info/vm-image/az-data/* cloud-control-manager/cloud-driver/drivers/azure/main/conf/config.yaml - cloud-control-manager/cloud-driver/drivers/cloudit/main/conf/config.yaml cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/conf/config.yaml cloud-control-manager/cloud-driver/drivers/openstack/main/conf/config.yaml - +cloud-control-manager/cloud-driver/drivers/tencent/main/conf/testConfigTencent.yaml +cloud-control-manager/cloud-driver/drivers/ncp/main/conf/config.yaml diff --git a/build_all_driver_lib.sh b/build_all_driver_lib.sh index 8529f5f12..a201065fe 100755 --- a/build_all_driver_lib.sh +++ b/build_all_driver_lib.sh @@ -2,7 +2,7 @@ source setup.env #DRIVERS=( aws-plugin azure-plugin openstack-plugin gcp-plugin alibaba-plugin cloudit-plugin docker-plugin ncp-plugin ncpvpc-plugin) -DRIVERS=( aws-plugin azure-plugin gcp-plugin alibaba-plugin openstack-plugin cloudit-plugin docker-plugin mock-plugin tencent-plugin ibmcloud-vpc-plugin ) +DRIVERS=( aws-plugin azure-plugin gcp-plugin alibaba-plugin openstack-plugin cloudit-plugin docker-plugin mock-plugin tencent-plugin ibmcloud-vpc-plugin ncp-plugin ) DRIVER_PATH=$CBSPIDER_ROOT/cloud-control-manager/cloud-driver/drivers DRIVERLIB_PATH=$CBSPIDER_ROOT/cloud-driver-libs diff --git a/cloud-control-manager/cloud-driver/drivers/ncp-plugin/NcpDriver-lib.go b/cloud-control-manager/cloud-driver/drivers/ncp-plugin/NcpDriver-lib.go new file mode 100644 index 000000000..030afd1c8 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp-plugin/NcpDriver-lib.go @@ -0,0 +1,110 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Example for PoC Test. +// +// by ETRI, 2020.08. + +package main + +import ( + //cblog "github.com/cloud-barista/cb-log" + + idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" + icon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/connect" + + // "github.com/davecgh/go-spew/spew" + // unused import "github.com/sirupsen/logrus" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + lb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/loadbalancer" + + // ncpcon "github.com/cloud-barista/ncp/ncp/connect" + ncpcon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp/connect" //To be built in the container +) + +/* +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VMHandler") +} +*/ + +type NcpDriver struct { +} + +func (NcpDriver) GetDriverVersion() string { + return "TEST NCP DRIVER Version 1.0" +} + +func (NcpDriver) GetDriverCapability() idrv.DriverCapabilityInfo { + var drvCapabilityInfo idrv.DriverCapabilityInfo + + // NOTE Temporary Setting + drvCapabilityInfo.ImageHandler = true + drvCapabilityInfo.VPCHandler = true + drvCapabilityInfo.SecurityHandler = true + drvCapabilityInfo.KeyPairHandler = true + drvCapabilityInfo.VNicHandler = false + drvCapabilityInfo.PublicIPHandler = false + drvCapabilityInfo.VMHandler = true + drvCapabilityInfo.VMSpecHandler = true + + return drvCapabilityInfo +} + +// func getVMClient(credential idrv.CredentialInfo) (*server.APIClient, error) { +func getVMClient(connectionInfo idrv.ConnectionInfo) (*server.APIClient, error) { + // NOTE 주의!! + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + // Create NCP service client + client := server.NewAPIClient(server.NewConfiguration(&apiKeys)) + return client, nil +} + +func getLbClient(connectionInfo idrv.ConnectionInfo) (*lb.APIClient, error) { + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + // Create NCP Classic Load Balancer service client + client := lb.NewAPIClient(lb.NewConfiguration(&apiKeys)) + return client, nil +} + +func (driver *NcpDriver) ConnectCloud(connectionInfo idrv.ConnectionInfo) (icon.CloudConnection, error) { + // 1. get info of credential and region for Test A Cloud from connectionInfo. + // 2. create a client object(or service object) of Test A Cloud with credential info. + // 3. create CloudConnection Instance of "connect/TDA_CloudConnection". + // 4. return CloudConnection Interface of TDA_CloudConnection. + + vmClient, err := getVMClient(connectionInfo) + if err != nil { + return nil, err + } + + lbClient, err := getLbClient(connectionInfo) + if err != nil { + return nil, err + } + + iConn := ncpcon.NcpCloudConnection{ + CredentialInfo: connectionInfo.CredentialInfo, + RegionInfo: connectionInfo.RegionInfo, + VmClient: vmClient, + LbClient: lbClient, + } + + return &iConn, nil +} + +var CloudDriver NcpDriver diff --git a/cloud-control-manager/cloud-driver/drivers/ncp-plugin/README.md b/cloud-control-manager/cloud-driver/drivers/ncp-plugin/README.md new file mode 100644 index 000000000..f471ff357 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp-plugin/README.md @@ -0,0 +1 @@ +# ncp/ncp-plugin directory diff --git a/cloud-control-manager/cloud-driver/drivers/ncp-plugin/build_driver_lib.sh b/cloud-control-manager/cloud-driver/drivers/ncp-plugin/build_driver_lib.sh new file mode 100755 index 000000000..fd3b5706f --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp-plugin/build_driver_lib.sh @@ -0,0 +1,14 @@ +#!/bin/bash +source $CBSPIDER_ROOT/setup.env + +DRIVERLIB_PATH=$CBSPIDER_ROOT/cloud-driver-libs +DRIVERFILENAME=ncp-driver-v1.0 + +# To be built in the container +# cp $HOME/ncp/go.* ./ +go mod download # cb-spider's go.mod and go.sum will be applied. + +rm -rf $DRIVERLIB_PATH/${DRIVERFILENAME}.so +go build -buildmode=plugin -o ${DRIVERFILENAME}.so NcpDriver-lib.go +chmod +x ${DRIVERFILENAME}.so +mv ./${DRIVERFILENAME}.so $DRIVERLIB_PATH diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/NcpDriver.go b/cloud-control-manager/cloud-driver/drivers/ncp/NcpDriver.go new file mode 100644 index 000000000..a95af3481 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/NcpDriver.go @@ -0,0 +1,106 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP Cloud Driver PoC +// +// by ETRI, 2020.07. +// updated by ETRI, 2023.08. + +package ncp + +import ( + cblog "github.com/cloud-barista/cb-log" + + idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" + icon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/connect" + + // "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + lb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/loadbalancer" + + // ncpcon "github.com/cloud-barista/ncp/ncp/connect" + ncpcon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp/connect" //To be built in the container +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VMHandler") +} + +type NcpDriver struct { +} + +func (NcpDriver) GetDriverVersion() string { + return "TEST NCP DRIVER Version 1.0" +} + +func (NcpDriver) GetDriverCapability() idrv.DriverCapabilityInfo { + var drvCapabilityInfo idrv.DriverCapabilityInfo + + // NOTE Temporary Setting + drvCapabilityInfo.ImageHandler = true + drvCapabilityInfo.VPCHandler = true + drvCapabilityInfo.SecurityHandler = true + drvCapabilityInfo.KeyPairHandler = true + drvCapabilityInfo.VNicHandler = false + drvCapabilityInfo.PublicIPHandler = false + drvCapabilityInfo.VMHandler = true + drvCapabilityInfo.VMSpecHandler = true + + return drvCapabilityInfo +} + +func getVMClient(connectionInfo idrv.ConnectionInfo) (*server.APIClient, error) { + // NOTE 주의!! + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + // Create NCP service client + client := server.NewAPIClient(server.NewConfiguration(&apiKeys)) + return client, nil +} + +func getLbClient(connectionInfo idrv.ConnectionInfo) (*lb.APIClient, error) { + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + // Create NCP Classic Load Balancer service client + client := lb.NewAPIClient(lb.NewConfiguration(&apiKeys)) + return client, nil +} + +func (driver *NcpDriver) ConnectCloud(connectionInfo idrv.ConnectionInfo) (icon.CloudConnection, error) { + // 1. get info of credential and region for Test A Cloud from connectionInfo. + // 2. create a client object(or service object) of Test A Cloud with credential info. + // 3. create CloudConnection Instance of "connect/TDA_CloudConnection". + // 4. return CloudConnection Interface of TDA_CloudConnection. + + vmClient, err := getVMClient(connectionInfo) + if err != nil { + return nil, err + } + + lbClient, err := getLbClient(connectionInfo) + if err != nil { + return nil, err + } + + iConn := ncpcon.NcpCloudConnection{ + CredentialInfo: connectionInfo.CredentialInfo, + RegionInfo: connectionInfo.RegionInfo, + VmClient: vmClient, + LbClient: lbClient, + } + + return &iConn, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/README.md b/cloud-control-manager/cloud-driver/drivers/ncp/README.md new file mode 100644 index 000000000..37ad96057 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/README.md @@ -0,0 +1,136 @@ +### NCP (Naver Cloud Platform) Classic driver Build 및 CB-Spider에 적용 방법 + + +#### # 연동 Driver 관련 기본적인 사항은 아래 link 참고 + + - [Cloud Driver Developer Guide](https://github.com/cloud-barista/cb-spider/wiki/Cloud-Driver-Developer-Guide) +


+#### # CB-Spider에서 NCP 연동 driver build 및 구동 방법 + +​ O 위에서와 같이 CB-Spider 코드가 clone된 상태에서 CB-Spider setup 파일 적용 +``` +$CBSPIDER_ROOT/ source setup.env +``` + +​ O Dynamic plugin mode로 'CB-Spider' build 실행 + +``` +cd $CBSPIDER_ROOT + +make dyna + +``` + - CB-Spider build 과정이 완료되면, $CBSPIDER_ROOT/bin/ 아래에 binary 파일로 'cb-spider-dyna' 가 생김 + +


+ +​ O CB-Spider server 구동(Dynamic plugin 방식, 1024 포트로 REST API server 구동됨) + +``` +cd $CBSPIDER_ROOT/bin + +./start-dyna.sh +``` + + - CB-Spider server가 구동된 후, NCP driver 등록 과정을 거치고 사용 + +


+ +#### # CB-Spider에 NCP driver 테스트 방법 + +​ O NCP Credential 정보(API 인증키) 발급 방법
+ - [네이버클라우드 포털](https://www.ncloud.com) > 마이페이지 > 계정관리 > '인증키 관리' 메뉴로 이동
+ > [신규 API 인증키 생성] 버튼을 클릭하면 인증키가 생성됨. + - 네이버클라우드 Credential 정보(API 인증키) 생성 메뉴 바로 가기 : 네이버클라우드 포털 > [인증키 관리](https://www.ncloud.com/mypage/manage/authkey) 메뉴 + + (참고) 네이버클라우드 API 인증키는 계정당 2개까지 생성할 수 있음. + +​ O NCP connection config 파일에 NCP Credential 정보(API 인증키) 기입 후 실행
+ +``` +$CBSPIDER_ROOT/api-runtime/rest-runtime/test/connect-config/ ./8.ncp-conn-config.sh +``` +


+ +#### # CB-Spider REST API 이용 NCP driver 모든 기능 테스트 + +​ O NCP 각 자원 생성, 자원정보 조회, VM instance Start 및 Terminate 테스트 등 + +- Curl command를 이용하는 테스트 script +``` +$CBSPIDER_ROOT/api-runtime/rest-runtime/test/full-test/8.ncp-test.sh +$CBSPIDER_ROOT/api-runtime/rest-runtime/test/full-test/ncp-full_test.sh +``` +


+ +#### # NCP driver 자체 test 파일을 이용한 기능 테스트 + +​ O CB-Spider 환경 파일 적용 +``` +$CBSPIDER_ROOT/ source setup.env +``` + +​ O 아래의 config 파일에 NCP Credential 정보 기입 +``` +$CBSPIDER_ROOT/cloud-control-manager/cloud-driver/drivers/ncp/main/config/config.yaml +``` + +​ O 아래의 위치에 있는 ~.sh 파일을 실행해서 NCP driver 각 handler 세부 기능 테스트 +``` +$CBSPIDER_ROOT/cloud-control-manager/cloud-driver/drivers/ncp/main/ +``` +


+ +#### # NCP cloud driver로 생성된 VM에 로그인하는 방법 + +​ O Cloud-Barista NCP driver를 이용해 생성된 VM에 로그인하는 방법(Linux 계열 guest OS 경우) + + - 사용자가 keyPair 생성시 생성되는 private key를 local에 저장해놓고, 그 private key를 이용해 'cb-user' 계정으로 SSH를 이용해 로그인하는 방법을 제공함. + + - Private ket 파일을 이용한 VM 접속 방법 + +``` +ssh -i /private_key_경로/private_key_파일명(~~.pem) cb-user@VM의_public_ip +``` + + +​ (참고) NCP CSP에서 제공하는 VM 접속 방법 + + - VM 생성 후, NCP console에서 사용자가 생성한 private key를 이용해 해당 VM의 root 비밀번호를 알아내어 SSH를 이용해 root 계정과 비밀번호로 로그인함. + +​ O Cloud-Barista NCP driver를 이용해 생성된 VM에 로그인하는 방법(Windows 계열 guest OS 경우) + + - 'Administrator' 계정으로 VM 생성시 지정한 사용자가 password 로그인함. + +


+ +(주의 사항)
+​ O NCP Classic 버전 CSP는 물리적 네트워크 기반으로 운영되므로, NCP에서 VPC/Subnet 생성 등의 제어 기능 및 API를 지원하지 않음. + - 따라서, 본 driver를 통해 VPC 및 Subnet 관련 제어가 진행될때 VPC 및 Subnet 정보는 driver 자체에서 임의적으로 local에서 JSON 파일 형태로 관리됨.(VPC 및 Subnet 생성시 어떤 Name이든 가능) + +​ O NCP Classic CSP는 VPC 및 Subnet 제어 기능을 제공하지 않으므로, 본 driver에서 지원하는 VPC와 Subnet 제어 기능은 CB-Spider common interface를 만족하기 위해 제공하는 임의의 VPC 및 Subnet을 위한 제어 기능임. + - NCP Classic에서 사용하는 private IP의 IPv4_CIDR은 10.0.0.0/XX 임. + +​ O NCP Classic CSP는 Security Group도 REST API를 통해서는 생성, 삭제 기능을 지원하지 않고 조회 기능만 지원함(Console에서는 모든 기능 지원). 따라서, CB-Spider 및 NCP 연동 driver를 통한 제어를 위해서는 다음 사항을 주의해야함. + + - Security Group 생성/삭제시에는 NCP console에서 생성/삭제하고, Cloud-Barista에서 생성, 조회, 삭제 요청시 console에서 생성한 그 'Security Group 이름을 그대로' 사용함. + - Console에서 생성시, 이름은 최소 6자/최대 30자의 소문자만 가능하고, 숫자, '-' 기호 사용 가능 + +​ O NCP Classic NLB 이용시 다음 사항을 주의해야함. + - NCP Classic NLB는 HTTP, HTTPS, TCP, SSL protocol만 지원함. + - Listener, VM Group, HealthChecker protocol이 동일해야함. + + O NCP Classic 버전 driver이 지원하는 region 및 zone은 아래의 파일을 참고 +``` + ./ncp/ncp/main/config/config.yaml.sample + ./cb-spider/api-runtime/rest-runtime/test/connect-config/8.ncp-conn-config.sh +``` + +​ O NCP 정책상, 생성되는 public IP 개수가 VM instance 수를 초과할 수 없으므로 다음 사항을 주의 + + - 만약, NCP console에서 수동으로 VM을 반납(termination) 할 경우에는 반드시 public IP도 반납하는것으로 체크 후 반납 필요 + - Public IP를 반납하지 않으면, NCP driver를 통해 VM instance 신규 생성시 public IP를 추가 생성할때 public IP 수가 instance 개수보다 많게 되어 error return + + - 단, NCP driver나 CB-Spider API를 이용해 NCP VM 반납시에는 VM 반납 후 자동으로 public IP까지 반납됨. + +​ O NCP 정책상, VM이 생성된 후 한번 정지시킨 상태에서 연속으로 최대 90일, 12개월 누적 180일을 초과하여 정지할 수 없으며, 해당 기간을 초과할 경우 반납(Terminate)하도록 안내하고 있음. diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/connect/NcpCloudConnection.go b/cloud-control-manager/cloud-driver/drivers/ncp/connect/NcpCloudConnection.go new file mode 100644 index 000000000..aaabaa981 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/connect/NcpCloudConnection.go @@ -0,0 +1,146 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Example for PoC Test. +// +// by ETRI, 2020.08. +// by ETRI, 2022.08. + +package connect + +import ( + "fmt" + "github.com/sirupsen/logrus" + + cblog "github.com/cloud-barista/cb-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" + + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + lb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/loadbalancer" + + // ncprs "github.com/cloud-barista/ncp/ncp/resources" + ncprs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp/resources" //To be built in the container +) + +type NcpCloudConnection struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VmClient *server.APIClient + LbClient *lb.APIClient +} + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Connect") +} + +func (cloudConn *NcpCloudConnection) CreateVMHandler() (irs.VMHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateVMHandler()!") + + vmHandler := ncprs.NcpVMHandler{ + CredentialInfo: cloudConn.CredentialInfo, + RegionInfo: cloudConn.RegionInfo, + VMClient: cloudConn.VmClient, + } + return &vmHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateVMSpecHandler() (irs.VMSpecHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateVMSpecHandler()!") + + vmspecHandler := ncprs.NcpVMSpecHandler{cloudConn.CredentialInfo, cloudConn.RegionInfo, cloudConn.VmClient} + return &vmspecHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateImageHandler() (irs.ImageHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateImagehandler()!") + + imageHandler := ncprs.NcpImageHandler{cloudConn.CredentialInfo, cloudConn.RegionInfo, cloudConn.VmClient} + return &imageHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateKeyPairHandler() (irs.KeyPairHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateKeyPairHandler()!") + + keypairHandler := ncprs.NcpKeyPairHandler{cloudConn.CredentialInfo, cloudConn.RegionInfo, cloudConn.VmClient} + return &keypairHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateSecurityHandler() (irs.SecurityHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateSecurityHandler()!") + + sgHandler := ncprs.NcpSecurityHandler{cloudConn.CredentialInfo, cloudConn.RegionInfo, cloudConn.VmClient} + return &sgHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateVPCHandler() (irs.VPCHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateVPCHandler()!") + + vpcHandler := ncprs.NcpVPCHandler{cloudConn.CredentialInfo, cloudConn.RegionInfo, cloudConn.VmClient} + return &vpcHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateNLBHandler() (irs.NLBHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateNLBHandler()!") + + nlbHandler := ncprs.NcpNLBHandler{CredentialInfo: cloudConn.CredentialInfo, RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient, LBClient: cloudConn.LbClient} + return &nlbHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateDiskHandler() (irs.DiskHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateDiskHandler()!") + + diskHandler := ncprs.NcpDiskHandler{RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + return &diskHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateMyImageHandler() (irs.MyImageHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateMyImageHandler()!") + + myimageHandler := ncprs.NcpMyImageHandler{RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + return &myimageHandler, nil +} + +func (cloudConn *NcpCloudConnection) CreateClusterHandler() (irs.ClusterHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateClusterHandler()!") + + return nil, fmt.Errorf("NCP Cloud Driver does not support CreateClusterHandler yet.") +} + +func (cloudConn *NcpCloudConnection) CreateAnyCallHandler() (irs.AnyCallHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateAnyCallHandler()!") + + return nil, fmt.Errorf("NCP Cloud Driver does not support CreateAnyCallHandler yet.") +} + +func (cloudConn *NcpCloudConnection) CreateRegionZoneHandler() (irs.RegionZoneHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateRegionZoneHandler()!") + + regionZoneHandler := ncprs.NcpRegionZoneHandler{RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + return ®ionZoneHandler, nil +} + +func (cloudConn *NcpCloudConnection) IsConnected() (bool, error) { + cblogger.Info("NCP Cloud Driver: called IsConnected()!") + if cloudConn == nil { + return false, nil + } + + if cloudConn.VmClient.V2Api == nil { + return false, nil + } + + return true, nil +} + +func (cloudConn *NcpCloudConnection) Close() error { + cblogger.Info("NCP Cloud Driver: called Close()!") + + return nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_DiskHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_DiskHandler.go new file mode 100644 index 000000000..7e0ad3175 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_DiskHandler.go @@ -0,0 +1,273 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2023.07. + +package main + +import ( + "os" + "errors" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +func handleDisk() { + cblogger.Debug("Start Disk Resource Test") + + resourceHandler, err := getResourceHandler("Disk") + if err != nil { + cblogger.Error(err) + return + } + diskHandler := resourceHandler.(irs.DiskHandler) + //config := readConfigFile() + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ DiskHandler Test ]") + cblogger.Info("1. ListDisk()") + cblogger.Info("2. GetDisk()") + cblogger.Info("3. CreateDisk()") + cblogger.Info("4. DeleteDisk()") + cblogger.Info("5. ChangeDiskSize()") + cblogger.Info("6. AttachDisk()") + cblogger.Info("7. DetachDisk()") + cblogger.Info("0. Exit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + var commandNum int + + diskIId := irs.IID{ + SystemId: "19308647", + } + + createReqInfo := irs.DiskInfo{ + IId: irs.IID{ + NameId: "ncp-disk-02", + }, + // DiskType: "default", + DiskType: "HDD", + // DiskType: "SSD", + // DiskSize: "default", + DiskSize: "50", + } + + vmIId := irs.IID{ // To attach disk + SystemId: "19313606", + } + + newDiskSize := "5" + + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + return + case 1: + cblogger.Info("Start ListDisk() ...") + if listResult, err := diskHandler.ListDisk(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(listResult) + cblogger.Info("# 출력 결과 수 : ", len(listResult)) + } + cblogger.Info("Finish ListDisk()") + case 2: + cblogger.Info("Start GetDisk() ...") + if diskInfo, err := diskHandler.GetDisk(diskIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(diskInfo) + } + cblogger.Info("Finish GetDisk()") + case 3: + cblogger.Info("Start CreateDisk() ...") + if diskInfo, err := diskHandler.CreateDisk(createReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(diskInfo) + } + cblogger.Info("Finish CreateDisk()") + case 4: + cblogger.Info("Start DeleteDisk() ...") + if delResult, err := diskHandler.DeleteDisk(diskIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(delResult) + } + cblogger.Info("Finish DeleteDisk()") + case 5: + cblogger.Info("Start ChangeDiskSize() ...") + if diskInfo, err := diskHandler.ChangeDiskSize(diskIId, newDiskSize); err != nil { + cblogger.Error(err) + } else { + spew.Dump(diskInfo) + } + cblogger.Info("Finish ChangeDiskSize()") + case 6: + cblogger.Info("Start AttachDisk() ...") + if diskInfo, err := diskHandler.AttachDisk(diskIId, vmIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(diskInfo) + } + cblogger.Info("Finish AttachDisk()") + case 7: + cblogger.Info("Start DetachDisk() ...") + if result, err := diskHandler.DetachDisk(diskIId, vmIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(result) + } + cblogger.Info("Finish DetachDisk()") + } + } + } +} + +func testErr() error { + + return errors.New("") +} + +func main() { + cblogger.Info("NCP Resource Test") + handleDisk() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + case "VPC": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "Disk": + resourceHandler, err = cloudConnection.CreateDiskHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + // rootPath := os.Getenv("CBSPIDER_PATH") + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_ImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_ImageHandler.go new file mode 100644 index 000000000..15b201ddc --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_ImageHandler.go @@ -0,0 +1,263 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2020.09. + +package main + +import ( + "os" + "errors" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +func handleImage() { + cblogger.Debug("Start ImageHandler Resource Test") + + ResourceHandler, err := getResourceHandler("Image") + if err != nil { + panic(err) + } + + handler := ResourceHandler.(irs.ImageHandler) + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ Image Management Test ]") + fmt.Println("1. Image List") + fmt.Println("2. Image Get") + fmt.Println("3. Image Create (TBD)") + fmt.Println("4. Image Delete (TBD)") + fmt.Println("0. Quit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + imageReqInfo := irs.ImageReqInfo{ + //IId: irs.IID{NameId: "Test OS Image", SystemId: "SPSW0LINUX000029"}, //NCP : Ubuntu Server 16.04 (64-bit) + IId: irs.IID{NameId: "Test OS Image", SystemId: "SPSW0LINUX000130"}, //NCP : Ubuntu Server 18.04 (64-bit) + // IId: irs.IID{NameId: "Test OS Image", SystemId: "SPSW0LINUX000031"}, //NCP : CentOS 6.3(64bit) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + return + + case 1: + cblogger.Infof("Image list 조회 테스트") + + result, err := handler.ListImage() + if err != nil { + cblogger.Infof(" Image list 조회 실패 : ", err) + } else { + fmt.Println("\n==================================================================================================================") + cblogger.Info("Image list 조회 결과") + fmt.Println("\n") + spew.Dump(result) + cblogger.Info("출력 결과 수 : ", len(result)) + //조회및 삭제 테스트를 위해 리스트의 첫번째 정보의 ID를 요청ID로 자동 갱신함. + if result != nil { + imageReqInfo.IId = result[0].IId // 조회 및 삭제를 위해 생성된 ID로 변경 + } + } + + cblogger.Info("\nListImage Test Finished") + + case 2: + cblogger.Infof("[%s] Image 조회 테스트", imageReqInfo.IId) + + result, err := handler.GetImage(imageReqInfo.IId) + if err != nil { + cblogger.Infof("[%s] Image 조회 실패 : ", imageReqInfo.IId.SystemId, err) + } else { + fmt.Println("\n==================================================================================================================") + cblogger.Infof("[%s] Image 조회 결과 : \n[%s]", imageReqInfo.IId.SystemId, result) + + fmt.Println("\n") + spew.Dump(result) + } + + cblogger.Info("\nGetImage Test Finished") + + // case 3: + // cblogger.Infof("[%s] Image 생성 테스트", imageReqInfo.IId.NameId) + // result, err := handler.CreateImage(imageReqInfo) + // if err != nil { + // cblogger.Infof(imageReqInfo.IId.NameId, " Image 생성 실패 : ", err) + // } else { + // cblogger.Infof("Image 생성 결과 : ", result) + // imageReqInfo.IId = result.IId // 조회 및 삭제를 위해 생성된 ID로 변경 + // spew.Dump(result) + // } + + // case 4: + // cblogger.Infof("[%s] Image 삭제 테스트", imageReqInfo.IId.NameId) + // result, err := handler.DeleteImage(imageReqInfo.IId) + // if err != nil { + // cblogger.Infof("[%s] Image 삭제 실패 : ", imageReqInfo.IId.NameId, err) + // } else { + // cblogger.Infof("[%s] Image 삭제 결과 : [%s]", imageReqInfo.IId.NameId, result) + // } + } + } + } +} + +func testErr() error { + //return awserr.Error("") + return errors.New("") + // return ncloud.New("504", "찾을 수 없음", nil) +} + +func main() { + cblogger.Info("NCP Resource Test") + + handleImage() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_KeyPairHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_KeyPairHandler.go new file mode 100644 index 000000000..6d6271780 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_KeyPairHandler.go @@ -0,0 +1,263 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2020.09. + +package main + +import ( + "os" + "errors" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +func testErr() error { + //return awserr.Error("") + return errors.New("") + // return ncloud.New("504", "찾을 수 없음", nil) +} + +// Test KeyPair +func handleKeyPair() { + cblogger.Debug("Start KeyPair Resource Test") + + ResourceHandler, err := getResourceHandler("KeyPair") + if err != nil { + panic(err) + } + //config := readConfigFile() + //VmID := config.Ncp.VmID + + keyPairHandler := ResourceHandler.(irs.KeyPairHandler) + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ KeyPair Management Test ]") + fmt.Println("1. List KeyPair") + fmt.Println("2. Create KeyPair") + fmt.Println("3. Get KeyPair") + fmt.Println("4. Delete KeyPair") + fmt.Println("0. Quit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + //keyPairName := config.Ncp.KeyName + keyPairName := "NCP-keypair-06" + 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 := keyPairHandler.ListKey() + if err != nil { + cblogger.Infof("KeyPair list 조회 실패 : ", err) + } else { + cblogger.Info("KeyPair list 조회 결과") + //cblogger.Info(result) + spew.Dump(result) + + cblogger.Infof("=========== KeyPair list 수 : [%d] ================", len(result)) + } + + cblogger.Info("\nListKey Test Finished") + + case 2: + cblogger.Infof("[%s] KeyPair 생성 테스트", keyPairName) + keyPairReqInfo := irs.KeyPairReqInfo{ + IId: irs.IID{NameId: keyPairName}, + //Name: keyPairName, + } + result, err := keyPairHandler.CreateKey(keyPairReqInfo) + if err != nil { + cblogger.Infof(keyPairName, " KeyPair 생성 실패 : ", err) + } else { + cblogger.Infof("[%s] KeyPair 생성 결과 : \n[%s]", keyPairName, result) + //spew.Dump(result) + } + + cblogger.Info("\nCreateKey Test Finished") + + case 3: + cblogger.Infof("[%s] KeyPair 조회 테스트", keyPairName) + result, err := keyPairHandler.GetKey(irs.IID{NameId: keyPairName}) + if err != nil { + cblogger.Infof(keyPairName, " KeyPair 조회 실패 : ", err) + } else { + cblogger.Infof("[%s] KeyPair 조회 결과 : \n[%s]", keyPairName, result) + //spew.Dump(result) + } + + cblogger.Info("\nGetKey Test Finished") + + case 4: + cblogger.Infof("[%s] KeyPair 삭제 테스트", keyPairName) + result, err := keyPairHandler.DeleteKey(irs.IID{NameId: keyPairName}) + if err != nil { + cblogger.Infof(keyPairName, " KeyPair 삭제 실패 : ", err) + } else { + cblogger.Infof("[%s] KeyPair 삭제 결과 : [%s]", keyPairName, result) + spew.Dump(result) + } + + cblogger.Info("\nDeleteKey Test Finished") + } + } + } +} + +func main() { + cblogger.Info("NCP Resource Test") + + handleKeyPair() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "KeyPair": + resourceHandler, err = cloudConnection.CreateKeyPairHandler() + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_MyImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_MyImageHandler.go new file mode 100644 index 000000000..cd7c1205f --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_MyImageHandler.go @@ -0,0 +1,231 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2023.08. + +package main + +import ( + "os" + "errors" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC Cloud Resource Test") + cblog.SetLevel("info") +} + +func handleMyImage() { + cblogger.Debug("Start MyImage Resource Test") + + resourceHandler, err := getResourceHandler("MyImage") + if err != nil { + cblogger.Error(err) + return + } + diskHandler := resourceHandler.(irs.MyImageHandler) + //config := readConfigFile() + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ MyImageHandler Test ]") + cblogger.Info("1. ListMyImage()") + cblogger.Info("2. GetMyImage()") + cblogger.Info("3. SnapshotVM()") + cblogger.Info("4. CheckWindowsImage()") + cblogger.Info("5. DeleteMyImage()") + cblogger.Info("0. Exit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + var commandNum int + + myImageIId := irs.IID{ + NameId: "ncp-myimage-01", + SystemId: "96215", + } + + snapshotReqInfo := irs.MyImageInfo{ + IId: irs.IID{ + NameId: "ncp-myimage-01", + }, + SourceVM: irs.IID{ + NameId: "ncp-test-vm-003", + SystemId: "19391267", + }, + } + + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + return + case 1: + cblogger.Info("Start ListMyImage() ...") + if listResult, err := diskHandler.ListMyImage(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(listResult) + cblogger.Info("# 출력 결과 수 : ", len(listResult)) + } + cblogger.Info("Finish ListMyImage()") + case 2: + cblogger.Info("Start GetMyImage() ...") + if diskInfo, err := diskHandler.GetMyImage(myImageIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(diskInfo) + } + cblogger.Info("Finish GetMyImage()") + case 3: + cblogger.Info("Start SnapshotVM() ...") + if diskInfo, err := diskHandler.SnapshotVM(snapshotReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(diskInfo) + } + cblogger.Info("Finish SnapshotVM()") + case 4: + cblogger.Info("Start CheckWindowsImage() ...") + if checkresult, err := diskHandler.CheckWindowsImage(myImageIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(checkresult) + } + cblogger.Info("Finish CheckWindowsImage()") + case 5: + cblogger.Info("Start DeleteMyImage() ...") + if delResult, err := diskHandler.DeleteMyImage(myImageIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(delResult) + } + cblogger.Info("Finish DeleteMyImage()") + } + } + } +} + +func testErr() error { + + return errors.New("") +} + +func main() { + cblogger.Info("NCP VPC Cloud Resource Test") + handleMyImage() +} + +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + case "VPC": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "MyImage": + resourceHandler, err = cloudConnection.CreateMyImageHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +func readConfigFile() Config { + // Set Environment Value of Project Root Path + // rootPath := os.Getenv("CBSPIDER_ROOT") + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + + cblogger.Info("Config file : " + rootPath + "/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + if err != nil { + cblogger.Error(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + cblogger.Error(err) + } + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_NLBHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_NLBHandler.go new file mode 100644 index 000000000..a387377b0 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_NLBHandler.go @@ -0,0 +1,351 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2023.08. + +package main + +import ( + "os" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + cblog "github.com/cloud-barista/cb-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" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Classic Resource Test") + cblog.SetLevel("info") +} + +// Test VMSpec +func handleNLB() { + cblogger.Debug("Start NLBHandler Resource Test") + + ResourceHandler, err := getResourceHandler("NLB") + if err != nil { + panic(err) + } + + nlbHandler := ResourceHandler.(irs.NLBHandler) + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ NLB Resource Test ]") + cblogger.Info("1. ListNLB()") + cblogger.Info("2. GetNLB()") + cblogger.Info("3. CreateNLB()") + cblogger.Info("4. DeleteNLB()") + cblogger.Info("5. ChangeListener()") + cblogger.Info("6. ChangeVMGroupInfo()") + cblogger.Info("7. AddVMs()") + cblogger.Info("8. RemoveVMs()") + cblogger.Info("9. GetVMGroupHealthInfo()") + cblogger.Info("10. ChangeHealthCheckerInfo()") + cblogger.Info("11. Exit") + fmt.Println("============================================================================================") + + config := readConfigFile() + cblogger.Infof("\n # NCP Classic Region : [%s]", config.Ncp.Region) + cblogger.Info("\n # Select Num : ") + + nlbIId := irs.IID{ + NameId: "new-nlb-01", + SystemId: "19315507", + } + + // Caution!! : Listener, VM Group and Healthchecker all use the same protocol type in NCP Classic NLB.(The Protocol specified by 'ProtocolTypeCode' when created). + nlbCreateReqInfo := irs.NLBInfo{ + IId: irs.IID{ + NameId: "new-nlb-05", + }, + VpcIID: irs.IID{ + NameId: "ncp-vpc-01", + }, + Listener: irs.ListenerInfo{ + Protocol: "TCP", + Port: "80", + // Port: "8080", + }, + VMGroup: irs.VMGroupInfo{ + Protocol: "TCP", + Port: "8080", + // Port: "8080", + VMs: &[]irs.IID{ + {NameId: "ncp-test-vm-001"}, + // {NameId: "ncp-test-vm-002"}, + }, + }, + HealthChecker: irs.HealthCheckerInfo{ + Protocol: "TCP", + Port: "8080", + Interval: -1, + Timeout: -1, + Threshold: -1, + }, + } + + updateListener := irs.ListenerInfo{ + Protocol: "TCP", + Port: "8087", + } + + updateVMGroups := irs.VMGroupInfo{ + Protocol: "TCP", + Port: "8087", + } + + addVMs := []irs.IID{ + // {NameId: "ncp-test-vm-002"}, + {NameId: "vm-01-cjo33q9jcupp70i7ad1g"}, + // {NameId: "s18431a1837f"}, + } + + removeVMs := []irs.IID{ + {NameId: "ncp-test-vm-002"}, + // {NameId: "s18431a1837f"}, + } + + updateHealthCheckerInfo := irs.HealthCheckerInfo{ + Protocol: "HTTP", + Port: "8080", + Interval: 7, + Timeout: 5, + Threshold: 4, + } + + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 1: + cblogger.Info("Start ListNLB() ...") + if list, err := nlbHandler.ListNLB(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + cblogger.Info("출력 결과 수 : ", len(list)) + } + cblogger.Info("Finish ListNLB()") + case 2: + cblogger.Info("Start GetNLB() ...") + if nlbInfo, err := nlbHandler.GetNLB(nlbIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(nlbInfo) + } + cblogger.Info("Finish GetNLB()") + case 3: + cblogger.Info("Start CreateNLB() ...") + if nlbInfo, err := nlbHandler.CreateNLB(nlbCreateReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(nlbInfo) + } + cblogger.Info("Finish CreateNLB()") + case 4: + cblogger.Info("Start DeleteNLB() ...") + if nlbStatus, err := nlbHandler.DeleteNLB(nlbIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(nlbStatus) + } + cblogger.Info("Finish DeleteNLB()") + case 5: + cblogger.Info("Start ChangeListener() ...") + if nlbInfo, err := nlbHandler.ChangeListener(nlbIId, updateListener); err != nil { + cblogger.Error(err) + } else { + spew.Dump(nlbInfo) + } + cblogger.Info("Finish ChangeListener()") + case 6: + cblogger.Info("Start ChangeVMGroupInfo() ...") + if info, err := nlbHandler.ChangeVMGroupInfo(nlbIId, updateVMGroups); err != nil { + cblogger.Error(err) + } else { + spew.Dump(info) + } + cblogger.Info("Finish ChangeVMGroupInfo()") + case 7: + cblogger.Info("Start AddVMs() ...") + if info, err := nlbHandler.AddVMs(nlbIId, &addVMs); err != nil { + cblogger.Error(err) + } else { + spew.Dump(info) + } + cblogger.Info("Finish AddVMs()") + case 8: + cblogger.Info("Start RemoveVMs() ...") + if result, err := nlbHandler.RemoveVMs(nlbIId, &removeVMs); err != nil { + cblogger.Error(err) + } else { + spew.Dump(result) + } + cblogger.Info("Finish RemoveVMs()") + case 9: + cblogger.Info("Start GetVMGroupHealthInfo() ...") + if info, err := nlbHandler.GetVMGroupHealthInfo(nlbIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(info) + } + cblogger.Info("Finish GetVMGroupHealthInfo()") + case 10: + cblogger.Info("Start ChangeHealthCheckerInfo() ...") + if info, err := nlbHandler.ChangeHealthCheckerInfo(nlbIId, updateHealthCheckerInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(info) + } + cblogger.Info("Finish ChangeHealthCheckerInfo()") + case 11: + cblogger.Info("Exit") + } + } + } +} + +func main() { + cblogger.Info("NCP Classic Resource Test") + + handleNLB() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + case "VPC": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "NLB": + resourceHandler, err = cloudConnection.CreateNLBHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + // rootPath := os.Getenv("CBSPIDER_PATH") + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + // cblogger.Info(config.Ncp.NcpAccessKeyID) + // cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_RegionZoneHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_RegionZoneHandler.go new file mode 100644 index 000000000..4a41bc4ef --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_RegionZoneHandler.go @@ -0,0 +1,253 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2023.09. + +package main + +import ( + "os" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +// Test RegionZone +func handleRegionZone() { + cblogger.Debug("Start RegionZoneHandler Resource Test") + + ResourceHandler, err := getResourceHandler("RegionZone") + if err != nil { + panic(err) + } + + handler := ResourceHandler.(irs.RegionZoneHandler) + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ RegionZone Resource Test ]") + fmt.Println("1. ListRegionZone()") + fmt.Println("2. GetRegionZone()") + fmt.Println("3. ListOrgRegion()") + fmt.Println("4. ListOrgZone()") + fmt.Println("0. Exit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + config := readConfigFile() + reqRegion := config.Ncp.Region // Region Code Ex) KR, HK, SGN, JPN, DEN, USWN + cblogger.Info("config.Ncp.Region : ", reqRegion) + + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 1: + fmt.Println("Start ListRegionZone() ...") + result, err := handler.ListRegionZone() + if err != nil { + cblogger.Error("RegionZone list 조회 실패 : ", err) + } else { + fmt.Println("\n==================================================================================================") + cblogger.Debug("RegionZone list 조회 성공!!") + spew.Dump(result) + cblogger.Debug(result) + cblogger.Infof("RegionZone list 개수 : [%d]", len(result)) + } + fmt.Println("\n# ListRegionZone() Test Finished") + + case 2: + fmt.Println("Start ListOrgRegion() ...") + result, err := handler.GetRegionZone(reqRegion) + if err != nil { + cblogger.Error("Region(Org) list 정보 조회 실패 : ", err) + } else { + fmt.Println("\n==================================================================================================") + cblogger.Debug("Region Info 조회 성공!!") + spew.Dump(result) + cblogger.Debug(result) + } + fmt.Println("\n# GetRegionZone() Test Finished") + + case 3: + fmt.Println("Start ListOrgRegion() ...") + result, err := handler.ListOrgRegion() + if err != nil { + cblogger.Error("Region(Org) list 정보 조회 실패 : ", err) + } else { + fmt.Println("\n==================================================================================================") + cblogger.Debug("Region(Org) list 조회 성공!!") + spew.Dump(result) + cblogger.Debug(result) + } + fmt.Println("\n# ListOrgRegion() Test Finished") + + case 4: + fmt.Println("Start ListOrgZone() ...") + result, err := handler.ListOrgZone() + if err != nil { + cblogger.Error("Zone(Org) list 조회 실패 : ", err) + } else { + fmt.Println("\n==================================================================================================") + cblogger.Debug("Zone(Org) list 조회 성공") + spew.Dump(result) + cblogger.Debug(result) + } + fmt.Println("\n# ListOrgZone() Test Finished") + + case 0: + fmt.Println("Exit") + return + } + } + } +} + +func main() { + cblogger.Info("NCP Resource Test") + + handleRegionZone() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "RegionZone": + resourceHandler, err = cloudConnection.CreateRegionZoneHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_SecurityHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_SecurityHandler.go new file mode 100644 index 000000000..6e974633e --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_SecurityHandler.go @@ -0,0 +1,353 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2020.12. + +package main + +import ( + "os" + "errors" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +func handleSecurity() { + cblogger.Debug("Start Security Resource Test") + + ResourceHandler, err := getResourceHandler("Security") + if err != nil { + panic(err) + } + handler := ResourceHandler.(irs.SecurityHandler) + + //config := readConfigFile() + //VmID := config.Ncp.VmID + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ Security Management Test ]") + + // Related APIs on NCP classic services are not supported. + fmt.Println("1. Create Security") + fmt.Println("2. List Security") + fmt.Println("3. Get Security") + fmt.Println("4. Delete Security") + fmt.Println("0. Quit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + var commandNum int + + securityName := "ncp-sg01" + securityId := "661762" //NCP default S/G + // securityId := "214436" + // vpcId := "vpc-c0479cab" + + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + return + + case 1: + reqInfo := irs.SecurityReqInfo{ + IId: irs.IID{ + NameId: securityName, + }, + } + result, err := handler.CreateSecurity(reqInfo) + if err != nil { + cblogger.Infof(" Security 생성 실패 : ", err) + } else { + cblogger.Info("Security 생성 결과") + //cblogger.Info(result) + spew.Dump(result) + // if result != nil { + // securityId = result.IId.SystemId // 조회 및 삭제를 위해 생성된 ID로 변경 + // spew.Dump(securityId) + // } + } + + cblogger.Info("\nCreateSecurity() Test Finished") + + case 2: + result, err := handler.ListSecurity() + if err != nil { + cblogger.Infof(" Security list 조회 실패 : ", err) + } else { + cblogger.Info("Security list 조회 결과") + //cblogger.Info(result) + spew.Dump(result) + cblogger.Infof("=========== S/G 목록 수 : [%d] ================", len(result)) + if result != nil { + securityId = result[0].IId.SystemId // 조회 및 삭제를 위해 생성된 ID로 변경 + } + } + + cblogger.Info("\nListSecurity Test Finished") + + case 3: + cblogger.Infof("[%s] Security 조회 테스트", securityId) + result, err := handler.GetSecurity(irs.IID{SystemId: securityId}) + if err != nil { + cblogger.Infof(securityId, " Security 조회 실패 : ", err) + } else { + cblogger.Infof("[%s] Security 조회 결과 : [%v]", securityId, result) + spew.Dump(result) + } + + cblogger.Info("\nGetSecurity Test Finished") + + // case 3: + // cblogger.Infof("[%s] Security 생성 테스트", securityName) + + // securityReqInfo := irs.SecurityReqInfo{ + // IId: irs.IID{NameId: securityName}, + // VpcIID: irs.IID{SystemId: vpcId}, + // SecurityRules: &[]irs.SecurityRuleInfo{ //보안 정책 설정 + // { + // FromPort: "20", + // ToPort: "22", + // IPProtocol: "tcp", + // Direction: "inbound", + // }, + + // { + // FromPort: "80", + // ToPort: "80", + // IPProtocol: "tcp", + // Direction: "inbound", + // }, + // { + // FromPort: "8080", + // ToPort: "8080", + // IPProtocol: "tcp", + // Direction: "inbound", + // }, + // { + // FromPort: "-1", + // ToPort: "-1", + // IPProtocol: "icmp", + // Direction: "inbound", + // }, + // { + // FromPort: "443", + // ToPort: "443", + // IPProtocol: "tcp", + // Direction: "outbound", + // }, + // { + // FromPort: "8443", + // ToPort: "9999", + // IPProtocol: "tcp", + // Direction: "outbound", + // }, + // /* + // { + // //FromPort: "8443", + // //ToPort: "9999", + // IPProtocol: "-1", // 모두 허용 (포트 정보 없음) + // Direction: "inbound", + // }, + // */ + // }, + // } + + // result, err := handler.CreateSecurity(securityReqInfo) + // if err != nil { + // cblogger.Infof(securityName, " Security 생성 실패 : ", err) + // } else { + // cblogger.Infof("[%s] Security 생성 결과 : [%v]", securityName, result) + // spew.Dump(result) + // } + + case 4: + cblogger.Infof("[%s] Security 삭제 테스트", securityId) + result, err := handler.DeleteSecurity(irs.IID{SystemId: securityId}) + if err != nil { + cblogger.Infof(securityId, " Security 삭제 실패 : ", err) + } else { + cblogger.Infof("[%s] Security 삭제 결과 : [%s]", securityId, result) + } + } + } + } +} + +func testErr() error { + //return awserr.Error("") + return errors.New("") + // return ncloud.New("504", "찾을 수 없음", nil) +} + +func main() { + cblogger.Info("NCP Resource Test") + /* + err := testErr() + spew.Dump(err) + if err != nil { + cblogger.Info("에러 발생") + awsErr, ok := err.(awserr.Error) + spew.Dump(awsErr) + spew.Dump(ok) + if ok { + if "404" == awsErr.Code() { + cblogger.Info("404!!!") + } else { + cblogger.Info("404 아님") + } + } + } + */ + + handleSecurity() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + // NOTE Just for test + cblogger.Info(config.Ncp.NcpAccessKeyID) + cblogger.Info(config.Ncp.NcpSecretKey) + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + //case "Publicip": + // resourceHandler, err = cloudConnection.CreatePublicIPHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + //case "VNic": + // resourceHandler, err = cloudConnection.CreateVNicHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + // cblogger.Info(config.Ncp.NcpAccessKeyID) + // cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMHandler.go new file mode 100644 index 000000000..4af94736a --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMHandler.go @@ -0,0 +1,377 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2020.09. + +package main + +import ( + "os" + "errors" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +func testErr() error { + return errors.New("") + // return ncloud.New("504", "찾을 수 없음", nil) +} + +// Test VM Lifecycle Management (Create/Suspend/Resume/Reboot/Terminate) +func handleVM() { + cblogger.Debug("Start VMHandler Resource Test") + + ResourceHandler, err := getResourceHandler("VM") + if err != nil { + panic(err) + } + + vmHandler := ResourceHandler.(irs.VMHandler) + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ VM Management Test ]") + fmt.Println("1. Start(Create) VM") + fmt.Println("2. Get VM Info") + fmt.Println("3. Suspend VM") + fmt.Println("4. Resume VM") + fmt.Println("5. Reboot VM") + + fmt.Println("6. Terminate VM") + fmt.Println("7. Get VMStatus") + fmt.Println("8. List VMStatus") + fmt.Println("9. List VM") + fmt.Println("0. Exit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + //config := readConfigFile() + VmID := irs.IID{SystemId: "19313606"} + + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + return + + case 1: + vmReqInfo := irs.VMReqInfo{ + // ImageType: irs.MyImage, + ImageType: irs.PublicImage, + + // # NCP에서는 VM instance 이름에 대문자 허용 안되므로 VMHandler 내부에서 소문자로 변환되어 반영됨. + // Caution!! : Under bar 문자 허용 안됨. + IId: irs.IID{NameId: "ncp-test-vm-007"}, + + // Caution!!) /home/sean/go/src/github.com/cloud-barista/ncp/ncp/main/config/config.yaml 에서 해당 region을 설정해야 그 region에 VM이 생성됨. + + //(참고) When Region is 'DEN'. + //VMSpec := "SPSVRSTAND000063" vCPU 8EA, Memory 64GB, [SSD]Disk 50GB", + //Image ID : SPSW0LINUX000031 + + // KR + ImageIID: irs.IID{NameId: "Ubuntu Server 18.04 (64-bit)", SystemId: "SPSW0LINUX000130"}, // $$$ PublicImage $$$ + VMSpecName: "SPSVRSTAND000073", + + // KR + // ImageIID: irs.IID{NameId: "Windows Server 2012 (64bit) R2 English Edition", SystemId: "SPSW0WINNTEN0015A"}, + // VMSpecName: "SPSVRSTAND000005A", + + // KR + // ImageIID: irs.IID{NameId: "Windows Server (64bit)", SystemId: "96215"}, // $$$ MyImage $$$ + // VMSpecName: "SPSVRSTAND000005A", + + // USWN + //ImageIID: irs.IID{NameId: "Ubuntu Server 18.04 (64-bit)", SystemId: "SPSW0LINUX000130"}, + //VMSpecName: "SPSVRSTAND000025", + + // USWN + //ImageIID: irs.IID{NameId: "WordPress-Ubuntu-16.04-64", SystemId: "SPSW0LINUX000088"}, + //VMSpecName: "SPSVRSTAND000050", + + // DEN : + //ImageIID: irs.IID{NameId: "Ubuntu Server 18.04 (64-bit)", SystemId: "SPSW0LINUX000130"}, + //VMSpecName: "SPSVRSTAND000025", + + // DEN : + //ImageIID: irs.IID{NameId: "centOS-6.3-64", SystemId: "SPSW0LINUX000031"}, + //VMSpecName: "SPSVRSSD00000006", + + // JPN + //ImageIID: irs.IID{NameId: "Ubuntu Server 18.04 (64-bit)", SystemId: "SPSW0LINUX000130"}, + //VMSpecName: "SPSVRSTAND000025", + + // SGN + //ImageIID: irs.IID{NameId: "Ubuntu Server 18.04 (64-bit)", SystemId: "SPSW0LINUX000130"}, + //VMSpecName: "SPSVRSTAND000025", + + // HK + //ImageIID: irs.IID{NameId: "ubuntu-16.04", SystemId: "SPSW0LINUX000095"}, + //VMSpecName: "SPSVRSTAND000052", + + KeyPairIID: irs.IID{SystemId: "NCP-keypair-06"}, + // KeyPairIID: irs.IID{SystemId: "ncp-key-0-cjheqe9jcupqtmoaa6bg"}, + + // # NCP Classic 2세대 service에서 subnet, VPC 지정은 미지원 + VpcIID: irs.IID{SystemId: "vpc-01-cdn00lhjcupqjjlde1rg"}, + SubnetIID: irs.IID{SystemId: "subnet-01-cdn00lhjcupqjjlde1s0"}, + + // SecurityGroupIIDs 미지정시, NCP default 값으로서 "ncloud-default-acg"인 "293807이 적용됨. + // SecurityGroupIIDs: []irs.IID{{SystemId: "293807"},{SystemId: "332703"}}, + SecurityGroupIIDs: []irs.IID{{SystemId: "1333707"}}, + + VMUserPasswd: "abcd000abcd", + } + + vmInfo, err := vmHandler.StartVM(vmReqInfo) + if err != nil { + //panic(err) + cblogger.Error(err) + } else { + cblogger.Info("VM 생성 완료!!", vmInfo) + spew.Dump(vmInfo) + } + cblogger.Info("\nCreateVM Test Finished") + + case 2: + vmInfo, err := vmHandler.GetVM(VmID) + if err != nil { + cblogger.Errorf("[%s] VM info. 조회 실패", VmID) + cblogger.Error(err) + } else { + cblogger.Infof("[%s] VM info. 조회 결과", VmID) + spew.Dump(vmInfo) + } + cblogger.Info("\nGetVM Test Finished") + + case 3: + cblogger.Info("Start Suspend VM ...") + result, err := vmHandler.SuspendVM(VmID) + if err != nil { + cblogger.Errorf("[%s] VM Suspend 실패 - [%s]", VmID, result) + cblogger.Error(err) + } else { + cblogger.Infof("[%s] VM Suspend 실행 성공 - [%s]", VmID, result) + } + cblogger.Info("\nSuspendVM Test Finished") + + case 4: + cblogger.Info("Start Resume VM ...") + result, err := vmHandler.ResumeVM(VmID) + if err != nil { + cblogger.Errorf("[%s] VM Resume 실패 - [%s]", VmID, result) + cblogger.Error(err) + } else { + cblogger.Infof("[%s] VM Resume 실행 성공 - [%s]", VmID, result) + } + cblogger.Info("\nResumeVM Test Finished") + + case 5: + cblogger.Info("Start Reboot VM ...") + result, err := vmHandler.RebootVM(VmID) + if err != nil { + cblogger.Errorf("[%s] VM Reboot 실패 - [%s]", VmID, result) + cblogger.Error(err) + } else { + cblogger.Infof("[%s] VM Reboot 실행 성공 - [%s]", VmID, result) + } + cblogger.Info("\nRebootVM Test Finished") + + case 6: + cblogger.Info("Start Terminate VM ...") + result, err := vmHandler.TerminateVM(VmID) + if err != nil { + cblogger.Errorf("[%s] VM Terminate 실패 - [%s]", VmID, result) + cblogger.Error(err) + } else { + cblogger.Infof("[%s] VM Terminate 실행 성공 - [%s]", VmID, result) + } + cblogger.Info("\nTerminateVM Test Finished") + + case 7: + cblogger.Info("Start Get VM Status...") + vmStatus, err := vmHandler.GetVMStatus(VmID) + if err != nil { + cblogger.Errorf("[%s] Get VM Status 실패", VmID) + cblogger.Error(err) + } else { + cblogger.Infof("[%s] Get VM Status 실행 성공 : [%s]", VmID, vmStatus) + } + cblogger.Info("\nGet VMStatus Test Finished") + + case 8: + cblogger.Info("Start ListVMStatus ...") + vmStatusInfos, err := vmHandler.ListVMStatus() + if err != nil { + cblogger.Error("ListVMStatus 실패") + cblogger.Error(err) + } else { + cblogger.Info("ListVMStatus 실행 성공") + spew.Dump(vmStatusInfos) + } + cblogger.Info("\nListVM Status Test Finished") + + case 9: + cblogger.Info("Start ListVM ...") + vmList, err := vmHandler.ListVM() + if err != nil { + cblogger.Error("ListVM 실패") + cblogger.Error(err) + } else { + cblogger.Info("ListVM 실행 성공") + cblogger.Info("=========== VM 목록 ================") + spew.Dump(vmList) + cblogger.Infof("=========== VM 목록 수 : [%d] ================", len(vmList)) + if len(vmList) > 0 { + VmID = vmList[0].IId + } + } + } + } +} +} + +func main() { + cblogger.Info("NCP Resource Test") + + handleVM() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region, config.Ncp.Zone) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMSpecHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMSpecHandler.go new file mode 100644 index 000000000..9b8a24f54 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VMSpecHandler.go @@ -0,0 +1,272 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2020.09. + +package main + +import ( + "os" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +// Test VMSpec +func handleVMSpec() { + cblogger.Debug("Start VMSpecHandler Resource Test") + + ResourceHandler, err := getResourceHandler("VMSpec") + if err != nil { + panic(err) + } + + handler := ResourceHandler.(irs.VMSpecHandler) + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ VMSpec Resource Test ]") + fmt.Println("1. ListVMSpec()") + fmt.Println("2. GetVMSpec()") + fmt.Println("3. ListOrgVMSpec()") + fmt.Println("4. GetOrgVMSpec()") + fmt.Println("0. Exit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + // reqVMSpec := config.Ncp.VMSpec + // reqVMSpec := "SPSVRSTAND000049" // Count: "2", Mem: "2048", Disk: 50G, 해당 Image ID : SPSW0LINUX000029, SPSW0LINUX000031, + reqVMSpec := "SPSVRHICPU000001" // Count: "2", Mem: "4096", Disk: 50G, 해당 Image ID : SPSW0LINUX000031, SPSW0LINUX000130, + // reqVMSpec := "SPSVRSTAND000063" // Region: 'DEN', vCPU 8EA, Memory 64GB, [SSD]Disk 50GB", Image ID : SPSW0LINUX000031 + + // reqVMSpec := "SPSVRSTAND000006A" // Region: HK, VCpu: "8", Mem: "16384", + + config := readConfigFile() + reqRegion := config.Ncp.Region + cblogger.Info("config.Ncp.Region : ", reqRegion) + + cblogger.Info("reqVMSpec : ", reqVMSpec) + + var commandNum int + + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 1: + fmt.Println("Start ListVMSpec() ...") + result, err := handler.ListVMSpec() + if err != nil { + cblogger.Error("VMSpec list 조회 실패 : ", err) + } else { + fmt.Println("\n==================================================================================================================") + cblogger.Debug("VMSpec list 조회 성공!!") + spew.Dump(result) + cblogger.Debug(result) + cblogger.Infof("전체 VMSpec list 개수 : [%d]", len(result)) + } + + fmt.Println("\nListVMSpec() Test Finished") + + case 2: + fmt.Println("Start GetVMSpec() ...") + result, err := handler.GetVMSpec(reqVMSpec) + if err != nil { + cblogger.Error(reqVMSpec, " VMSpec 정보 조회 실패 : ", err) + } else { + fmt.Println("\n==================================================================================================================") + cblogger.Debugf("VMSpec[%s] 정보 조회 성공!!", reqVMSpec) + spew.Dump(result) + cblogger.Debug(result) + //cblogger.Infof(result) + } + + fmt.Println("\nGetVMSpec() Test Finished") + + case 3: + fmt.Println("Start ListOrgVMSpec() ...") + result, err := handler.ListOrgVMSpec() + if err != nil { + cblogger.Error("VMSpec Org list 조회 실패 : ", err) + } else { + cblogger.Debug("VMSpec Org list 조회 성공") + spew.Dump(result) + cblogger.Debug(result) + //spew.Dump(result) + //fmt.Println(result) + //fmt.Println("=========================") + //fmt.Println(result) + cblogger.Infof("전체 목록 개수 : [%d]", len(result)) + } + + fmt.Println("\nListOrgVMSpec() Test Finished") + + case 4: + fmt.Println("Start GetOrgVMSpec() ...") + result, err := handler.GetOrgVMSpec(reqVMSpec) + if err != nil { + cblogger.Error(reqVMSpec, " VMSpec Org 정보 조회 실패 : ", err) + } else { + cblogger.Debugf("VMSpec[%s] Org 정보 조회 성공", reqVMSpec) + spew.Dump(result) + cblogger.Debug(result) + //fmt.Println(result) + } + + fmt.Println("\nGetOrgVMSpec() Test Finished") + + case 0: + fmt.Println("Exit") + return + } + } + } +} + +func main() { + cblogger.Info("NCP Resource Test") + + handleVMSpec() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VPCHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VPCHandler.go new file mode 100644 index 000000000..83e2ae591 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/Test_VPCHandler.go @@ -0,0 +1,270 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Tester Example. +// +// by ETRI, 2020.09. + +package main + +import ( + "os" + "fmt" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + 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" + cblog "github.com/cloud-barista/cb-log" + + // ncpdrv "github.com/cloud-barista/ncp/ncp" // For local test + ncpdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncp" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Resource Test") + cblog.SetLevel("info") +} + +// Test VMSpec +func handleVPC() { + cblogger.Debug("Start VMSpecHandler Resource Test") + + ResourceHandler, err := getResourceHandler("VPC") + if err != nil { + panic(err) + } + + handler := ResourceHandler.(irs.VPCHandler) + + for { + fmt.Println("\n============================================================================================") + fmt.Println("[ VPC Resource Test ]") + fmt.Println("1. CreateVPC()") + fmt.Println("2. ListVPC()") + fmt.Println("3. GetVPC()") + fmt.Println("4. DeleteVPC()") + fmt.Println("0. Exit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + subnetReqName := "myTest-subnet-03" + vpcIId := irs.IID{NameId: "ncp-vpc-0-cjo2smhjcupp70i7acu0"} + + var subnetInfoList []irs.SubnetInfo + subnetInfo := irs.SubnetInfo{ + IId: irs.IID{ + NameId: subnetReqName, + }, + IPv4_CIDR: "10.0.0.0/24", + } + subnetInfoList = append(subnetInfoList, subnetInfo) + + // vpcReqInfo := irs.VPCReqInfo{ + // IId: irs.IID{NameId: reqVPCName, SystemId: vpcId}, + // } + + vpcReqInfo := irs.VPCReqInfo{ + IId: vpcIId, + IPv4_CIDR: "10.0.0.0/16", + SubnetInfoList: subnetInfoList, + } + + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 1: + fmt.Println("Start CreateVPC() ...") + + vpcInfo, err := handler.CreateVPC(vpcReqInfo) + if err != nil { + //panic(err) + cblogger.Error(err) + cblogger.Error("VPC 생성 실패 : ", err) + } else { + cblogger.Info("VPC 생성 완료!!", vpcInfo) + spew.Dump(vpcInfo) + cblogger.Debug(vpcInfo) + } + fmt.Println("\nCreateVPC() Test Finished") + + case 2: + fmt.Println("Start ListVPC() ...") + result, err := handler.ListVPC() + if err != nil { + cblogger.Error("VPC list 조회 실패 : ", err) + } else { + cblogger.Info("VPC list 조회 성공!!") + spew.Dump(result) + cblogger.Debug(result) + cblogger.Infof("전체 list 개수 : [%d]", len(result)) + } + fmt.Println("\nListVMSpec() Test Finished") + + case 3: + fmt.Println("Start GetVPC() ...") + if vpcInfo, err := handler.GetVPC(vpcIId); err != nil { + cblogger.Error(err) + cblogger.Error("VPC 정보 조회 실패 : ", err) + } else { + cblogger.Info("VPC 정보 조회 성공!!") + spew.Dump(vpcInfo) + } + fmt.Println("\nGetVPC() Test Finished") + + case 4: + fmt.Println("Start DeleteVPC() ...") + if result, err := handler.DeleteVPC(vpcIId); err != nil { + cblogger.Error(err) + cblogger.Error("VPC 삭제 실패 : ", err) + } else { + cblogger.Info("VPC 삭제 성공!!") + spew.Dump(result) + } + fmt.Println("\nGetVPC() Test Finished") + + case 0: + fmt.Println("Exit") + return + } + } + } +} + +func main() { + cblogger.Info("NCP Resource Test") + + handleVPC() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpdrv.NcpDriver) + + config := readConfigFile() + connectionInfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ClientId: config.Ncp.NcpAccessKeyID, + ClientSecret: config.Ncp.NcpSecretKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.Ncp.Region, + Zone: config.Ncp.Zone, + }, + } + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + cloudConnection, errCon := cloudDriver.ConnectCloud(connectionInfo) + if errCon != nil { + return nil, errCon + } + + var resourceHandler interface{} + var err error + + switch handlerType { + case "Image": + resourceHandler, err = cloudConnection.CreateImageHandler() + case "Security": + resourceHandler, err = cloudConnection.CreateSecurityHandler() + case "VNetwork": + resourceHandler, err = cloudConnection.CreateVPCHandler() + case "VM": + resourceHandler, err = cloudConnection.CreateVMHandler() + case "VMSpec": + resourceHandler, err = cloudConnection.CreateVMSpecHandler() + case "VPC": + resourceHandler, err = cloudConnection.CreateVPCHandler() + } + + if err != nil { + return nil, err + } + return resourceHandler, nil +} + +// Region : 사용할 리전명 (ex) ap-northeast-2 +// ImageID : VM 생성에 사용할 AMI ID (ex) ami-047f7b46bd6dd5d84 +// BaseName : 다중 VM 생성 시 사용할 Prefix이름 ("BaseName" + "_" + "숫자" 형식으로 VM을 생성 함.) (ex) mcloud-barista +// VmID : 라이프 사이트클을 테스트할 EC2 인스턴스ID +// InstanceType : VM 생성시 사용할 인스턴스 타입 (ex) t2.micro +// KeyName : VM 생성시 사용할 키페어 이름 (ex) mcloud-barista-keypair +// MinCount : +// MaxCount : +// SubnetId : VM이 생성될 VPC의 SubnetId (ex) subnet-cf9ccf83 +// SecurityGroupID : 생성할 VM에 적용할 보안그룹 ID (ex) sg-0df1c209ea1915e4b +type Config struct { + Ncp struct { + NcpAccessKeyID string `yaml:"ncp_access_key_id"` + NcpSecretKey string `yaml:"ncp_secret_key"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + + ImageID string `yaml:"image_id"` + + VmID string `yaml:"ncp_instance_id"` + BaseName string `yaml:"base_name"` + InstanceType string `yaml:"instance_type"` + KeyName string `yaml:"key_name"` + MinCount int64 `yaml:"min_count"` + MaxCount int64 `yaml:"max_count"` + + SubnetID string `yaml:"subnet_id"` + SecurityGroupID string `yaml:"security_group_id"` + + PublicIP string `yaml:"public_ip"` + } `yaml:"ncp"` +} + +//환경 설정 파일 읽기 +//환경변수 CBSPIDER_PATH 설정 후 해당 폴더 하위에 /config/config.yaml 파일 생성해야 함. +func readConfigFile() Config { + // Set Environment Value of Project Root Path + goPath := os.Getenv("GOPATH") + rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + //rootpath := "D:/Workspace/mcloud-barista-config" + // /mnt/d/Workspace/mcloud-barista-config/config/config.yaml + cblogger.Debugf("Test Data 설정파일 : [%]", rootPath+"/config/config.yaml") + + data, err := os.ReadFile(rootPath + "/config/config.yaml") + //data, err := ioutil.ReadFile("D:/Workspace/mcloud-bar-config/config/config.yaml") + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + + cblogger.Info("Loaded ConfigFile...") + //spew.Dump(config) + //cblogger.Info(config) + + // NOTE Just for test + //cblogger.Info(config.Ncp.NcpAccessKeyID) + //cblogger.Info(config.Ncp.NcpSecretKey) + + // NOTE Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/config/config.yaml.sample b/cloud-control-manager/cloud-driver/drivers/ncp/main/config/config.yaml.sample new file mode 100644 index 000000000..3c7d28401 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/config/config.yaml.sample @@ -0,0 +1,47 @@ +ncp: + + # NCP Credential Info + ncp_access_key_id: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + ncp_secret_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + region: KR + zone: KR-1 + # region: KR + # zone: KR-2 + # region: HK + # zone: HK-1 + # region: SGN + # zone: SGN-1 + # region: JPN + # zone: JPN-1 + # region: DEN + # zone: DEN-1 + # region: USWN + # zone: USWN-1 + + + # Note!! : + # region: KR (RegionNo: 1), zone: KR-1 (ZoneNo: 2) or KR-2 (ZoneNo: 3) + # region: HK (RegionNo: 3), zone: HK-1 (ZoneNo: 20) + # region: SGN (RegionNo: 7), zone: SGN-1 (ZoneNo: 70) + # region: JPN (RegionNo: 8), zone: JPN-1 (ZoneNo: 80) + # region: USWN (RegionNo: 9), zone: USWN-1 (ZoneNo: 90) + # region: DEN (RegionNo: 10), zone: DEN-1 (ZoneNo: 100) + + # AMI + image_id: SPSW0LINUX000130 + + # NCP + ncp_instance_id: 5344572 + base_name: Cloud-Barista-VM-Test-10 + instance_type: SPSVRHICPU000001 + key_name: Sean01-AuthKey + min_count: 1 + max_count: 1 + + # Network + #subnet_id: subnet-cf9ccf83 + security_group_id: 293807 + + # PublicIP Test + #public_ip: 13.209.241.236 \ No newline at end of file diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/goget-ncpsdk.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/goget-ncpsdk.sh new file mode 100755 index 000000000..844135491 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/goget-ncpsdk.sh @@ -0,0 +1,7 @@ + +export GIT_TERMINAL_PROMPT=1 +export GOPRIVATE="github.com/cloud-barista" + +go get -u github.com/NaverCloudPlatform/ncloud-sdk-go-v2@latest +go get -u github.com/cloud-barista/cb-store@latest + diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_disk.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_disk.sh new file mode 100755 index 000000000..d3d396c3b --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_disk.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_DiskHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_image.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_image.sh new file mode 100755 index 000000000..aabad167c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_image.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_ImageHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_keypair.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_keypair.sh new file mode 100755 index 000000000..02d1639a5 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_keypair.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_KeyPairHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_myimage.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_myimage.sh new file mode 100755 index 000000000..91211174a --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_myimage.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_MyImageHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_nlb.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_nlb.sh new file mode 100755 index 000000000..db56e1923 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_nlb.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_NLBHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_region-zone.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_region-zone.sh new file mode 100755 index 000000000..595e3b5f5 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_region-zone.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_RegionZoneHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_security.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_security.sh new file mode 100755 index 000000000..252ea90f4 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_security.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_SecurityHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vm.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vm.sh new file mode 100755 index 000000000..b65b1d5af --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vm.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_VMHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vmspec.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vmspec.sh new file mode 100755 index 000000000..17ec78feb --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vmspec.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_VMSpecHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vpc.sh b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vpc.sh new file mode 100755 index 000000000..a62a0061c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/main/test_vpc.sh @@ -0,0 +1,3 @@ +source ../../../../../setup.env + +go run Test_VPCHandler.go diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/CommonNcpFunc.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/CommonNcpFunc.go new file mode 100644 index 000000000..a2406c4a8 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/CommonNcpFunc.go @@ -0,0 +1,173 @@ +package resources + +import ( + "encoding/json" + "fmt" + "sync" + "time" + "os" + "os/exec" + "strings" + "math/rand" + + cblog "github.com/cloud-barista/cb-log" + "github.com/sirupsen/logrus" + + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" +) + +var once sync.Once +var cblogger *logrus.Logger +var calllogger *logrus.Logger + +//Cloud Object를 JSON String 타입으로 변환 +func ConvertJsonString(v interface{}) (string, error) { + jsonBytes, errJson := json.Marshal(v) + + if errJson != nil { + cblogger.Error("JSON 변환 실패") + cblogger.Error(errJson) + return "", errJson + } + + jsonString := string(jsonBytes) + + return jsonString, nil +} + +// int32 to string 변환 : String(), int64 to string 변환 : strconv.Itoa() +func String(n int32) string { + buf := [11]byte{} + pos := len(buf) + i := int64(n) + signed := i < 0 + if signed { + i = -i + } + for { + pos-- + buf[pos], i = '0'+byte(i%10), i/10 + if i == 0 { + if signed { + pos-- + buf[pos] = '-' + } + return string(buf[pos:]) + } + } +} + +func InitLog() { + once.Do(func() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Cloud Driver") + calllogger = call.GetLogger("HISCALL") + }) +} + +func LoggingError(hiscallInfo call.CLOUDLOGSCHEMA, err error) { + cblogger.Error(err.Error()) + hiscallInfo.ErrorMSG = err.Error() + calllogger.Error(call.String(hiscallInfo)) +} + +func LoggingInfo(hiscallInfo call.CLOUDLOGSCHEMA, start time.Time) { + hiscallInfo.ElapsedTime = call.Elapsed(start) + calllogger.Info(call.String(hiscallInfo)) +} + +func GetCallLogScheme(zoneInfo string, resourceType call.RES_TYPE, resourceName string, apiName string) call.CLOUDLOGSCHEMA { + cblogger.Info(fmt.Sprintf("Call %s %s", call.NCP, apiName)) + + return call.CLOUDLOGSCHEMA{ + CloudOS: call.NCP, + RegionZone: zoneInfo, + ResourceType: resourceType, + ResourceName: resourceName, + CloudOSAPI: apiName, + } +} + +func logAndReturnError(callLogInfo call.CLOUDLOGSCHEMA, givenErrString string, v interface{}) (error) { + newErr := fmt.Errorf(givenErrString + " %v", v) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return newErr +} + +func CheckFolderAndCreate(folderPath string) error { + // Check if the Folder Exists and Create it + if _, err := os.Stat(folderPath); os.IsNotExist(err) { + if err := os.Mkdir(folderPath, 0700); err != nil { + return err + } + } + return nil +} + +func GetOriginalNameId(IID2NameId string) string { + reversedNameId := Reverse(IID2NameId) + originalNameId := reversedNameId[:21] + originalNameId = strings.TrimSuffix(IID2NameId, Reverse(originalNameId)) + + return originalNameId +} + +func Reverse(s string) (result string) { + for _,v := range s { + result = string(v) + result + } + return +} + +func RunCommand(cmdName string, cmdArgs []string) (string, error) { + + /* + Ref) + var ( + cmdOut []byte + cmdErr error + ) + */ + + cblogger.Infof("cmdName : %s", cmdName) + cblogger.Infof("cmdArgs : %s", cmdArgs) + + //if cmdOut, cmdErr = exec.Command(cmdName, cmdArgs...).Output(); cmdErr != nil { + if cmdOut, cmdErr := exec.Command(cmdName, cmdArgs...).CombinedOutput(); cmdErr != nil { + fmt.Fprintln(os.Stderr, "There was an error running command: ", cmdErr) + //panic("Can't exec the command: " + cmdErr1.Error()) + fmt.Println(fmt.Sprint(cmdErr) + ": " + string(cmdOut)) + os.Exit(1) + + return string(cmdOut), cmdErr + } else { + fmt.Println("cmdOut : ", string(cmdOut)) + + return string(cmdOut), nil + } +} + +func convertTimeFormat(inputTime string) (time.Time, error) { + // Parse the input time using the given layout + layout := "2006-01-02T15:04:05-0700" + parsedTime, err := time.Parse(layout, inputTime) + if err != nil { + newErr := fmt.Errorf("Failed to Parse the Input Time Format!!") + cblogger.Error(newErr.Error()) + return time.Time{}, newErr + } + + return parsedTime, nil +} + +func randSeq(n int) string { + var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + rand.Seed(time.Now().UnixNano()) + + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/DiskHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/DiskHandler.go new file mode 100644 index 000000000..2fa768a9c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/DiskHandler.go @@ -0,0 +1,755 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Example for PoC Test. +// +// by ETRI, 2023.07. + +package resources + +import ( + // "errors" + "fmt" + // "io/ioutil" + // "os" + "strconv" + "strings" + "time" + // "github.com/davecgh/go-spew/spew" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + + 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" +) + +const ( + DefaultDiskSize string = "10" +) + +type NcpDiskHandler struct { + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +// Caution : Incase of NCP, there must be a created VM to create a new disk volume. +func (diskHandler *NcpDiskHandler) CreateDisk(diskReqInfo irs.DiskInfo) (irs.DiskInfo, error) { + cblogger.Info("NCP Driver: called CreateDisk()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Zone, call.DISK, diskReqInfo.IId.NameId, "CreateDisk()") // HisCall logging + + if strings.EqualFold(diskReqInfo.IId.NameId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk NameId!!", "") + return irs.DiskInfo{}, rtnErr + } + + // $$$ At least one VM is required to create new disk volume in case of NCP. + instanceList, err := diskHandler.GetNcpVMList() + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Instacne List :", err) + return irs.DiskInfo{}, rtnErr + } + var instanceNo string + if len(instanceList) < 1 { + cblogger.Info("### VM Instance does Not Exist!!") + rtnErr := logAndReturnError(callLogInfo, "At least one VM is required to create new disk volume in case of NCP.", "") + return irs.DiskInfo{}, rtnErr + } else { + instanceNo = *instanceList[0].ServerInstanceNo // InstanceNo of any VM on the Zone + cblogger.Infof("# VM instanceNo : [%v]", instanceNo) + } + + reqDiskType := diskReqInfo.DiskType // Option : 'default', 'SSD' or 'HDD' + reqDiskSize := diskReqInfo.DiskSize // Range : 10~2000(GB) + + if strings.EqualFold(reqDiskType, "") || strings.EqualFold(reqDiskType, "default") { + reqDiskType = "SSD" // In case, Volume Type is not specified. + } + if strings.EqualFold(reqDiskSize, "") || strings.EqualFold(reqDiskSize, "default") { + reqDiskSize = DefaultDiskSize // In case, Volume Size is not specified. + } + + // Covert String to Int64 + reqDiskSizeInt, err := strconv.ParseInt(reqDiskSize, 10, 64) // Caution : Need 64bit int + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Parse to Get 64bit int. : ", err) + return irs.DiskInfo{}, rtnErr + } + if reqDiskSizeInt < 10 || reqDiskSizeInt > 2000 { // Range : 10~2000(GB) + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk Size. Disk Size Must be between 10 and 2000(GB).", "") + return irs.DiskInfo{}, rtnErr + } + + storageReq := server.CreateBlockStorageInstanceRequest{ + BlockStorageName: ncloud.String(diskReqInfo.IId.NameId), + BlockStorageSize: &reqDiskSizeInt, // *** Required (Not Optional + ServerInstanceNo: ncloud.String(instanceNo), // *** Required (Not Optional) + DiskDetailTypeCode: ncloud.String(reqDiskType), + } + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.CreateBlockStorageInstance(&storageReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create New Disk Volume. : ", err) + return irs.DiskInfo{}, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.BlockStorageInstanceList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find the Created New Disk Volume Info!!", "") + return irs.DiskInfo{}, rtnErr + } else { + cblogger.Info("Succeeded in Creating New Block Storage Volume.") + } + + newDiskIID := irs.IID{NameId: *result.BlockStorageInstanceList[0].BlockStorageName, SystemId: *result.BlockStorageInstanceList[0].BlockStorageInstanceNo} + // Wait for Disk Creation Process finished + curStatus, err := diskHandler.WaitForDiskCreation(newDiskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Wait for the Disk Creation. : ", err) + return irs.DiskInfo{}, rtnErr + } + cblogger.Infof("==> New Disk Volume Status : [%s]", curStatus) + + // Wait for Disk Attachment finished + curStatus, waitErr := diskHandler.WaitForDiskAttachment(newDiskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Wait for the Disk Attachement. : ", waitErr) + return irs.DiskInfo{}, rtnErr + } + cblogger.Infof("==> Disk Status : [%s]", string(curStatus)) + + // Caution!! + // Incase of NCP, there must be a created VM to create a new disk volume. + // Therefore, the status of the new disk volume is 'Attached' after creation. + // ### Need to be 'Available' status after disk creation process like other CSP (with detachment). + isDetached, err := diskHandler.DetachDisk(newDiskIID, irs.IID{SystemId: instanceNo}) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Detach the Disk Volume : ", err) + return irs.DiskInfo{}, rtnErr + } else if !isDetached { + rtnErr := logAndReturnError(callLogInfo, "Failed to Detach the Disk Volume!!", "") + return irs.DiskInfo{}, rtnErr + } + + newDiskInfo, err := diskHandler.GetDisk(newDiskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to the Get Disk Info!! : ", err) + return irs.DiskInfo{}, rtnErr + } + return newDiskInfo, nil +} + +func (diskHandler *NcpDiskHandler) ListDisk() ([]*irs.DiskInfo, error) { + cblogger.Info("NCP Driver: called ListDisk()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Zone, call.DISK, "ListDisk()", "ListDisk()") // HisCall logging + + vmHandler := NcpVMHandler{ + RegionInfo: diskHandler.RegionInfo, + VMClient: diskHandler.VMClient, + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Zone No of the Zone Code : ", err) + return nil, rtnErr + } + storageReq := server.GetBlockStorageInstanceListRequest{ + ZoneNo: zoneNo, // $$$ Caution!! : Not ZoneCode + } + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.GetBlockStorageInstanceList(&storageReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Block Storage List from NCP : ", err) + return nil, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + var diskInfoList []*irs.DiskInfo + if len(result.BlockStorageInstanceList) < 1 { + cblogger.Info("### Block Storage does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting Block Storage list from NCP.") + for _, storage := range result.BlockStorageInstanceList { + storageInfo, err := diskHandler.MappingDiskInfo(*storage) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Map Block Storage Info : ", err) + return nil, rtnErr + } + diskInfoList = append(diskInfoList, &storageInfo) + } + } + // cblogger.Infof("# DiskInfo List count : [%d]", len(diskInfoList)) + return diskInfoList, nil +} + +func (diskHandler *NcpDiskHandler) GetDisk(diskIID irs.IID) (irs.DiskInfo, error) { + cblogger.Info("NCP Driver: called GetDisk()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "GetDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk SystemId!!", "") + return irs.DiskInfo{}, rtnErr + } + + diskInfo, err := diskHandler.GetNcpDiskInfo(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Disk Info : ", err) + return irs.DiskInfo{}, rtnErr + } + + storageInfo, err := diskHandler.MappingDiskInfo(*diskInfo) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Map the Block Storage Info : ", err) + return irs.DiskInfo{}, rtnErr + } + return storageInfo, nil +} + +func (diskHandler *NcpDiskHandler) ChangeDiskSize(diskIID irs.IID, size string) (bool, error) { + cblogger.Info("NCP Driver: called ChangeDiskSize()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "ChangeDiskSize()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk SystemId!!", "") + return false, rtnErr + } + + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Disk Status : ", err) + return false, rtnErr + } else if strings.EqualFold(string(curStatus), string(irs.DiskAttached)) { + rtnErr := logAndReturnError(callLogInfo, "Failed to Change the Disk Size. The Disk Status is 'Attached'. Change Size after Detaching.", "") + return false, rtnErr + } + + // Covert String to Int64 + reqDiskSizeInt, err := strconv.ParseInt(size, 10, 64) // Caution : Need 64bit int + if err != nil { + panic(err) + } + if reqDiskSizeInt < 10 || reqDiskSizeInt > 2000 { // Range : 10~2000(GB) + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk Size. Disk Size Must be between 10 and 2000(GB).", "") + return false, rtnErr + } + changeReq := server.ChangeBlockStorageVolumeSizeRequest{ + BlockStorageInstanceNo: ncloud.String(diskIID.SystemId), + BlockStorageSize: &reqDiskSizeInt, + } + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.ChangeBlockStorageVolumeSize(&changeReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Change the Block Storage Volume Size : ", err) + return false, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + rtnErr := logAndReturnError(callLogInfo, "Failed to Change the Block Storage Volume Size!!", "") + return false, rtnErr + } else { + cblogger.Info("Succeeded in Changing the Block Storage Volume Size.") + } + cblogger.Infof("# Chaneged Size : %s(GB)", strconv.FormatInt(*result.BlockStorageInstanceList[0].BlockStorageSize/(1024*1024*1024), 10)) + + return true, nil +} + +func (diskHandler *NcpDiskHandler) DeleteDisk(diskIID irs.IID) (bool, error) { + cblogger.Info("NCP Driver: called DeleteDisk()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "DeleteDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk SystemId!!", "") + return false, rtnErr + } + + isBasicBlockStorage, err := diskHandler.IsBasicBlockStorage(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Disk Info. : ", err) + return false, rtnErr + } else if isBasicBlockStorage { + rtnErr := logAndReturnError(callLogInfo, "Failed to Delete the Disk Volume. The Disk is Basic(Bootable) Disk Volume.", "") + return false, rtnErr + } + + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Disk Status : ", err) + return false, rtnErr + } + if strings.EqualFold(string(curStatus), string(irs.DiskAttached)) { + rtnErr := logAndReturnError(callLogInfo, "The Block Storage is Attached to a VM. First Detach it before Deleting!!", "") + return false, rtnErr + } + + delReq := server.DeleteBlockStorageInstancesRequest { + BlockStorageInstanceNoList: []*string{ncloud.String(diskIID.SystemId),}, + } + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.DeleteBlockStorageInstances(&delReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Delete the Block Storage : ", err) + return false, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + rtnErr := logAndReturnError(callLogInfo, "Failed to Delete the Block Storage!!", "") + return false, rtnErr + } else { + cblogger.Info("Succeeded in Deleting the Block Storage.") + } + + return true, nil +} + +func (diskHandler *NcpDiskHandler) AttachDisk(diskIID irs.IID, vmIID irs.IID) (irs.DiskInfo, error) { + cblogger.Info("NCP Driver: called AttachDisk()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "AttachDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk SystemId!!", "") + return irs.DiskInfo{}, rtnErr + } else if strings.EqualFold(vmIID.SystemId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid VM SystemId!!", "") + return irs.DiskInfo{}, rtnErr + } + + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Disk Status : ", err) + return irs.DiskInfo{}, rtnErr + } else if strings.EqualFold(string(curStatus), string(irs.DiskAttached)) { + rtnErr := logAndReturnError(callLogInfo, "Failed to Attach the Disk Volume. The Disk is already 'Attached'.", "") + return irs.DiskInfo{}, rtnErr + } + + attachReq := server.AttachBlockStorageInstanceRequest{ + ServerInstanceNo: ncloud.String(vmIID.SystemId), + BlockStorageInstanceNo: ncloud.String(diskIID.SystemId), + } + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.AttachBlockStorageInstance(&attachReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Attach the Block Storage : ", err) + return irs.DiskInfo{}, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + rtnErr := logAndReturnError(callLogInfo, "Failed to Attach the Block Storage!!", "") + return irs.DiskInfo{}, rtnErr + } else { + cblogger.Info("Succeeded in Attaching the Block Storage.") + } + + // Wait for Disk Attachment finished + curStatus, waitErr := diskHandler.WaitForDiskAttachment(diskIID) + if waitErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Wait for the Disk Attachment. : ", waitErr) + return irs.DiskInfo{}, rtnErr + } + cblogger.Infof("==> Disk Status : [%s]", string(curStatus)) + + diskInfo, err := diskHandler.GetDisk(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Disk Info!! : ", err) + return irs.DiskInfo{}, rtnErr + } + return diskInfo, nil +} + +func (diskHandler *NcpDiskHandler) DetachDisk(diskIID irs.IID, ownerVM irs.IID) (bool, error) { + cblogger.Info("NCP Driver: called DetachDisk()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "DetachDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk SystemId!!", "") + return false, rtnErr + } + + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Disk Status : ", err) + return false, rtnErr + } else if !strings.EqualFold(string(curStatus), string(irs.DiskAttached)) { + rtnErr := logAndReturnError(callLogInfo, "Failed to Detach the Disk Volume. The Disk Status is Not 'Attached'", "") + return false, rtnErr + } + + isBasicBlockStorage, err := diskHandler.IsBasicBlockStorage(diskIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Disk Info. : ", err) + return false, rtnErr + } else if isBasicBlockStorage { + rtnErr := logAndReturnError(callLogInfo, "Failed to Detach the Disk Volume. The Disk is Basic(Bootable) Disk Volume.", "") + return false, rtnErr + } + + detachReq := server.DetachBlockStorageInstancesRequest{ + BlockStorageInstanceNoList: []*string{ncloud.String(diskIID.SystemId),}, + } + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.DetachBlockStorageInstances(&detachReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Detach the Block Storage : ", err) + return false, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + newErr := fmt.Errorf("Failed to Detach the Block Storage!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + // return false, newErr + + // Try again!! + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.DetachBlockStorageInstances(&detachReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Detach the Block Storage : ", err) + return false, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + rtnErr := logAndReturnError(callLogInfo, "Failed to Detach the Block Storage!!", "") + return false, rtnErr + } else { + cblogger.Info("Succeeded in Detaching the Block Storage.") + } + } else { + cblogger.Info("Succeeded in Detaching the Block Storage.") + } + + // Wait for Disk Detachment finished + curStatus, waitErr := diskHandler.WaitForDiskDetachment(diskIID) + if waitErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Wait to Get Disk Info. : ", waitErr) + return false, rtnErr + } + cblogger.Infof("==> Disk Status : [%s]", string(curStatus)) + + return true, nil +} + +func (diskHandler *NcpDiskHandler) GetNcpDiskInfo(diskIID irs.IID) (*server.BlockStorageInstance, error) { + cblogger.Info("NCP Cloud Driver: called GetNCPDiskInfo()") + InitLog() + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "DetachDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + rtnErr := logAndReturnError(callLogInfo, "Invalid Disk SystemId!!", "") + return nil, rtnErr + } + + vmHandler := NcpVMHandler{ + RegionInfo: diskHandler.RegionInfo, + VMClient: diskHandler.VMClient, + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Zone No of the Zone Code : ", err) + return nil, rtnErr + } + storageNoList := []*string{ncloud.String(diskIID.SystemId), + } + storageReq := server.GetBlockStorageInstanceListRequest{ + ZoneNo: zoneNo, // Caution : Not ZoneCode + BlockStorageInstanceNoList: storageNoList, + } + result, err := diskHandler.VMClient.V2Api.GetBlockStorageInstanceList(&storageReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the Block Storage Info : ", err) + return nil, rtnErr + } + if len(result.BlockStorageInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Find Any Block Storage Info with the ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting NCP Block Storage Info.") + } + return result.BlockStorageInstanceList[0], nil +} + +// Waiting for up to 500 seconds during Disk creation until Disk info. can be get +func (diskHandler *NcpDiskHandler) WaitForDiskCreation(diskIID irs.IID) (irs.DiskStatus, error) { + cblogger.Info("===> Since Disk info. cannot be retrieved immediately after Disk creation, it waits until running.") + + curRetryCnt := 0 + maxRetryCnt := 500 + for { + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Status : [%v] ", err) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } else { + cblogger.Infof("Succeeded in Getting the Disk Status : [%s]", string(curStatus)) + } + + cblogger.Infof("===> Disk Status : [%s]", string(curStatus)) + + switch string(curStatus) { + case "Creating": + curRetryCnt++ + cblogger.Infof("The Disk is still 'Creating', so wait for a second more before inquiring the Disk info.") + time.Sleep(time.Second * 2) + if curRetryCnt > maxRetryCnt { + newErr := fmt.Errorf("Despite waiting for a long time(%d sec), the Disk status is %s, so it is forcibly finished.", maxRetryCnt, string(curStatus)) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } + default: + cblogger.Infof("===> ### The Disk 'Creation' is finished, stopping the waiting.") + return curStatus, nil + //break + } + } +} + +// Waiting for up to 500 seconds during Disk Attachment +func (diskHandler *NcpDiskHandler) WaitForDiskAttachment(diskIID irs.IID) (irs.DiskStatus, error) { + curRetryCnt := 0 + maxRetryCnt := 500 + for { + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Status : [%v] ", err) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } else { + cblogger.Infof("Succeeded in Getting the Disk Status : [%s]", curStatus) + } + + cblogger.Infof("===> Disk Status : [%s]", string(curStatus)) + + switch string(curStatus) { + case string(irs.DiskCreating), string(irs.DiskAvailable), string(irs.DiskDeleting), string(irs.DiskError), "Attaching", "Detaching", "Unknown" : + curRetryCnt++ + cblogger.Infof("The Disk is still [%s], so wait for a second more during the Disk 'Attachment'.", string(curStatus)) + time.Sleep(time.Second * 2) + if curRetryCnt > maxRetryCnt { + newErr := fmt.Errorf("Despite waiting for a long time(%d sec), the Disk status is '%s', so it is forcibly finished.", maxRetryCnt, string(curStatus)) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } + default: + cblogger.Infof("===> ### The Disk 'Attachment' is finished, stopping the waiting.") + return curStatus, nil + //break + } + } +} + +// Waiting for up to 500 seconds during Disk Attachment +func (diskHandler *NcpDiskHandler) WaitForDiskDetachment(diskIID irs.IID) (irs.DiskStatus, error) { + curRetryCnt := 0 + maxRetryCnt := 500 + for { + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Status : [%v] ", err) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } else { + cblogger.Infof("Succeeded in Getting the Disk Status : [%s]", curStatus) + } + + cblogger.Infof("===> Disk Status : [%s]", string(curStatus)) + + switch string(curStatus) { + case string(irs.DiskCreating), string(irs.DiskAttached), string(irs.DiskDeleting), string(irs.DiskError), "Attaching", "Detaching", "Unknown" : + curRetryCnt++ + cblogger.Infof("The Disk is still [%s], so wait for a second more during the Disk 'Detachment'.", string(curStatus)) + time.Sleep(time.Second * 2) + if curRetryCnt > maxRetryCnt { + newErr := fmt.Errorf("Despite waiting for a long time(%d sec), the Disk status is '%s', so it is forcibly finished.", maxRetryCnt, string(curStatus)) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } + default: + cblogger.Infof("===> ### The Disk 'Detachment' is finished, stopping the waiting.") + return curStatus, nil + //break + } + } +} + +func (diskHandler *NcpDiskHandler) GetDiskStatus(diskIID irs.IID) (irs.DiskStatus, error) { + cblogger.Info("NCP Cloud Driver: called GetDiskStatus()") + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + return irs.DiskError, newErr + } + + diskInfo, err := diskHandler.GetNcpDiskInfo(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Info : [%v] ", err) + cblogger.Error(newErr.Error()) + return irs.DiskError, newErr + } + cblogger.Infof("# Disk Status of NCP : [%s]", *diskInfo.BlockStorageInstanceStatusName) + return ConvertDiskStatus(*diskInfo.BlockStorageInstanceStatusName), nil +} + +func (diskHandler *NcpDiskHandler) MappingDiskInfo(storage server.BlockStorageInstance) (irs.DiskInfo, error) { + cblogger.Info("NCP Cloud Driver: called MappingDiskInfo()") + + if strings.EqualFold(ncloud.StringValue(storage.BlockStorageInstanceNo), "") { + newErr := fmt.Errorf("Invalid Block Storage Info!!") + cblogger.Error(newErr.Error()) + return irs.DiskInfo{}, newErr + } + + // cblogger.Info("\n\n### storage : ") + // spew.Dump(storage) + // cblogger.Info("\n") + + convertedTime, err := convertTimeFormat(*storage.CreateDate) + if err != nil { + newErr := fmt.Errorf("Failed to Convert the Time Format!!") + cblogger.Error(newErr.Error()) + return irs.DiskInfo{}, newErr + } + + diskInfo := irs.DiskInfo{ + IId: irs.IID{ + NameId: ncloud.StringValue(storage.BlockStorageName), + SystemId: ncloud.StringValue(storage.BlockStorageInstanceNo), + }, + DiskSize: strconv.FormatInt((*storage.BlockStorageSize)/(1024*1024*1024), 10), + Status: ConvertDiskStatus(ncloud.StringValue(storage.BlockStorageInstanceStatusName)), // Not BlockStorageInstanceStatus.Code + CreatedTime: convertedTime, + DiskType: ncloud.StringValue(storage.DiskDetailType.Code), + } + + if strings.EqualFold(ncloud.StringValue(storage.BlockStorageInstanceStatusName), "attached") { + vmHandler := NcpVMHandler{ + RegionInfo: diskHandler.RegionInfo, + VMClient: diskHandler.VMClient, + } + vmInfo, err := vmHandler.GetNcpVMInfo(ncloud.StringValue(storage.ServerInstanceNo)) + if err != nil { + newErr := fmt.Errorf("Failed to Get the VM Info. : [%v] ", err) + cblogger.Error(newErr.Error()) + return irs.DiskInfo{}, newErr + } + diskInfo.OwnerVM = irs.IID{ + NameId: ncloud.StringValue(vmInfo.ServerName), + SystemId: ncloud.StringValue(storage.ServerInstanceNo), + } + } + + keyValueList := []irs.KeyValue{ + {Key: "DeviceName", Value: ncloud.StringValue(storage.DeviceName)}, + {Key: "RegionCode", Value: ncloud.StringValue(storage.Region.RegionCode)}, + {Key: "ZoneCode", Value: ncloud.StringValue(storage.Zone.ZoneCode)}, + {Key: "BlockStorageType", Value: ncloud.StringValue(storage.BlockStorageType.CodeName)}, + {Key: "BlockStorageDiskType", Value: ncloud.StringValue(storage.DiskType.CodeName)}, + } + diskInfo.KeyValueList = keyValueList + + return diskInfo, nil +} + +func ConvertDiskStatus(diskStatus string) irs.DiskStatus { + cblogger.Info("NCP Cloud Driver: called ConvertDiskStatus()") + + var resultStatus irs.DiskStatus + switch strings.ToLower(diskStatus) { + case "creating": + resultStatus = irs.DiskCreating + case "detached": + resultStatus = irs.DiskAvailable + case "attached": + resultStatus = irs.DiskAttached + case "deleting": + resultStatus = irs.DiskDeleting + case "error": + resultStatus = irs.DiskError + case "attaching": + resultStatus = "Attaching" + case "detaching": + resultStatus = "Detaching" + default: + resultStatus = "Unknown" + } + return resultStatus +} + +func (diskHandler *NcpDiskHandler) GetNcpVMList() ([]*server.ServerInstance, error) { + cblogger.Info("NCP Cloud Driver: called GetNcpVMList()") + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, "GetNcpVMList()", "GetNcpVMList()") + + vmHandler := NcpVMHandler{ + RegionInfo: diskHandler.RegionInfo, + VMClient: diskHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(diskHandler.RegionInfo.Region) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Region No of the Region Code : ", err) + return nil, rtnErr + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Zone No of the Zone Code : ", err) + return nil, rtnErr + } + instanceReq := server.GetServerInstanceListRequest{ + ServerInstanceNoList: []*string{}, + RegionNo: regionNo, // Caution : Not RegionCode + ZoneNo: zoneNo, // Caution : Not ZoneCode + } + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find the VM Instance list from NCP : ", err) + return nil, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.ServerInstanceList) < 1 { + cblogger.Info("### VM Instance does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting VM Instance list from NCP") + } + return result.ServerInstanceList, nil +} + +func (diskHandler *NcpDiskHandler) IsBasicBlockStorage(diskIID irs.IID) (bool, error) { + cblogger.Info("NCP Cloud Driver: called IsBasicBlockStorage()") + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + return false, newErr + } + + diskInfo, err := diskHandler.GetNcpDiskInfo(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Info : [%v] ", err) + cblogger.Error(newErr.Error()) + return false, newErr + } + if strings.EqualFold(*diskInfo.BlockStorageType.Code, "BASIC") { // Ex) "BASIC", "SVRBS", ... + return true, nil + } else { + cblogger.Infof("# BlockStorageType : [%s]", *diskInfo.BlockStorageType.CodeName) // Ex) "Basic BS", "Server BS", ... + return false, nil + } +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go new file mode 100644 index 000000000..3118a1437 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/ImageHandler.go @@ -0,0 +1,188 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP Image Handler +// +// by ETRI, 2020.09. + +package resources + +import ( + // "errors" + "fmt" + "strconv" + "strings" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + + 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/sirupsen/logrus" +) + +type NcpImageHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +var cblogger2 *logrus.Logger + +func init() { + cblogger2 = cblog.GetLogger("NCP ImageHandler") // cblog is a global variable. +} + +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()") + + if strings.EqualFold(imageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Image SystemId") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.ImageInfo{}, 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 irs.ImageInfo{}, newErr + } + imageInfo := MappingImageInfo(*ncpImageInfo) + return imageInfo, nil +} + +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()") + + vmHandler := NcpVMHandler{ + RegionInfo: imageHandler.RegionInfo, + VMClient: imageHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(imageHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + imageReq := server.GetServerImageProductListRequest{ + ProductCode: nil, + RegionNo: regionNo, // CAUTION!! : When searching image Info by RegionNo + } + callLogStart := call.Start() + result, err := imageHandler.VMClient.V2Api.GetServerImageProductList(&imageReq) + if err != nil { + cblogger.Error(*result.ReturnMessage) + newErr := fmt.Errorf("Failed to Find Image list from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.ProductList) < 1 { + newErr := fmt.Errorf("Failed to Find Any Image Info.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting NCP Image list.") + } + + var vmImageList []*irs.ImageInfo + for _, image := range result.ProductList { + imageInfo := MappingImageInfo(*image) + vmImageList = append(vmImageList, &imageInfo) + } + cblogger.Info("# Supported Image Product count : ", len(vmImageList)) + return vmImageList, nil +} + +func MappingImageInfo(serverImage server.Product) irs.ImageInfo { + cblogger.Info("NCP Classic Cloud Driver: called MappingImageInfo()!") + + imageInfo := irs.ImageInfo{ + IId: irs.IID{ // NOTE 주의 : serverImage.ProductCode -> ProductName 으로 + NameId: *serverImage.ProductCode, + SystemId: *serverImage.ProductCode, + }, + GuestOS: *serverImage.ProductDescription, + Status: "available", + } + + //Image OS Information + keyValueList := []irs.KeyValue{ + {Key: "PlatformType", Value: *serverImage.PlatformType.CodeName}, + {Key: "InfraResourceType", Value: *serverImage.InfraResourceType.CodeName}, + {Key: "BaseBlockStorageSize(GB)", Value: strconv.FormatFloat(float64(*serverImage.BaseBlockStorageSize)/(1024*1024*1024), 'f', 0, 64)}, + //{Key: "OsInformation", Value: *serverImage.OsInformation}, + //{Key: "DB Type", Value: *serverImage.DbKindCode}, + //{Key: "NCP GenerationCode", Value: *serverImage.GenerationCode}, + } + keyValueList = append(keyValueList, irs.KeyValue{Key: "Description", Value: *serverImage.ProductDescription}) + imageInfo.KeyValueList = keyValueList + return imageInfo +} + +func (imageHandler *NcpImageHandler) CreateImage(imageReqInfo irs.ImageReqInfo) (irs.ImageInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called CreateImage()!") + + return irs.ImageInfo{}, fmt.Errorf("Does not support CreateImage() yet!!") +} + +func (imageHandler *NcpImageHandler) CheckWindowsImage(imageIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called CheckWindowsImage()") + + return false, fmt.Errorf("Does not support CheckWindowsImage() yet!!") +} + +func (imageHandler *NcpImageHandler) DeleteImage(imageIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called DeleteImage()!") + + return false, fmt.Errorf("Does not support DeleteImage() yet!!") +} + +func (imageHandler *NcpImageHandler) GetNcpImageInfo(imageIID irs.IID) (*server.Product, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetNcpImageInfo()!!") + + InitLog() + callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Zone, call.VMIMAGE, imageIID.SystemId, "GetNcpImageInfo()") + + if strings.EqualFold(imageIID.SystemId, "") { + createErr := fmt.Errorf("Invalid Image SystemId") + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return nil, createErr + } + + imageReq := server.GetServerImageProductListRequest{ProductCode: ncloud.String(imageIID.SystemId)} + callLogStart := call.Start() + result, err := imageHandler.VMClient.V2Api.GetServerImageProductList(&imageReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find Image list from NCP : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.ProductList) < 1 { + newErr := fmt.Errorf("Failed to Find Any Image info with the SystemId : [%s]", imageIID.SystemId) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + cblogger.Info("Succeeded in Getting NCP Image info.") + return result.ProductList[0], nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/KeyPairHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/KeyPairHandler.go new file mode 100644 index 000000000..715c13deb --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/KeyPairHandler.go @@ -0,0 +1,252 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP Classic Cloud KeyPair Handler +// +// Created by ETRI, 2020.09. +// Updated by ETRI, 2022.09. +// Updated by ETRI, 2023.09. + +package resources + +import ( + "fmt" + "errors" + "strings" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + // "github.com/davecgh/go-spew/spew" + + 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" + keycommon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/common" +) + +type NcpKeyPairHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +func (keyPairHandler *NcpKeyPairHandler) ListKey() ([]*irs.KeyPairInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called ListKey()!!") + + InitLog() + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, "ListKey()", "ListKey()") + + keypairReq := server.GetLoginKeyListRequest{ + KeyName: nil, + } + callLogStart := call.Start() + result, err := keyPairHandler.VMClient.V2Api.GetLoginKeyList(&keypairReq) // *server.APIClient + if err != nil { + newErr := fmt.Errorf("Failed to Find KeyPairList from NCP Cloud : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var keyPairList []*irs.KeyPairInfo + if len(result.LoginKeyList) > 0 { + for _, keyPair := range result.LoginKeyList { + keyPairInfo := MappingKeyPairInfo(keyPair) + keyPairList = append(keyPairList, &keyPairInfo) + } + return keyPairList, nil + } else { + return nil, errors.New("Failed to Find KeyPairList!!") + } +} + +func (keyPairHandler *NcpKeyPairHandler) CreateKey(keyPairReqInfo irs.KeyPairReqInfo) (irs.KeyPairInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called CreateKey()!!") + + InitLog() + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, keyPairReqInfo.IId.NameId, "CreateKey()") + + strList:= []string{ + keyPairHandler.CredentialInfo.ClientId, + keyPairHandler.CredentialInfo.ClientSecret, + } + hashString, err := keycommon.GenHash(strList) + if err != nil { + newErr := fmt.Errorf("Failed to Generate Hash String : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } + + keypairReq := server.CreateLoginKeyRequest{ + KeyName: ncloud.String(keyPairReqInfo.IId.NameId), + } + callLogStart := call.Start() + // Creates a new key pair with the given name + result, err := keyPairHandler.VMClient.V2Api.CreateLoginKey(&keypairReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create KeyPair: [%s], [%v]", keyPairReqInfo.IId.NameId, err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Infof("(# result.ReturnMessage : %s ", ncloud.StringValue(result.ReturnMessage)) + + // Create PublicKey from PrivateKey + publicKey, makePublicKeyErr := keycommon.MakePublicKeyFromPrivateKey(*result.PrivateKey) + if makePublicKeyErr != nil { + newErr := fmt.Errorf("Failed to Generated the Public Key : [%v]", makePublicKeyErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } + publicKey = strings.TrimSpace(publicKey) + " " + lnxUserName // Append VM User Name + + // Save the publicKey to DB in other to use on VMHandler(Cloud-init) + addKeyErr := keycommon.AddKey("NCP", hashString, keyPairReqInfo.IId.NameId, publicKey) + if addKeyErr != nil { + newErr := fmt.Errorf("Failed to Save the Private Key to DB : [%v]", addKeyErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } + + resultKey, keyError := keyPairHandler.GetKey(keyPairReqInfo.IId) + if keyError != nil { + newErr := fmt.Errorf("Failed to Get the KeyPair Info : [%v]", keyError) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } + + // NCP Key does not have SystemId, so the unique NameId value is also applied to the SystemId + keyPairInfo := irs.KeyPairInfo{ + IId: irs.IID{NameId: keyPairReqInfo.IId.NameId, SystemId: keyPairReqInfo.IId.NameId}, + Fingerprint: resultKey.Fingerprint, + PublicKey: publicKey, // Generated above. Show only when KeyPair Creation. + PrivateKey: *result.PrivateKey, // Show only when KeyPair Creation. + VMUserID: lnxUserName, + } + return keyPairInfo, nil +} + +func (keyPairHandler *NcpKeyPairHandler) GetKey(keyIID irs.IID) (irs.KeyPairInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called GetKey()!!") + + InitLog() + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, keyIID.SystemId, "GetKey()") + + var keyNameId string + if keyIID.SystemId == "" { + keyNameId = keyIID.NameId + } else { + keyNameId = keyIID.SystemId + } + + keypairReq := server.GetLoginKeyListRequest{ // server.GetLoginKey~~~ + KeyName: ncloud.String(keyNameId), // Caution!! + } + callLogStart := call.Start() + result, err := keyPairHandler.VMClient.V2Api.GetLoginKeyList(&keypairReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find the KeyPair Info from NCP Cloud : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.LoginKeyList) > 0 { + keyPairInfo := MappingKeyPairInfo(result.LoginKeyList[0]) + return keyPairInfo, nil + } else { + return irs.KeyPairInfo{}, errors.New("Failed to Find the KeyPair info with the Name!!") + } +} + +func (keyPairHandler *NcpKeyPairHandler) DeleteKey(keyIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud driver: called DeleteKey()!!") + + InitLog() + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, keyIID.NameId, "DeleteKey()") + + var keyNameId string + if keyIID.SystemId == "" { + keyNameId = keyIID.NameId + } else { + keyNameId = keyIID.SystemId + } + cblogger.Infof("KeyPairName to Delete : [%s]", keyNameId) + // Delete the key pair by key 'Name' + + strList:= []string{ + keyPairHandler.CredentialInfo.ClientId, + keyPairHandler.CredentialInfo.ClientSecret, + } + hashString, err := keycommon.GenHash(strList) + if err != nil { + newErr := fmt.Errorf("Failed to Generate Hash String : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + // Because it succeeds unconditionally even if the corresponding keypair does not exist, the existence is checked in advance. + _, keyError := keyPairHandler.GetKey(keyIID) + if keyError != nil { + newErr := fmt.Errorf("Failed to Get the KeyPair with the Name : [%s], [%v]", keyNameId, keyError) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + keypairDelReq := server.DeleteLoginKeyRequest{ + ncloud.String(keyNameId), // Caution!! + } + callLogStart := call.Start() + result, err := keyPairHandler.VMClient.V2Api.DeleteLoginKey(&keypairDelReq) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the KeyPair with the keyNameId : [%s], [%v]", keyNameId, err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Infof("(# result.ReturnMessage : [%s] ", ncloud.StringValue(result.ReturnMessage)) + + // Delete the saved publicKey from DB + delKeyErr := keycommon.DelKey("NCP", hashString, keyNameId) + if delKeyErr != nil { + newErr := fmt.Errorf("Failed to Delete the KeyPair info form DB : [%v]", delKeyErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + cblogger.Infof("Succeeded in Deleting Process of the KeyPair : [%s]\n", keyNameId) + return true, nil +} + +// KeyPair 정보를 추출함 +func MappingKeyPairInfo(NcpKeyPairList *server.LoginKey) irs.KeyPairInfo { + cblogger.Info("NCP Classic Cloud driver: called MappingKeyPairInfo()!!") + + // Note) NCP Key does not have SystemId, so the unique NameId value is also applied to the SystemId + keyPairInfo := irs.KeyPairInfo{ + IId: irs.IID{ + NameId: *NcpKeyPairList.KeyName, + SystemId: *NcpKeyPairList.KeyName, + }, + Fingerprint: *NcpKeyPairList.Fingerprint, + PublicKey: "N/A", + PrivateKey: "N/A", + VMUserID: lnxUserName, + } + + keyValueList := []irs.KeyValue{ + {Key: "CreateDate", Value: *NcpKeyPairList.CreateDate}, + } + keyPairInfo.KeyValueList = keyValueList + return keyPairInfo +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go new file mode 100644 index 000000000..80537b76a --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/MyImageHandler.go @@ -0,0 +1,501 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Example for PoC Test. +// +// by ETRI, 2023.08. + +package resources + +import ( + "fmt" + "strings" + "time" + // "github.com/davecgh/go-spew/spew" + + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + + 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" +) + +type NcpMyImageHandler struct { + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +func (myImageHandler *NcpMyImageHandler) SnapshotVM(snapshotReqInfo irs.MyImageInfo) (irs.MyImageInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called SnapshotVM()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, snapshotReqInfo.IId.SystemId, "SnapshotVM()") + + if strings.EqualFold(snapshotReqInfo.SourceVM.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + + snapshotReq := server.CreateMemberServerImageRequest{ // Not CreateBlockStorageSnapshotInstanceRequest{} + MemberServerImageName: &snapshotReqInfo.IId.NameId, + ServerInstanceNo: &snapshotReqInfo.SourceVM.SystemId, + } + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.CreateMemberServerImage(&snapshotReq) // Not CreateBlockStorageSnapshotInstance + if err != nil { + newErr := fmt.Errorf("Failed to Create New VM Snapshot : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.MemberServerImageList) < 1 { + newErr := fmt.Errorf("Failed to Create New VM Snapshot. Snapshot does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } else { + cblogger.Info("Succeeded in Creating New Snapshot.") + } + + newImageIID := irs.IID{SystemId: *result.MemberServerImageList[0].MemberServerImageNo} + // To Wait for Creating a Snapshot Image + curStatus, err := myImageHandler.WaitForImageSnapshot(newImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Wait for Image Snapshot. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + cblogger.Infof("==> Image Status of the Snapshot : [%s]", string(curStatus)) + + myImageInfo, err := myImageHandler.GetMyImage(newImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get MyImage Info. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + return myImageInfo, nil +} + +// To Manage My Images +func (myImageHandler *NcpMyImageHandler) ListMyImage() ([]*irs.MyImageInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called ListMyImage()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, "ListMyImage()", "ListMyImage()") + + vmHandler := NcpVMHandler{ + RegionInfo: myImageHandler.RegionInfo, + VMClient: myImageHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(myImageHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + imageReq := server.GetMemberServerImageListRequest{ // Not GetBlockStorageSnapshotInstanceDetailRequest{} + RegionNo: regionNo, // Caution!! : RegionNo (Not RegionCode) + } + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.GetMemberServerImageList(&imageReq) // Caution : Not GetBlockStorageSnapshotInstanceDetail() + if err != nil { + newErr := fmt.Errorf("Failed to Get the Snapshot Image Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var imageInfoList []*irs.MyImageInfo + if len(result.MemberServerImageList) < 1 { + cblogger.Info("# Snapshot Image does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting the Snapshot Info List.") + for _, snapshotImage := range result.MemberServerImageList { + imageInfo, err := myImageHandler.MappingMyImageInfo(snapshotImage) + if err != nil { + newErr := fmt.Errorf("Failed to Map MyImage Info!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + } + imageInfoList = append(imageInfoList, imageInfo) + } + } + return imageInfoList, nil +} + +func (myImageHandler *NcpMyImageHandler) GetMyImage(myImageIID irs.IID) (irs.MyImageInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetMyImage()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "GetMyImage()") + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid myImage SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + + memberServerImageInfo, err := myImageHandler.GetNcpMemberServerImageInfo(myImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Member Server Image Info. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + imageInfo, err := myImageHandler.MappingMyImageInfo(&memberServerImageInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Map MyImage Info!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + } + return *imageInfo, nil +} + +func (myImageHandler *NcpMyImageHandler) CheckWindowsImage(myImageIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called CheckWindowsImage()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "CheckWindowsImage()") + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid myImage SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + myImagePlatform, err := myImageHandler.GetOriginImageOSPlatform(myImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get MyImage Info. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + isWindowsImage := false + if strings.Contains(myImagePlatform, "WINDOWS") { + isWindowsImage = true + } + return isWindowsImage, nil +} + +func (myImageHandler *NcpMyImageHandler) DeleteMyImage(myImageIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called DeleteMyImage()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "DeleteMyImage()") + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid myImage SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + snapshotImageNoList := []*string {&myImageIID.SystemId} + delReq := server.DeleteMemberServerImagesRequest{ // Not DeleteBlockStorageSnapshotInstancesRequest{} + MemberServerImageNoList: snapshotImageNoList, + } + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.DeleteMemberServerImages(&delReq) // Not DeleteBlockStorageSnapshotInstances() + if err != nil { + newErr := fmt.Errorf("Failed to Delete the Snapshot Image. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + newErr := fmt.Errorf("Failed to Delete the Snapshot Image.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Deleting the Snapshot Image.") + } + + return true, nil +} + +// Waiting for up to 500 seconds during Taking a Snapshot from a VM +func (myImageHandler *NcpMyImageHandler) WaitForImageSnapshot(myImageIID irs.IID) (irs.MyImageStatus, error) { + cblogger.Info("===> Since Snapshot info. cannot be retrieved immediately after taking a snapshot, waits ....") + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid myImage SystemId!!") + cblogger.Error(newErr.Error()) + return "", newErr + } + + curRetryCnt := 0 + maxRetryCnt := 500 + for { + curStatus, err := myImageHandler.GetMyImageStatus(myImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Image Status. : [%v] ", err) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } else { + cblogger.Infof("Succeeded in Getting the Image Status : [%s]", string(curStatus)) + } + cblogger.Infof("\n ### Image Status : [%s]", string(curStatus)) + + if strings.EqualFold(string(curStatus), "Unavailable") { + curRetryCnt++ + cblogger.Infof("The Image is still 'Unavailable', so wait for a second more before inquiring the Image info.") + time.Sleep(time.Second * 3) + if curRetryCnt > maxRetryCnt { + newErr := fmt.Errorf("Despite waiting for a long time(%d sec), the Image status is %s, so it is forcibly finished.", maxRetryCnt, string(curStatus)) + cblogger.Error(newErr.Error()) + return "Failed. ", newErr + } + } else { + cblogger.Infof("===> ### The Image Snapshot is finished, stopping the waiting.") + return curStatus, nil + //break + } + } +} + +func (myImageHandler *NcpMyImageHandler) GetMyImageStatus(myImageIID irs.IID) (irs.MyImageStatus, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetMyImageStatus()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "GetMyImageStatus()") + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid myImage SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + memberServerImageInfo, err := myImageHandler.GetNcpMemberServerImageInfo(myImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Member Server Image Info. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + cblogger.Infof("### NCP Member Server Image Status : [%s]" , *memberServerImageInfo.MemberServerImageStatus.Code) + myImageStatus := ConvertImageStatus(*memberServerImageInfo.MemberServerImageStatus.Code) + return myImageStatus, nil +} + +func ConvertImageStatus(myImageStatus string) irs.MyImageStatus { + cblogger.Info("NCP Classic Cloud Driver: called ConvertImageStatus()") + // Ref) https://api.ncloud-docs.com/docs/common-vapidatatype-blockstoragesnapshotinstance + var resultStatus irs.MyImageStatus + switch myImageStatus { + case "INIT" : + resultStatus = irs.MyImageUnavailable // "Unavailable" + case "CREAT" : // CREATED + resultStatus = irs.MyImageAvailable // "Available" + default: + resultStatus = "Unknown" + } + return resultStatus +} + +func (myImageHandler *NcpMyImageHandler) MappingMyImageInfo(myImage *server.MemberServerImage) (*irs.MyImageInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called MappingMyImageInfo()!") + + // cblogger.Info("\n\n### myImage in MappingMyImageInfo() : ") + // spew.Dump(myImage) + // cblogger.Info("\n") + + convertedTime, err := convertTimeFormat(*myImage.CreateDate) + if err != nil { + newErr := fmt.Errorf("Failed to Convert the Time Format!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + myImageInfo := &irs.MyImageInfo { + IId: irs.IID{ + NameId: *myImage.MemberServerImageName, + SystemId: *myImage.MemberServerImageNo, + }, + SourceVM: irs.IID{NameId: *myImage.OriginalServerName, SystemId: *myImage.OriginalServerInstanceNo}, + Status: ConvertImageStatus(*myImage.MemberServerImageStatus.Code), + CreatedTime: convertedTime, + } + + keyValueList := []irs.KeyValue{ + {Key: "Region", Value: myImageHandler.RegionInfo.Region}, + {Key: "OriginalImageProductCode", Value: *myImage.OriginalServerImageProductCode}, + {Key: "MyImagePlatformType", Value: *myImage.MemberServerImagePlatformType.CodeName}, + {Key: "CreateDate", Value: *myImage.CreateDate}, + } + myImageInfo.KeyValueList = keyValueList + return myImageInfo, nil +} + +func (myImageHandler *NcpMyImageHandler) GetNcpMemberServerImageInfo(myImageIID irs.IID) (server.MemberServerImage, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetMyImage()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "GetNcpMemberServerImageInfo()") + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid myImage ystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return server.MemberServerImage{}, newErr + } + + vmHandler := NcpVMHandler{ + RegionInfo: myImageHandler.RegionInfo, + VMClient: myImageHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(myImageHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return server.MemberServerImage{}, newErr + } + imageReq := server.GetMemberServerImageListRequest{ // Not GetBlockStorageSnapshotInstanceDetailRequest{} + RegionNo: regionNo, // Caution!! : RegionNo (Not RegionCode) + MemberServerImageNoList: []*string{&myImageIID.SystemId}, + } + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.GetMemberServerImageList(&imageReq) // Caution : Not GetBlockStorageSnapshotInstanceDetail() + if err != nil { + newErr := fmt.Errorf("Failed to Get the Member Server Image List from NCP: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return server.MemberServerImage{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.MemberServerImageList) < 1 { + newErr := fmt.Errorf("Failed to Get the Member Server Image List from NCP. Member Server Image does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return server.MemberServerImage{}, newErr + } else { + cblogger.Info("Succeeded in Getting the Member Server Image Info.") + } + return *result.MemberServerImageList[0], nil +} + +func (myImageHandler *NcpMyImageHandler) GetOriginImageOSPlatform(imageIID irs.IID) (string, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetOriginImageOSPlatform()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, imageIID.SystemId, "GetOriginImageOSPlatform()") + + if strings.EqualFold(imageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + isPublicImage, err := myImageHandler.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) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } else { + imagePlatformType := strings.ToUpper(*ncpImageInfo.PlatformType.CodeName) + var originImagePlatform string + if strings.Contains(imagePlatformType, "UBUNTU") { + originImagePlatform = "UBUNTU" + } else if strings.Contains(imagePlatformType, "CENTOS") { + originImagePlatform = "CENTOS" + } else if strings.Contains(imagePlatformType, "WINDOWS") { + originImagePlatform = "WINDOWS" + } else { + newErr := fmt.Errorf("Failed to Get OriginImageOSPlatform of the Image!!") + cblogger.Error(newErr.Error()) + return "", newErr + } + cblogger.Infof("### OriginImagePlatform : [%s]", originImagePlatform) + return originImagePlatform, nil + } + } else { + memberServerImageInfo, err := myImageHandler.GetNcpMemberServerImageInfo(imageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Member Server Image Info. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + cblogger.Infof("### MyImagePlatformType : [%s]", *memberServerImageInfo.MemberServerImagePlatformType.CodeName) + + imagePlatformType := strings.ToUpper(*memberServerImageInfo.MemberServerImagePlatformType.CodeName) + var originImagePlatform string + if strings.Contains(imagePlatformType, "UBUNTU") { + originImagePlatform = "UBUNTU" + } else if strings.Contains(imagePlatformType, "CENTOS") { + originImagePlatform = "CENTOS" + } else if strings.Contains(imagePlatformType, "WINDOWS") { + originImagePlatform = "WINDOWS" + } else { + newErr := fmt.Errorf("Failed to Get OriginImageOSPlatform of the MyImage!!") + cblogger.Error(newErr.Error()) + return "", newErr + } + cblogger.Infof("### OriginImagePlatform : [%s]", originImagePlatform) + return originImagePlatform, nil + } +} + +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 + } +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/NLBHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/NLBHandler.go new file mode 100644 index 000000000..fb4b5cc56 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/NLBHandler.go @@ -0,0 +1,930 @@ +// Proof of Concepts of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// This is a Cloud Driver Example for PoC Test. +// +// by ETRI, 2023.08. + +package resources + +import ( + "fmt" + "strconv" + "strings" + "time" + // "github.com/davecgh/go-spew/spew" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + lb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/loadbalancer" + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + + 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" +) + +type NcpNLBHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient + LBClient *lb.APIClient +} + +const ( + // NCP Classic LB Algorithm type codes : RR (ROUND ROBIN), LC (LEAST_CONNECTION), SIPHS (Source IP Hash) + DefaultLBAlgorithmType string = "RR" // ROUND ROBIN + + // You can select whether to create a load balancer with public/private IP + // NCP Classic Cloud NLB network type code : PBLIP(Public IP LB), PRVT(Private IP LB). default : PBLIP + NcpPublicNlBType string = "PBLIP" + NcpInternalNlBType string = "PRVT" + + // 'L7HealthCheckPath' required if ProtocolTypeCode value is 'HTTP' or 'HTTPS' for NCP Classic NLB. + DefaulthealthCheckPath string = "/index.html" +) + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Clssic NLBHandler") +} + +// Note : Cloud-Barista supports only this case => [ LB : Listener : VM Group : Health Checker = 1 : 1 : 1 : 1 ] +// NCP Classic NLB Supported regions: Korea, US West, Hong Kong, Singapore, Japan, Germany +// ### Caution!! : Listener, VM Group and Healthchecker all use the same protocol type in NCP Classic NLB.(The Protocol specified by 'ProtocolTypeCode' when created). +func (nlbHandler *NcpNLBHandler) CreateNLB(nlbReqInfo irs.NLBInfo) (createNLB irs.NLBInfo, newErr error) { + cblogger.Info("NPC Classic Cloud Driver: called CreateNLB()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbReqInfo.IId.NameId, "CreateNLB()") + + if strings.EqualFold(nlbReqInfo.IId.NameId, "") { + newErr := fmt.Errorf("Invalid NLB NameId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + + // ### ProtocolTypeCode : Enter the protocol identification code in the load balancer RULE. + // The following codes can be entered for the protocol identification code: HTTP, HTTPS, TCP, SSL + if strings.EqualFold(nlbReqInfo.Listener.Protocol, "HTTP") || strings.EqualFold(nlbReqInfo.Listener.Protocol, "HTTPS") || strings.EqualFold(nlbReqInfo.Listener.Protocol, "TCP") || strings.EqualFold(nlbReqInfo.Listener.Protocol, "SSL"){ + cblogger.Info("# It's Supporting Listener Protocol in NCP Classic!!") + } else { + return irs.NLBInfo{}, fmt.Errorf("Invalid Listener Protocol. Must be 'HTTP', 'HTTPS', 'TCP' or 'SSL' for NCP Classic NLB.") // According to the NCP Classic API document. + } + + if !strings.EqualFold(nlbReqInfo.Listener.Protocol, nlbReqInfo.VMGroup.Protocol) { + return irs.NLBInfo{}, fmt.Errorf("NLB can be created only when Listener.Protocol and VMGroup.Protocol are of the Same Protocol type in case of NCP Classic.") + } + + if !strings.EqualFold(nlbReqInfo.VMGroup.Protocol, nlbReqInfo.HealthChecker.Protocol) { + return irs.NLBInfo{}, fmt.Errorf("NLB can be created only when VMGroup.Protocol and HealthChecker.Protocol are of the Same Protocol type in case of NCP Classic.") + } + + if !strings.EqualFold(nlbReqInfo.VMGroup.Port, nlbReqInfo.HealthChecker.Port) { + return irs.NLBInfo{}, fmt.Errorf("NLB can be created only when VMGroup.Port and HealthChecker.Port are of the Same Number in case of NCP Classic.") + } + + // NCP Classic Cloud NLB network type code : PBLIP(Public IP LB), PRVT(Private IP LB). default : PBLIP + var lbNetType string + if strings.EqualFold(nlbReqInfo.Type, "PUBLIC") || strings.EqualFold(nlbReqInfo.Type, "default") || strings.EqualFold(nlbReqInfo.Type, "") { + lbNetType = NcpPublicNlBType + } else if strings.EqualFold(nlbReqInfo.Type, "INTERNAL") { + lbNetType = NcpInternalNlBType + } + + vmHandler := NcpVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(nlbHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + zoneNo, err := vmHandler.GetZoneNo(nlbHandler.RegionInfo.Zone) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + zoneNoList := []*string{zoneNo} + + // LB Port num. : Min : 1, Max : 65534 + lbPort, err := strconv.ParseInt(nlbReqInfo.Listener.Port, 10, 32) // Caution : Covert String to Int32 + if err != nil { + panic(err) + } + int32lbPort := int32(lbPort) + if int32lbPort < 1 || int32lbPort > 65534 { + newErr := fmt.Errorf("Invalid LB Port Number.(Must be between 1 and 65534)") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + + // VM(Server) Port num. : Min : 1, Max : 65534 + vmPort, err := strconv.ParseInt(nlbReqInfo.VMGroup.Port, 10, 32) // Caution : Covert String to Int32 + if err != nil { + panic(err) + } + int32vmPort := int32(vmPort) + if int32vmPort < 1 || int32vmPort > 65534 { + newErr := fmt.Errorf("Invalid Target VM Port Number.(Must be between 1 and 65534)") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + + // 'L7HealthCheckPath' required if ProtocolTypeCode value is 'HTTP' or 'HTTPS' for NCP Classic NLB. + var healthCheckPath string + if strings.EqualFold(nlbReqInfo.Listener.Protocol, "HTTP") || strings.EqualFold(nlbReqInfo.Listener.Protocol, "HTTPS") { + healthCheckPath = DefaulthealthCheckPath + } + + // ### ProtocolTypeCode : Enter the protocol identification code in the load balancer RULE. + // The following codes can be entered for the protocol identification code: HTTP, HTTPS, TCP, SSL + ruleParameter := []*lb.LoadBalancerRuleParameter{ + { + ProtocolTypeCode: ncloud.String(nlbReqInfo.Listener.Protocol), // *** Required (Not Optional) + LoadBalancerPort: &int32lbPort, // *** Required (Not Optional) + ServerPort: &int32vmPort, // *** Required (Not Optional) + L7HealthCheckPath: ncloud.String(healthCheckPath), // *** Required In case the ProtocolTypeCode is HTTP or HTTPS. + + // ProxyProtocolUseYn: ncloud.String(doesUseProxyProtocol), + // StickySessionUseYn: ncloud.String(doesUseStickySession), + // Http2UseYn: ncloud.String(doesUseHttp2), + + // Can only be set when the ProtocloTypeCode value is HTTPS. (Options : "HTTP" or "HTTPS". Default : HTTP) + // ServerProtocolTypeCode: nlbReqInfo.VMGroup.Protocol, // Does Not support yet through NCP API SDK. + }, + } + + var vmNoList []*string // Caution : var. type + if len(*nlbReqInfo.VMGroup.VMs) > 0 { + var vmIds []*string + for _, IId := range *nlbReqInfo.VMGroup.VMs { + vmId, err := vmHandler.GetVmIdByName(IId.NameId) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP VM ID with VM Name. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + vmIds = append(vmIds, &vmId) + } + vmNoList = vmIds + } else { + cblogger.Info("The VMGroup does Not have any VM Member!!") + } + + // NCP Classic LB Algorithm type codes : RR (ROUND ROBIN), LC (LEAST_CONNECTION), SIPHS (Source IP Hash) + lbReq := lb.CreateLoadBalancerInstanceRequest{ + LoadBalancerName: ncloud.String(nlbReqInfo.IId.NameId), + LoadBalancerAlgorithmTypeCode: ncloud.String(DefaultLBAlgorithmType), + LoadBalancerRuleList: ruleParameter, // *** Required (Not Optional) + ServerInstanceNoList: vmNoList, + NetworkUsageTypeCode: ncloud.String(lbNetType), + RegionNo: regionNo, // Caution!! : RegionNo (Not RegionCode) + ZoneNoList: zoneNoList, // Caution!! : ZoneNoList (Not ZoneCodeList) + } + + callLogStart := call.Start() + result, err := nlbHandler.LBClient.V2Api.CreateLoadBalancerInstance(&lbReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create New NLB : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.LoadBalancerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Create New NLB. NLB does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } else { + cblogger.Info("Succeeded in Creating New NLB.") + } + + newNlbIID := irs.IID{SystemId: *result.LoadBalancerInstanceList[0].LoadBalancerInstanceNo} + _, err = nlbHandler.WaitToGetNlbInfo(newNlbIID) // Wait until the NLB Status is "USED" + if err != nil { + newErr := fmt.Errorf("Failed to Wait For Creating the NLB. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + + nlbInfo, err := nlbHandler.GetNLB(newNlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Created NLB Info. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + return nlbInfo, nil +} + +func (nlbHandler *NcpNLBHandler) ListNLB() ([]*irs.NLBInfo, error) { + cblogger.Info("NPC Classic Cloud Driver: called ListNLB()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", "ListNLB()", "ListNLB()") + + vmHandler := NcpVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(nlbHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + zoneNo, err := vmHandler.GetZoneNo(nlbHandler.RegionInfo.Zone) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + lbReq := lb.GetLoadBalancerInstanceListRequest{ + RegionNo: regionNo, // Caution!! : RegionNo (Not RegionCode) + ZoneNo: zoneNo, // Caution!! : ZoneNo (Not ZoneCode) + } + callLogStart := call.Start() + result, err := nlbHandler.LBClient.V2Api.GetLoadBalancerInstanceList(&lbReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find NLB list from NCP Classic : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var nlbInfoList []*irs.NLBInfo + if len(result.LoadBalancerInstanceList) < 1 { + cblogger.Info("# NLB does Not Exist!!") + } else { + for _, nlb := range result.LoadBalancerInstanceList { + nlbInfo, err := nlbHandler.MappingNlbInfo(nlb) + if err != nil { + newErr := fmt.Errorf("Failed to Map NLB lnfo. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + nlbInfoList = append(nlbInfoList, &nlbInfo) + } + } + return nlbInfoList, nil +} + +func (nlbHandler *NcpNLBHandler) GetNLB(nlbIID irs.IID) (irs.NLBInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetNLB()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbIID.SystemId, "GetNLB()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + return irs.NLBInfo{}, newErr + } + + ncpNlbInfo, err := nlbHandler.GetNcpNlbInfo(nlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NLB info from NCP Classic : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + nlbInfo, err := nlbHandler.MappingNlbInfo(ncpNlbInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Map the NLB Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + return nlbInfo, nil +} + +func (nlbHandler *NcpNLBHandler) DeleteNLB(nlbIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called DeleteNLB()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbIID.SystemId, "DeleteNLB()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + return false, newErr + } + + lbNoList := []*string{ncloud.String(nlbIID.SystemId)} + lbReq := lb.DeleteLoadBalancerInstancesRequest{ + LoadBalancerInstanceNoList: lbNoList, + } + callLogStart := call.Start() + result, err := nlbHandler.LBClient.V2Api.DeleteLoadBalancerInstances(&lbReq) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the NLB : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + newErr := fmt.Errorf("Failed to Delete the NLB!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Deleting the NLB.") + } + + newNlbIID := irs.IID{SystemId: *result.LoadBalancerInstanceList[0].LoadBalancerInstanceNo} + _, err = nlbHandler.WaitForDelNlb(newNlbIID) // Wait until 'provisioningStatus' is "Terminated" + if err != nil { + newErr := fmt.Errorf("Failed to Wait For Deleting the NLB. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + // return false, newErr // Catuton!! : Incase the status is 'Terminated', fail to get NLB info. + } + + return true, nil +} + +func (nlbHandler *NcpNLBHandler) AddVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (irs.VMGroupInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called AddVMs()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbIID.SystemId, "AddVMs()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + + vmHandler := NcpVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + var newVmIdList []*string + if len(*vmIIDs) > 0 { + for _, vmIID := range *vmIIDs { + vmId, err := vmHandler.GetVmIdByName(vmIID.NameId) + if err != nil { + newErr := fmt.Errorf("Failed to Get the VM ID with the VM Name : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMGroupInfo{}, newErr + } + newVmIdList = append(newVmIdList, ncloud.String(vmId)) + } + } else { + newErr := fmt.Errorf("Failded to Find any VM NameId to Add to the VMGroup!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + + addVMReq := lb.AddServerInstancesToLoadBalancerRequest{ + LoadBalancerInstanceNo: ncloud.String(nlbIID.SystemId), + ServerInstanceNoList: newVmIdList, + } + callLogStart := call.Start() + result, err := nlbHandler.LBClient.V2Api.AddServerInstancesToLoadBalancer(&addVMReq) + if err != nil { + newErr := fmt.Errorf("Failed to Add the VM to the Target Group : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.LoadBalancerInstanceList[0].LoadBalancedServerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Add Any VM to the LoadBalancer!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } else { + cblogger.Info("Succeeded in Adding New VM to the LoadBalancer.") + } + + cblogger.Info("\n\n#### Waiting for Changing the NLB Settings!!") + _, err = nlbHandler.WaitToGetNlbInfo(nlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Wait For Changing the NLB. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + + newVMGroupNlbInfo, err := nlbHandler.GetNLB(nlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get NLB info!! [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + return newVMGroupNlbInfo.VMGroup, nil +} + +func (nlbHandler *NcpNLBHandler) RemoveVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called RemoveVMs()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbIID.SystemId, "RemoveVMs()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + vmHandler := NcpVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + var vmIdList []*string + if len(*vmIIDs) > 0 { + for _, vmIID := range *vmIIDs { + vmId, err := vmHandler.GetVmIdByName(vmIID.NameId) + if err != nil { + newErr := fmt.Errorf("Failed to Get the VM ID with the VM Name : [%v]", err) + cblogger.Error(newErr.Error()) + return false, newErr + } + vmIdList = append(vmIdList, ncloud.String(vmId)) // ncloud.String func(v string) *string + } + } else { + newErr := fmt.Errorf("Failed to Find any VM NameId to Remove from the LoadBalancer!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + removeVMReq := lb.DeleteServerInstancesFromLoadBalancerRequest{ + LoadBalancerInstanceNo: ncloud.String(nlbIID.SystemId), + ServerInstanceNoList: vmIdList, + } + callLogStart := call.Start() + result, err := nlbHandler.LBClient.V2Api.DeleteServerInstancesFromLoadBalancer(&removeVMReq) + if err != nil { + newErr := fmt.Errorf("Failed to Remove the VM frome the VMGroup : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + newErr := fmt.Errorf("Failed to Remove the VM from the LoadBalancer!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Removing the VM from the LoadBalancer!!") + } + + cblogger.Info("\n\n#### Waiting for Changing the NLB Settings!!") + _, err = nlbHandler.WaitToGetNlbInfo(nlbIID) // Wait until 'provisioningStatus' is "Changing" -> "Running" + if err != nil { + newErr := fmt.Errorf("Failed to Wait For Changing the NLB. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + return true, nil +} + +func (nlbHandler *NcpNLBHandler) GetVMGroupHealthInfo(nlbIID irs.IID) (irs.HealthInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetVMGroupHealthInfo()") + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbIID.SystemId, "GetVMGroupHealthInfo()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.HealthInfo{}, newErr + } + + ncpNlbInfo, err := nlbHandler.GetNcpNlbInfo(nlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Classic NLB info!! [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.HealthInfo{}, newErr + } + cblogger.Infof("\n### NLB Status : [%s]", *ncpNlbInfo.LoadBalancerInstanceStatus.Code) // Ex) "USED" means "Running" + + var vmGroupHealthInfo irs.HealthInfo + if len(ncpNlbInfo.LoadBalancedServerInstanceList) > 0 { + var allVMs []irs.IID + var healthVMs []irs.IID + var unHealthVMs []irs.IID + + for _, member := range ncpNlbInfo.LoadBalancedServerInstanceList { + allVMs = append(allVMs, irs.IID{NameId: *member.ServerInstance.ServerName, SystemId: *member.ServerInstance.ServerInstanceNo}) // Caution : Not 'VM Member ID' but 'VM System ID' + + // Note : Server Status (Is Not NLB Status) : True (Healthy), False (Unhealthy) + if *member.ServerHealthCheckStatusList[0].ServerStatus { + cblogger.Infof("\n### [%s] is a Healthy VM.", *member.ServerInstance.ServerName) + healthVMs = append(healthVMs, irs.IID{NameId: *member.ServerInstance.ServerName, SystemId: *member.ServerInstance.ServerInstanceNo}) + } else if !*member.ServerHealthCheckStatusList[0].ServerStatus { + cblogger.Infof("\n### [%s] is an Unhealthy VM.", *member.ServerInstance.ServerName) + unHealthVMs = append(unHealthVMs, irs.IID{NameId: *member.ServerInstance.ServerName, SystemId: *member.ServerInstance.ServerInstanceNo}) + } + } + + vmGroupHealthInfo = irs.HealthInfo{ + AllVMs: &allVMs, + HealthyVMs: &healthVMs, + UnHealthyVMs: &unHealthVMs, + } + return vmGroupHealthInfo, nil + } else { + return irs.HealthInfo{}, nil + } +} + +func (nlbHandler *NcpNLBHandler) GetListenerInfo(nlb lb.LoadBalancerInstance) (irs.ListenerInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetListenerInfo()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", *nlb.LoadBalancerInstanceNo, "GetListenerInfo()") + + if strings.EqualFold(*nlb.LoadBalancerInstanceNo, "") { + newErr := fmt.Errorf("Invalid LoadBalancerInstance ID. The LB does Not Exit!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.ListenerInfo{}, newErr + } + + listenerInfo := irs.ListenerInfo{ + Protocol: *nlb.LoadBalancerRuleList[0].ProtocolType.Code, + Port: strconv.FormatInt(int64(*nlb.LoadBalancerRuleList[0].LoadBalancerPort), 10), + DNSName: *nlb.DomainName, + } + virtualIPs := strings.Split(*nlb.VirtualIp, ",") + if len(virtualIPs) >= 2 { + fmt.Println("First part:", virtualIPs[0]) + listenerInfo.IP = virtualIPs[0] + } else { + fmt.Println("nlb.VirtualIp does not contain a comma.") + listenerInfo.IP = *nlb.VirtualIp + } + listenerKVList := []irs.KeyValue{ + // {Key: "NLB_DomainName", Value: *nlb.DomainName}, + } + listenerInfo.KeyValueList = listenerKVList + return listenerInfo, nil +} + +func (nlbHandler *NcpNLBHandler) GetVMGroupInfo(nlb lb.LoadBalancerInstance) (irs.VMGroupInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetVMGroupInfo()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", *nlb.LoadBalancerInstanceNo, "GetVMGroupInfo()") + + if strings.EqualFold(*nlb.LoadBalancerInstanceNo, "") { + newErr := fmt.Errorf("Invalid LoadBalancer No.!!") + cblogger.Error(newErr.Error()) + return irs.VMGroupInfo{}, newErr + } + + // Note : Cloud-Barista supports only this case => [ LB : Listener : VM Group : Health Checker = 1 : 1 : 1 : 1 ] + vmGroupInfo := irs.VMGroupInfo{ + Protocol: *nlb.LoadBalancerRuleList[0].ProtocolType.Code, + Port: strconv.FormatInt(int64(*nlb.LoadBalancerRuleList[0].ServerPort), 10), + } + + if len(nlb.LoadBalancedServerInstanceList) > 0 { + vmHandler := NcpVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + var vmIIds []irs.IID + for _, member := range nlb.LoadBalancedServerInstanceList { + vm, err := vmHandler.GetNcpVMInfo(*member.ServerInstance.ServerInstanceNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP VM Info with ServerInstance No. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + vmIIds = append(vmIIds, irs.IID{ + NameId: *vm.ServerName, + SystemId: *vm.ServerInstanceNo, + }) + } + vmGroupInfo.VMs = &vmIIds + } else { + cblogger.Info("The VMGroup does Not have any VM Member!!") + } + return vmGroupInfo, nil +} + +func (nlbHandler *NcpNLBHandler) GetHealthCheckerInfo(nlb lb.LoadBalancerInstance) (irs.HealthCheckerInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetHealthCheckerInfo()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", *nlb.LoadBalancerInstanceNo, "GetHealthCheckerInfo()") + + if len(nlb.LoadBalancedServerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Get Any NCP VM List.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.HealthCheckerInfo{}, newErr + } + + // ### In case of NCP Classic Cloud, + // When a load balancer is created, a health check is performed with the designated server port, and servers that fail the health check are excluded from the load balancing target. + // In the case of the HTTP service, if you enter the content path in the L7 Health Check field, the normal operation of the content is checked, and servers that fail the health check are excluded from load balancing. Input (example) /somedir/index.html + healthCheckerInfo := irs.HealthCheckerInfo{ + Protocol: *nlb.LoadBalancedServerInstanceList[0].ServerHealthCheckStatusList[0].ProtocolType.Code, + Port: strconv.FormatInt(int64(*nlb.LoadBalancedServerInstanceList[0].ServerHealthCheckStatusList[0].ServerPort), 10), // Note!! : ServerPort + // Interval: int(*ncpTargetGroupList[0].HealthCheckCycle), + Timeout: int(*nlb.ConnectionTimeout), + // Threshold: int(*ncpTargetGroupList[0].HealthCheckUpThreshold), + // CspID: *ncpTargetGroupList[0].TargetGroupNo, + } + keyValueList := []irs.KeyValue{ + {Key: "L7HealthCheckPath", Value: *nlb.LoadBalancedServerInstanceList[0].ServerHealthCheckStatusList[0].L7HealthCheckPath}, + } + healthCheckerInfo.KeyValueList = keyValueList + return healthCheckerInfo, nil +} + +func (nlbHandler *NcpNLBHandler) WaitToGetNlbInfo(nlbIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called WaitToGetNlbInfo()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + return false, newErr + } + + curRetryCnt := 0 + maxRetryCnt := 1000 + for { + curRetryCnt++ + nlbStatus, err := nlbHandler.GetNcpNlbStatus(nlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NLB Provisioning Status : [%v]", err) + cblogger.Error(newErr.Error()) + return false, newErr + } else if strings.EqualFold(nlbStatus, "Running") { // Caution!! + return true, nil + } else { + cblogger.Infof("\n### NLB Status : [%s]", nlbStatus) + } + time.Sleep(5 * time.Second) + if curRetryCnt > maxRetryCnt { + return false, fmt.Errorf("Failed to Create the NLB. Exceeded maximum retry count %d", maxRetryCnt) + } + } +} + +func (nlbHandler *NcpNLBHandler) WaitForDelNlb(nlbIID irs.IID) (bool, error) { + cblogger.Info("NCP Classic Cloud Driver: called WaitForDelNlb()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + return false, newErr + } + + curRetryCnt := 0 + maxRetryCnt := 500 + for { + curRetryCnt++ + nlbStatus, err := nlbHandler.GetNcpNlbStatus(nlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NLB Status : [%v]", err) + cblogger.Error(newErr.Error()) + return false, newErr + } else if !strings.EqualFold(nlbStatus, "Running") && !strings.EqualFold(nlbStatus, "Terminating") { + return true, nil + } else { + cblogger.Infof("\n### NLB Status : [%s]", nlbStatus) + } + time.Sleep(3 * time.Second) + if curRetryCnt > maxRetryCnt { + return false, fmt.Errorf("Failed to Del the NLB. Exceeded maximum retry count %d", maxRetryCnt) + } + } +} + +func (nlbHandler *NcpNLBHandler) GetNcpNlbStatus(nlbIID irs.IID) (string, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetNcpNlbStatus()") + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbIID.SystemId, "GetNcpNlbStatus()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + ncpNlbInfo, err := nlbHandler.GetNcpNlbInfo(nlbIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Classic NLB info!! [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + if strings.EqualFold(*ncpNlbInfo.LoadBalancerInstanceStatus.Code, "USED") { + return "Running", nil + } else if strings.EqualFold(*ncpNlbInfo.LoadBalancerInstanceStatus.Code, "INIT") { + return "Creating", nil + } else { + return *ncpNlbInfo.LoadBalancerInstanceStatus.Code, nil + } +} + +func (nlbHandler *NcpNLBHandler) GetNcpNlbInfo(nlbIID irs.IID) (*lb.LoadBalancerInstance, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetNcpNlbInfo()") + + InitLog() + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbIID.SystemId, "GetNcpNlbInfo()") + + if strings.EqualFold(nlbIID.SystemId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + vmHandler := NcpVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(nlbHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + zoneNo, err := vmHandler.GetZoneNo(nlbHandler.RegionInfo.Zone) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + lbInstanceNoList := []*string{ncloud.String(nlbIID.SystemId)} + lbReq := lb.GetLoadBalancerInstanceListRequest{ + RegionNo: regionNo, // Caution!! : Not RegionCode + ZoneNo: zoneNo, // Caution!! : Not ZoneCode + LoadBalancerInstanceNoList: lbInstanceNoList, + } + callLogStart := call.Start() + result, err := nlbHandler.LBClient.V2Api.GetLoadBalancerInstanceList(&lbReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NLB Info from NCP Classic : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.LoadBalancerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Get Any NLB Info with the ID from NCP Classic!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting the NLB Info.") + } + return result.LoadBalancerInstanceList[0], nil +} + +// NCP Classic LB resource Def. : https://api.ncloud-docs.com/docs/networking-loadbalancing-createloadbalancerinstance +func (nlbHandler *NcpNLBHandler) MappingNlbInfo(nlb *lb.LoadBalancerInstance) (irs.NLBInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called MappingNlbInfo()") + + if strings.EqualFold(*nlb.LoadBalancerInstanceNo, "") { + newErr := fmt.Errorf("Invalid LoadBalancer Instance Info!!") + cblogger.Error(newErr.Error()) + return irs.NLBInfo{}, newErr + } + + // cblogger.Info("\n### NCP NlbInfo") + // spew.Dump(nlb) + + // You can select whether to create a load balancer with public/private IP + // PBLIP(Public IP LB), PRVT(Private IP LB). default : PBLIP + var nlbType string + if strings.EqualFold(*nlb.NetworkUsageType.Code, "PBLIP") { + nlbType = "PUBLIC" + } else if strings.EqualFold(*nlb.NetworkUsageType.Code, "PRVT") { + nlbType = "INTERNAL" + } + + convertedTime, err := convertTimeFormat(*nlb.CreateDate) + if err != nil { + newErr := fmt.Errorf("Failed to Convert the Time Format!!") + cblogger.Error(newErr.Error()) + return irs.NLBInfo{}, newErr + } + + nlbInfo := irs.NLBInfo{ + IId: irs.IID{ + NameId: *nlb.LoadBalancerName, + SystemId: *nlb.LoadBalancerInstanceNo, + }, + // VpcIID: irs.IID{ + // SystemId: *nlb.VpcNo, + // }, + Type: nlbType, + Scope: "REGION", + CreatedTime: convertedTime, + } + + var nlbStatus string + if strings.EqualFold(*nlb.LoadBalancerInstanceStatus.Code, "USED") { + nlbStatus = "Running" + } else { + nlbStatus = *nlb.LoadBalancerInstanceStatus.Code + } + + keyValueList := []irs.KeyValue{ + {Key: "Region", Value: *nlb.Region.RegionCode}, + {Key: "NLB_Status", Value: nlbStatus}, + {Key: "LoadBalancerAlgorithmType", Value: *nlb.LoadBalancerAlgorithmType.CodeName}, + } + nlbInfo.KeyValueList = keyValueList + + // // Caution : If Get Listener info during Changing settings of a NLB., makes an Error. + // if strings.EqualFold(*nlb.LoadBalancerInstanceStatusName, "Changing") { + // cblogger.Info("### The NLB is being Changed Settings Now. Try again after finishing the changing processes.") + // } else { + // // Note : It is assumed that there is only one listener in the LB. + // } + listenerInfo, err := nlbHandler.GetListenerInfo(*nlb) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Listener Info : [%v]", err.Error()) + cblogger.Error(newErr.Error()) + return irs.NLBInfo{}, newErr + } + nlbInfo.Listener = listenerInfo + + if len(nlb.LoadBalancedServerInstanceList) > 0 { + vmGroupInfo, err := nlbHandler.GetVMGroupInfo(*nlb) + if err != nil { + newErr := fmt.Errorf("Failed to Get VMGroup Info from the NLB. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + // return irs.NLBInfo{}, newErr + } + nlbInfo.VMGroup = vmGroupInfo + + // ### In case of NCP Classic Cloud, + // When a load balancer is created, a health check is performed with the designated server port, and servers that fail the health check are excluded from the load balancing target. + // In the case of the HTTP service, if you enter the content path in the L7 Health Check field, the normal operation of the content is checked, and servers that fail the health check are excluded from load balancing. Input (example) /somedir/index.html + healthCheckerInfo, err := nlbHandler.GetHealthCheckerInfo(*nlb) + if err != nil { + newErr := fmt.Errorf("Failed to Get HealthChecker Info. frome the NLB. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + return irs.NLBInfo{}, newErr + } + nlbInfo.HealthChecker = healthCheckerInfo + } + + return nlbInfo, nil +} + +// Note!! : Will be decided later if we would support bellow methoeds or not. +// ------ Frontend Control +func (nlbHandler *NcpNLBHandler) ChangeListener(nlbIID irs.IID, listener irs.ListenerInfo) (irs.ListenerInfo, error) { + + return irs.ListenerInfo{}, fmt.Errorf("Does not support yet!!") +} + +// ------ Backend Control +func (nlbHandler *NcpNLBHandler) ChangeVMGroupInfo(nlbIID irs.IID, vmGroup irs.VMGroupInfo) (irs.VMGroupInfo, error) { + + return irs.VMGroupInfo{}, fmt.Errorf("Does not support yet!!") +} + +func (nlbHandler *NcpNLBHandler) ChangeHealthCheckerInfo(nlbIID irs.IID, healthChecker irs.HealthCheckerInfo) (irs.HealthCheckerInfo, error) { + + return irs.HealthCheckerInfo{}, fmt.Errorf("Does not support yet!!") +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/RegionZoneHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/RegionZoneHandler.go new file mode 100644 index 000000000..6d452a104 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/RegionZoneHandler.go @@ -0,0 +1,284 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP Classic RegionZone Handler +// +// Created by ETRI, 2023.09. +//================================================================================================== + +package resources + +import ( + "fmt" + // "errors" + "sync" + "strings" + // "github.com/davecgh/go-spew/spew" + + // ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + + 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" +) + +// KeyValueList Omission Issue : https://github.com/cloud-barista/cb-spider/issues/930#issuecomment-1734817828 + +type NcpRegionZoneHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +func (regionZoneHandler *NcpRegionZoneHandler) ListRegionZone() ([]*irs.RegionZoneInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called ListRegionZone()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, "ListRegionZone()", "ListRegionZone()") + + regionListReq := server.GetRegionListRequest{} + callLogStart := call.Start() + regionListResult, err := regionZoneHandler.VMClient.V2Api.GetRegionList(®ionListReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get RegionList from NCP Cloud : ", err) + return nil, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(regionListResult.RegionList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find Any Region Info.", "") + return nil, rtnErr + } else { + cblogger.Infof("# Supported Region count : [%d]", len(regionListResult.RegionList)) + // spew.Dump(regionListResult) + } + + var regionZoneInfoList []*irs.RegionZoneInfo + var wait sync.WaitGroup + var zoneListErr error + var zoneExistErr error + for _, region := range regionListResult.RegionList { + wait.Add(1) + go func(region *server.Region) { + defer wait.Done() + cblogger.Info("# Search Criteria(NCP RegionCode) : ", *region.RegionCode) + + regionZoneInfo := irs.RegionZoneInfo{ + Name: *region.RegionCode, + DisplayName: *region.RegionName, + // KeyValueList: []irs.KeyValue{ + // {Key: "RegionNo", Value: *region.RegionNo}, + // {Key: "RegionCode", Value: *region.RegionCode}, + // }, + } + zoneListReq := server.GetZoneListRequest{ + RegionNo: region.RegionNo, + //RegionNo: nil, // Caution!! : If look up like this, only Korean two zones will come out. + } + callLogStart := call.Start() + zoneListResult, err := regionZoneHandler.VMClient.V2Api.GetZoneList(&zoneListReq) + if err != nil { + zoneListErr = err + return + } + LoggingInfo(callLogInfo, callLogStart) + + if len(zoneListResult.ZoneList) < 1 { + zoneExistErr = fmt.Errorf("Failed to Find Any Zone Info!!") + return + } else { + cblogger.Infof("# Supported Zone count : [%d]", len(zoneListResult.ZoneList)) + // spew.Dump(zoneListResult) + } + + var zoneInfoList []irs.ZoneInfo + for _, zone := range zoneListResult.ZoneList { + zoneInfo := irs.ZoneInfo{ + Name: *zone.ZoneName, + DisplayName: *zone.ZoneDescription, + Status: irs.NotSupported, + // KeyValueList: []irs.KeyValue{ + // {Key: "ZoneNo", Value: *zone.ZoneNo}, + // {Key: "ZoneCode", Value: *zone.ZoneCode}, + // }, + } + zoneInfoList = append(zoneInfoList, zoneInfo) + } + regionZoneInfo.ZoneList = zoneInfoList + regionZoneInfoList = append(regionZoneInfoList, ®ionZoneInfo) + }(region) + } + wait.Wait() + + if zoneListErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Zone List!!", zoneListErr) + return nil, rtnErr + } + if zoneExistErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Zone Info.", zoneExistErr) + return nil, rtnErr + } + + return regionZoneInfoList, nil +} + +func (regionZoneHandler NcpRegionZoneHandler) GetRegionZone(regionCode string) (irs.RegionZoneInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetRegionZone()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, regionCode, "GetRegionZone()") + + if len(regionCode) < 1 { + rtnErr := logAndReturnError(callLogInfo, "The RegionCode is Empty!!", "") + return irs.RegionZoneInfo{}, rtnErr + } + + regionListReq := server.GetRegionListRequest{} + callLogStart := call.Start() + regionListResult, err := regionZoneHandler.VMClient.V2Api.GetRegionList(®ionListReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get RegionList from NCP Cloud : ", err) + return irs.RegionZoneInfo{}, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(regionListResult.RegionList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find Any Region Info.", "") + return irs.RegionZoneInfo{}, rtnErr + } else { + cblogger.Infof("# Supported Region count : [%d]", len(regionListResult.RegionList)) + // spew.Dump(regionListResult) + } + + var regionZoneInfo irs.RegionZoneInfo + for _, region := range regionListResult.RegionList { + if strings.EqualFold(regionCode, *region.RegionCode){ + cblogger.Info("# Search Criteria(NCP RegionCode) : ", *region.RegionCode) + + regionZoneInfo = irs.RegionZoneInfo{ + Name: *region.RegionCode, + DisplayName: *region.RegionName, + // KeyValueList: []irs.KeyValue{ + // {Key: "RegionNo", Value: *region.RegionNo}, + // {Key: "RegionCode", Value: *region.RegionCode}, + // }, + } + zoneListReq := server.GetZoneListRequest{ + RegionNo: region.RegionNo, + //RegionNo: nil, //CAUTION!! : 이렇게 조회하면 zone이 한국 zone 두개만 나옴. + } + callLogStart := call.Start() + zoneListResult, err := regionZoneHandler.VMClient.V2Api.GetZoneList(&zoneListReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get ZoneList from NCP Cloud : ", err) + return irs.RegionZoneInfo{}, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(zoneListResult.ZoneList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find Any Zone Info.", "") + return irs.RegionZoneInfo{}, rtnErr + } else { + cblogger.Infof("# Supported Zone count : [%d]", len(zoneListResult.ZoneList)) + // spew.Dump(zoneListResult) + } + + var zoneInfoList []irs.ZoneInfo + for _, zone := range zoneListResult.ZoneList { + zoneInfo := irs.ZoneInfo{ + Name: *zone.ZoneName, + DisplayName: *zone.ZoneDescription, + Status: irs.NotSupported, + // KeyValueList: []irs.KeyValue{ + // {Key: "ZoneNo", Value: *zone.ZoneNo}, + // {Key: "ZoneCode", Value: *zone.ZoneCode}, + // }, + } + zoneInfoList = append(zoneInfoList, zoneInfo) + } + regionZoneInfo.ZoneList = zoneInfoList + } + } + return regionZoneInfo, nil +} + +func (regionZoneHandler *NcpRegionZoneHandler) ListOrgRegion() (string, error) { + cblogger.Info("NCP Classic Cloud Driver: called ListOrgRegion()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, "ListOrgRegion()", "ListOrgRegion()") + + regionListReq := server.GetRegionListRequest{} + callLogStart := call.Start() + regionListResult, err := regionZoneHandler.VMClient.V2Api.GetRegionList(®ionListReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get RegionList from NCP Cloud : ", err) + return "", rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(regionListResult.RegionList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find Any Region Info.", "") + return "", rtnErr + } else { + cblogger.Infof("# Supported Region count : [%d]", len(regionListResult.RegionList)) + // spew.Dump(regionListResult) + } + + jsonString, convertErr := ConvertJsonString(regionListResult) + if convertErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Convert the Region List to Json format string.", convertErr) + return "", rtnErr + } + return jsonString, convertErr +} + +func (regionZoneHandler *NcpRegionZoneHandler) ListOrgZone() (string, error) { + cblogger.Info("NCP Classic Cloud Driver: called ListOrgZone()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, regionZoneHandler.RegionInfo.Region, "ListOrgZone()") + + if len(regionZoneHandler.RegionInfo.Region) < 1 { + rtnErr := logAndReturnError(callLogInfo, "RegionInfo.Region is Empty!!", "") + return "", rtnErr + } + + vmHandler := NcpVMHandler{ + CredentialInfo: regionZoneHandler.CredentialInfo, + RegionInfo: regionZoneHandler.RegionInfo, + VMClient: regionZoneHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(regionZoneHandler.RegionInfo.Region) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Region No of the Region Code : ", err) + return "", rtnErr + } + zoneListReq := server.GetZoneListRequest{ + RegionNo: regionNo, + //RegionNo: nil, //CAUTION!! : 이렇게 조회하면 zone이 한국 zone 두개만 나옴. + } + callLogStart := call.Start() + zoneListResult, err := regionZoneHandler.VMClient.V2Api.GetZoneList(&zoneListReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get ZoneList from NCP Cloud : ", err) + return "", rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(zoneListResult.ZoneList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find Any Zone Info.", "") + return "", rtnErr + } else { + cblogger.Infof("# Supported Zone count : [%d]", len(zoneListResult.ZoneList)) + // spew.Dump(zoneListResult) + } + + jsonString, convertErr := ConvertJsonString(zoneListResult) + if convertErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Convert the Zone List to Json format string.", convertErr) + return "", rtnErr + } + return jsonString, convertErr +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/SecurityHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/SecurityHandler.go new file mode 100644 index 000000000..9bb79cb24 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/SecurityHandler.go @@ -0,0 +1,301 @@ +// Cloud Driver Interface of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP Security Group Handler +// +// by ETRI, 2020.10. +// by ETRI, 2022.02. updated + +package resources + +import ( + "fmt" + "errors" + "strings" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + + 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" +) + +type NcpSecurityHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Security Group Handler") +} + +func (securityHandler *NcpSecurityHandler) CreateSecurity(securityReqInfo irs.SecurityReqInfo) (irs.SecurityInfo, error) { + cblogger.Info("NCP Cloud Driver: called CreateSecurity()!") + + InitLog() + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Zone, call.SECURITYGROUP, securityReqInfo.IId.NameId, "CreateSecurity()") + + // CB-Spider에서 IID2 포멧(최대 30자)의 이름으로 변경되어 사용되므로 + // 사용자가 지정한 본래의 이름으로 사용하기 위해 맨뒤에서부터의 21자리 문자 제거 + // originalNameId := GetOriginalNameId(securityReqInfo.IId.NameId) + // cblogger.Infof("# VPC NameID requested by user : [%s]", originalNameId) + + if securityReqInfo.IId.NameId == "" { + newErr := fmt.Errorf("Invalid S/G Name Requested") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } + + reqNameId := securityReqInfo.IId.NameId + + var sgSystemId string + + // Get SecurityGroup list + securityList, err := securityHandler.ListSecurity() + if err != nil { + newErr := fmt.Errorf("Failed to Find SecurityGroup list : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } + + // Search S/G SystemId by NameID in the SecurityGroup list + for _, security := range securityList { + if strings.EqualFold(security.IId.NameId, reqNameId) { + sgSystemId = security.IId.SystemId + cblogger.Infof("# SystemId of the matched S/G : [%s]", sgSystemId) + break + } + } + + // When the SecurityGroup is not found + if strings.EqualFold(sgSystemId, "") { + err := fmt.Errorf("Failed to Find S/G SystemId with the NameID.") + return irs.SecurityInfo{}, err + } + + sgInfo, err := securityHandler.GetSecurity(irs.IID{SystemId: sgSystemId}) + if err != nil { + newErr := fmt.Errorf("Failed to Get SecurityGroup Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + } else { + sgInfo.IId.NameId = securityReqInfo.IId.NameId // Caution!! For IID2 NameID validation check + } + + return sgInfo, err +} + +func (securityHandler *NcpSecurityHandler) GetSecurity(securityIID irs.IID) (irs.SecurityInfo, error) { + cblogger.Info("NCP Cloud Driver: called GetSecurity()!!") + + cblogger.Infof("NCP securityIID.SystemId : [%s]", securityIID.SystemId) + + InitLog() + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Zone, call.SECURITYGROUP, securityIID.NameId, "GetSecurity()") + + if securityIID.SystemId == "" { + newErr := fmt.Errorf("Invalid S/G SystemId") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } + + // spew.Dump(securityIID.SystemId) + sgNumList := []*string{ncloud.String(securityIID.SystemId)} + + sgReq := server.GetAccessControlGroupListRequest{AccessControlGroupConfigurationNoList: sgNumList} + + // Search NCP AccessControlGroup with securityIID.SystemId + callLogStart := call.Start() + ncpSG, err := securityHandler.VMClient.V2Api.GetAccessControlGroupList(&sgReq) + if err != nil { + cblogger.Error(*ncpSG.ReturnMessage) + newErr := fmt.Errorf("Failed to Get SecurityGroup list from NCP : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(ncpSG.AccessControlGroupList) < 1 { + newErr := fmt.Errorf("Failed to Find Any SecurityGroup with the SystemId : [%s]", securityIID.SystemId) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } + + cblogger.Info("Succeeded in Getting NCP SecurityGroup info.") + // spew.Dump(ncpSG) + + securityGroupInfo, securityInfoErr := securityHandler.MappingSecurityInfo(*ncpSG.AccessControlGroupList[0]) + if securityInfoErr != nil { + cblogger.Error(securityInfoErr) + return irs.SecurityInfo{}, securityInfoErr + } + + return securityGroupInfo, nil +} + +func (securityHandler *NcpSecurityHandler) ListSecurity() ([]*irs.SecurityInfo, error) { + cblogger.Info("NCP Cloud Driver: called ListSecurity()!!") + + InitLog() + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Zone, call.SECURITYGROUP, "ListSecurity()", "ListSecurity()") + + var securityGroupList []*irs.SecurityInfo + + sgReq := server.GetAccessControlGroupListRequest{AccessControlGroupConfigurationNoList: nil} + + // Search NCP AccessControlGroup with securityIID.SystemId + callLogStart := call.Start() + ncpSG, err := securityHandler.VMClient.V2Api.GetAccessControlGroupList(&sgReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find SecurityGroup list from NCP : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(ncpSG.AccessControlGroupList) < 1 { + return nil, errors.New("Failed to Find Any SecurityGroup info!!") + } + + cblogger.Info("Succeeded in Getting NCP SecurityGroup info.") + + for _, sg := range ncpSG.AccessControlGroupList { + cblogger.Info("NCP SecurityGroup No : ", *sg.AccessControlGroupConfigurationNo) + + sgInfo, _ := securityHandler.GetSecurity(irs.IID{SystemId: *sg.AccessControlGroupConfigurationNo}) + securityGroupList = append(securityGroupList, &sgInfo) + } + + return securityGroupList, nil +} + +func (securityHandler *NcpSecurityHandler) DeleteSecurity(securityIID irs.IID) (bool, error) { + cblogger.Info("NCP Cloud Driver: called DeleteSecurity()!") + + cblogger.Infof("securityIID.SystemId to Delete : [%s]", securityIID.SystemId) + + InitLog() + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Zone, call.SECURITYGROUP, securityIID.NameId, "DeleteSecurity()") + + if securityIID.SystemId == "" { + newErr := fmt.Errorf("Invalid S/G SystemId") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + sgInfo, err := securityHandler.GetSecurity(securityIID) + if err != nil { + newErr := fmt.Errorf("Failed to Find the SecurityGroup info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + cblogger.Info("Succeeded in Deleting the SecurityGroup : " + sgInfo.IId.NameId) + return true, nil +} + +func (securityHandler *NcpSecurityHandler) MappingSecurityInfo(ncpSecurityGroup server.AccessControlGroup) (irs.SecurityInfo, error) { + cblogger.Info("NCP Cloud Driver: called MappingSecurityInfo()!") + + var ncpSgRuleList []irs.SecurityRuleInfo + + ncpSgRuleList, ruleInfoError := securityHandler.ExtractSecurityRuleInfo(ncloud.StringValue(ncpSecurityGroup.AccessControlGroupConfigurationNo)) + if ruleInfoError != nil { + cblogger.Error(ruleInfoError) + // return irs.SecurityInfo{}, ruleInfoError // Caution!! + } + + securityInfo := irs.SecurityInfo{ + IId: irs.IID{NameId: ncloud.StringValue(ncpSecurityGroup.AccessControlGroupName), SystemId: ncloud.StringValue(ncpSecurityGroup.AccessControlGroupConfigurationNo)}, + VpcIID: irs.IID{NameId: "", SystemId: ""}, + SecurityRules: &ncpSgRuleList, + + KeyValueList: []irs.KeyValue{ + {Key: "SecurityGroupDescription", Value: ncloud.StringValue(ncpSecurityGroup.AccessControlGroupDescription)}, + {Key: "CreateTime", Value: ncloud.StringValue(ncpSecurityGroup.CreateDate)}, + // {Key: "IsDefaultGroup", Value: strconv.FormatBool(*ncpSecurityGroup.IsDefaultGroup)}, + }, + } + + return securityInfo, nil +} + +// Search NCP SecurityGroup Rule List +func (securityHandler *NcpSecurityHandler) ExtractSecurityRuleInfo(ncpSecurityGroupId string) ([]irs.SecurityRuleInfo, error) { + cblogger.Info("NCP Cloud Driver: called ExtractSecurityRuleInfo()!") + + var securityRuleList []irs.SecurityRuleInfo + + sgRuleReq := server.GetAccessControlRuleListRequest{ + AccessControlGroupConfigurationNo: ncloud.String(ncpSecurityGroupId), + } + + // securityIID.SystemId와 NCP의 AccessControlGroupConfigurationNo 비교 + ncpRuleList, err := securityHandler.VMClient.V2Api.GetAccessControlRuleList(&sgRuleReq) + if err != nil { + cblogger.Error(*ncpRuleList.ReturnMessage) + newErr := fmt.Errorf("Failed to Get SecurityRule List from NCP : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + if len(ncpRuleList.AccessControlRuleList) < 1 { + newErr := fmt.Errorf("Failed to Find Any SecurityRule of S/G SystemId : [%s]", ncpSecurityGroupId) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + // spew.Dump(ncpRuleList) + + // Caution!!) FromPort string, ToPort string + var curSecurityRuleInfo irs.SecurityRuleInfo + + for _, curRule := range ncpRuleList.AccessControlRuleList { + curSecurityRuleInfo.IPProtocol = ncloud.StringValue(curRule.ProtocolType.CodeName) + + if curSecurityRuleInfo.IPProtocol == "icmp" { + curSecurityRuleInfo.FromPort = "-1" + curSecurityRuleInfo.ToPort = "-1" + } else if ncloud.StringValue(curRule.DestinationPort) == "1-65535" { + curSecurityRuleInfo.FromPort = "1" + curSecurityRuleInfo.ToPort = "65535" + } else { + curSecurityRuleInfo.FromPort = ncloud.StringValue(curRule.DestinationPort) + curSecurityRuleInfo.ToPort = ncloud.StringValue(curRule.DestinationPort) + } + + curSecurityRuleInfo.Direction = "inbound" //NCP Classic S/G : inbound rule만 지원 + curSecurityRuleInfo.CIDR = ncloud.StringValue(curRule.SourceIp) //CIDR + + securityRuleList = append(securityRuleList, curSecurityRuleInfo) + } + + return securityRuleList, nil +} + +func (securityHandler *NcpSecurityHandler) AddRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (irs.SecurityInfo, error) { + cblogger.Info("NCP Cloud Driver: called AddRules()!") + + return irs.SecurityInfo{}, fmt.Errorf("Does not support AddRules() yet!!") +} + +func (securityHandler *NcpSecurityHandler) RemoveRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (bool, error) { + cblogger.Info("NCP Cloud Driver: called RemoveRules()!") + + return false, fmt.Errorf("Does not support RemoveRules() yet!!") +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go new file mode 100644 index 000000000..d5fc2c01e --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMHandler.go @@ -0,0 +1,1715 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP Classic VM Handler +// +// Created by ETRI, 2020.09. +// Updated by ETRI, 2023.08. +//================================================================================================== + +package resources + +import ( + "errors" + "fmt" + "io" + "os" + "strconv" + "strings" + "time" + // "github.com/davecgh/go-spew/spew" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + server "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + + cblog "github.com/cloud-barista/cb-log" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" + keycommon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/common" + 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" +) + +type NcpVMHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +const ( + ubuntuCloudInitFilePath string = "/cloud-driver-libs/.cloud-init-ncp/cloud-init-ubuntu" + centosCloudInitFilePath string = "/cloud-driver-libs/.cloud-init-ncp/cloud-init-centos" + winCloudInitFilePath string = "/cloud-driver-libs/.cloud-init-ncp/cloud-init-windows" + + lnxUserName string = "cb-user" + winUserName string = "Administrator" + + LnxTypeOs string = "LINUX" + WinTypeOS string = "WINDOWS" +) + +// Already declared in CommonNcpFunc.go +// var cblogger *logrus.Logger +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Classic VMHandler") +} + +func (vmHandler *NcpVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called StartVM()!!") + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmReqInfo.IId.NameId, "StartVM()") + + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Zone 'No' of the Zone : ", err) + return irs.VMInfo{}, rtnErr + } + + // CAUTION!! : Instance Name is Converted to lowercase.(strings.ToLower()) + // NCP에서는 VM instance 이름에 영문 대문자 허용 안되므로 여기서 변환하여 반영.(대문자가 포함되면 Error 발생) + instanceName := strings.ToLower(vmReqInfo.IId.NameId) + instanceType := vmReqInfo.VMSpecName + keyPairId := vmReqInfo.KeyPairIID.SystemId + minCount := ncloud.Int32(1) + + // Check whether the VM name exists. Search by instanceName converted to lowercase + vmId, err := vmHandler.GetVmIdByName(instanceName) + if err != nil { + cblogger.Error("The VM with the name is not exists : " + instanceName) + // return irs.VMInfo{}, err //Caution!! + } + if vmId != "" { + cblogger.Info("The vmId : ", vmId) + createErr := fmt.Errorf("VM with the name '%s' already exist!!", vmReqInfo.IId.NameId) + LoggingError(callLogInfo, createErr) + return irs.VMInfo{}, createErr + } + + // Security Group IID 처리 - SystemId 기반 + cblogger.Info("Security Group IID 변환") + var newSecurityGroupIds []*string + for _, sgID := range vmReqInfo.SecurityGroupIIDs { + cblogger.Infof("Security Group IID : [%s]", sgID) + newSecurityGroupIds = append(newSecurityGroupIds, ncloud.String(sgID.SystemId)) + } + cblogger.Info(newSecurityGroupIds) + + // Set cloud-init script + var publicImageId string + var myImageId string + var initUserData *string + + if vmReqInfo.ImageType == irs.PublicImage || vmReqInfo.ImageType == "" || vmReqInfo.ImageType == "default" { + myImageHandler := NcpMyImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + isPublicImage, err := myImageHandler.isPublicImage(vmReqInfo.ImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if !isPublicImage { + newErr := fmt.Errorf("'PublicImage' type is selected, but Specified image is Not a PublicImage in the region!!") + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } else { + publicImageId = vmReqInfo.ImageIID.SystemId + } + + isPublicWindowsImage, err := myImageHandler.CheckWindowsImage(vmReqInfo.ImageIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Check Whether the Image is MS Windows Image : ", err) + return irs.VMInfo{}, rtnErr + } + if isPublicWindowsImage { + var createErr error + initUserData, createErr = vmHandler.CreateWinInitUserData(vmReqInfo.VMUserPasswd) + if createErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create Cloud-Init Script with the Password : ", createErr) + return irs.VMInfo{}, rtnErr + } + } else { + var createErr error + initUserData, createErr = vmHandler.CreateLinuxInitUserData(vmReqInfo.ImageIID, keyPairId) + if createErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create Cloud-Init Script with the KeyPairId : ", createErr) + return irs.VMInfo{}, rtnErr + } + } + } else { + myImageHandler := NcpMyImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + isPublicImage, err := myImageHandler.isPublicImage(vmReqInfo.ImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if isPublicImage { + newErr := fmt.Errorf("'MyImage' type is selected, but Specified image is Not a MyImage!!") + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } else { + myImageId = vmReqInfo.ImageIID.SystemId + } + + isMyWindowsImage, err := myImageHandler.CheckWindowsImage(vmReqInfo.ImageIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Check Whether My Image is MS Windows Image : ", err) + return irs.VMInfo{}, rtnErr + } + if isMyWindowsImage { + var createErr error + initUserData, createErr = vmHandler.CreateWinInitUserData(vmReqInfo.VMUserPasswd) + if createErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create Cloud-Init Script with the Password : ", createErr) + return irs.VMInfo{}, rtnErr + } + } else { + var createErr error + initUserData, createErr = vmHandler.CreateLinuxInitUserData(vmReqInfo.ImageIID, keyPairId) + if createErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create Cloud-Init Script with the KeyPairId : ", createErr) + return irs.VMInfo{}, rtnErr + } + } + } + cblogger.Info("### Succeeded in Creating Init UserData!!") + // cblogger.Infof("Init UserData : [%s]", *initUserData) + // Note) NCP에서는 UserData용 string에 Base64 인코딩 불필요 + // cmdStringBase64 := base64.StdEncoding.EncodeToString([]byte(cmdString)) + + cblogger.Info("### Start to Create NCP VM Instance!!") + // VM Creation req. info. setting + // Note) Since NCP Classic is based on a physical network, it does not support VPC and Subnet specifications when creating VM. + instanceReq := server.CreateServerInstancesRequest{ + ServerName: ncloud.String(instanceName), + ServerImageProductCode: ncloud.String(publicImageId), + MemberServerImageNo: ncloud.String(myImageId), + ServerProductCode: ncloud.String(instanceType), + ServerDescription: ncloud.String(vmReqInfo.ImageIID.SystemId), // Caution!! + LoginKeyName: ncloud.String(keyPairId), + ZoneNo: zoneNo, + IsProtectServerTermination: ncloud.Bool(false), // NOTE Caution!! : 'true'로 설정하면 API로 Terminate(VM 반환) 제어 안됨. + ServerCreateCount: minCount, + AccessControlGroupConfigurationNoList: newSecurityGroupIds, + UserData: initUserData, + } + // cblogger.Info(instanceReq) + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.CreateServerInstances(&instanceReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create NCP VM instance. : ", err) + return irs.VMInfo{}, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + // Because there are functions that use NameID + newVMIID := irs.IID{NameId: instanceName, SystemId: ncloud.StringValue(runResult.ServerInstanceList[0].ServerInstanceNo)} + // Wait while being created to get VM information. + curStatus, statusErr := vmHandler.WaitToGetInfo(newVMIID) + if statusErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Wait to Get the VM info. : ", statusErr) + return irs.VMInfo{}, rtnErr + } + cblogger.Infof("==> VM status of [%s] : [%s]", newVMIID.NameId, curStatus) + + var vpcNameId string + var subnetNameId string + if !strings.EqualFold(vmReqInfo.VpcIID.NameId, "") { + vpcNameId = vmReqInfo.VpcIID.NameId + } else { + vpcNameId = vmReqInfo.VpcIID.SystemId + } + if !strings.EqualFold(vmReqInfo.SubnetIID.NameId, "") { + subnetNameId = vmReqInfo.SubnetIID.NameId + } else { + subnetNameId = vmReqInfo.SubnetIID.SystemId + } + // Save VPC name to tag on the VM instance + createTagResult, error := vmHandler.CreateVPCnSubnetTag(ncloud.String(newVMIID.SystemId), vpcNameId, subnetNameId) + if error != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create VPC and Subnet Tag : ", error) + return irs.VMInfo{}, rtnErr + } + cblogger.Info("# createTagResult : ", createTagResult) + + vmInfo, error := vmHandler.GetVM(newVMIID) + if error != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Info : ", error) + return irs.VMInfo{}, rtnErr + } + cblogger.Info("### VM Creation Processes have been Finished !!") + + if vmInfo.Platform == irs.WINDOWS { + vmInfo.VMUserPasswd = vmReqInfo.VMUserPasswd + } + return vmInfo, nil +} + +func (vmHandler *NcpVMHandler) MappingServerInfo(NcpInstance server.ServerInstance) (irs.VMInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called MappingServerInfo()!") + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, "MappingServerInfo()", "MappingServerInfo()") + + var publicIp *string = nil + var publicIpInstanceNo *string = nil + + convertedTime, err := convertTimeFormat(*NcpInstance.CreateDate) + if err != nil { + newErr := fmt.Errorf("Failed to Convert the Time Format!! : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + + // Create a PublicIp, if the instance doesn't have a 'Public IP' after creation. + if ncloud.StringValue(NcpInstance.PublicIp) == "" { + publicIpReq := server.CreatePublicIpInstanceRequest{ + ServerInstanceNo: NcpInstance.ServerInstanceNo, + ZoneNo: NcpInstance.Zone.ZoneNo, // NOTE check again!! + } + cblogger.Infof("publicIpReq Ready") + + // CAUTION!!) The number of Public IPs cannot be more than the number of instances on NCP cloud default service. + result, err := vmHandler.VMClient.V2Api.CreatePublicIpInstance(&publicIpReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Create PublicIp : ", err) + return irs.VMInfo{}, rtnErr + } + if len(result.PublicIpInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Create any PublicIp.") + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + publicIp = result.PublicIpInstanceList[0].PublicIp + publicIpInstanceNo = result.PublicIpInstanceList[0].PublicIpInstanceNo + // cblogger.Infof("*** NcpInstance.PublicIp : [%s]", ncloud.StringValue(publicIp)) + // cblogger.Infof("*** NcpInstance.publicIpInstanceNo [%s]: ", ncloud.StringValue(publicIpInstanceNo)) + + cblogger.Infof("Finished to Create New Public IP.") + } else { + publicIp = NcpInstance.PublicIp + cblogger.Infof("*** NcpInstance.PublicIp : [%s]", ncloud.StringValue(publicIp)) + + instanceReq := server.GetPublicIpInstanceListRequest{ + PublicIpList: []*string{publicIp}, + } + + // Search the Public IP list info. to get the PublicIp InstanceNo + result, err := vmHandler.VMClient.V2Api.GetPublicIpInstanceList(&instanceReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Get PublicIp InstanceList : ", err) + return irs.VMInfo{}, rtnErr + } + if len(result.PublicIpInstanceList) < 1 { + cblogger.Errorf("Failed to Get Any PublicIp : [%v]", err) + return irs.VMInfo{}, errors.New("Failed to Get Any PublicIp.") + } + publicIpInstanceNo = result.PublicIpInstanceList[0].PublicIpInstanceNo + cblogger.Infof("*** NcpInstance.publicIpInstanceNo : [%s]", ncloud.StringValue(publicIpInstanceNo)) + + cblogger.Infof("Finished to Get PublicIP InstanceNo") + } + + // To Get the BlockStorage info. of the VM instance + blockStorageReq := server.GetBlockStorageInstanceListRequest{ + ServerInstanceNo: NcpInstance.ServerInstanceNo, + } + blockStorageResult, err := vmHandler.VMClient.V2Api.GetBlockStorageInstanceList(&blockStorageReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Block Storage InstanceList : ", err) + return irs.VMInfo{}, rtnErr + } + if len(blockStorageResult.BlockStorageInstanceList) < 1 { + cblogger.Errorf("Failed to Find Any BlockStorageInstance!!") + return irs.VMInfo{}, errors.New("Failed to Find Any BlockStorageInstance.") + } + cblogger.Infof("Succeeded in Getting Block Storage InstanceList!!") + //spew.Dump(blockStorageResult.BlockStorageInstanceList[0]) + + // To Get the VM resources Info. + // PublicIpID : To use it when delete the PublicIP + vmInfo := irs.VMInfo{ + IId: irs.IID{ + NameId: *NcpInstance.ServerName, + SystemId: *NcpInstance.ServerInstanceNo, + }, + StartTime: convertedTime, + + // (Ref) NCP region/zone info. example + // Region: "KR", Zone: "KR-2" + Region: irs.RegionInfo{ + Region: *NcpInstance.Region.RegionCode, + // *NcpInstance.Zone.ZoneCode, // Zone info is bellow. + }, + VMSpecName: ncloud.StringValue(NcpInstance.ServerProductCode), //Server Spec code임. + SecurityGroupIIds: []irs.IID{ + { + NameId: *NcpInstance.AccessControlGroupList[0].AccessControlGroupName, + SystemId: *NcpInstance.AccessControlGroupList[0].AccessControlGroupConfigurationNo, + }, + }, + + //NCP Key에는 SystemID가 없으므로, 고유한 NameID 값을 SystemID에도 반영 + KeyPairIId: irs.IID{ + NameId: *NcpInstance.LoginKeyName, + SystemId: *NcpInstance.LoginKeyName, + }, + + PublicIP: *publicIp, + PrivateIP: *NcpInstance.PrivateIp, + VMBootDisk: ncloud.StringValue(blockStorageResult.BlockStorageInstanceList[0].DeviceName), + VMBlockDisk: ncloud.StringValue(blockStorageResult.BlockStorageInstanceList[0].DeviceName), + RootDiskType: *NcpInstance.BaseBlockStorageDiskDetailType.CodeName, + SSHAccessPoint: *publicIp + ":22", + + KeyValueList: []irs.KeyValue{ + {Key: "ServerInstanceType", Value: *NcpInstance.ServerInstanceType.CodeName}, + {Key: "CpuCount", Value: String(*NcpInstance.CpuCount)}, + {Key: "MemorySize(GB)", Value: strconv.FormatFloat(float64(*NcpInstance.MemorySize)/(1024*1024*1024), 'f', 0, 64)}, + {Key: "BaseBlockStorageSize(GB)", Value: strconv.FormatFloat(float64(*NcpInstance.BaseBlockStorageSize)/(1024*1024*1024), 'f', 0, 64)}, //GB로 변환 + {Key: "DiskType", Value: ncloud.StringValue(blockStorageResult.BlockStorageInstanceList[0].DiskType.CodeName)}, + {Key: "DiskDetailType", Value: ncloud.StringValue(blockStorageResult.BlockStorageInstanceList[0].DiskDetailType.CodeName)}, + {Key: "PlatformType", Value: *NcpInstance.PlatformType.CodeName}, + {Key: "ZoneCode", Value: *NcpInstance.Zone.ZoneCode}, + //{Key: "ZoneNo", Value: *NcpInstance.Zone.ZoneNo}, + {Key: "PublicIpID", Value: *publicIpInstanceNo}, + // {Key: "ServerDescription", Value: *NcpInstance.ServerDescription}, => Blank + }, + } + + myImageHandler := NcpMyImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + // Set the VM Image Type : 'PublicImage' or 'MyImage' + if !strings.EqualFold(*NcpInstance.ServerDescription, "") { + 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' + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if isPublicImage { + vmInfo.ImageType = irs.PublicImage + } else { + vmInfo.ImageType = irs.MyImage + } + } else { + vmInfo.ImageIId.SystemId = *NcpInstance.ServerImageProductCode + vmInfo.ImageIId.NameId = *NcpInstance.ServerImageProductCode + } + + storageSize, deviceName, err := vmHandler.GetVmRootDiskInfo(NcpInstance.ServerInstanceNo) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find BlockStorage Info : ", err) + return irs.VMInfo{}, rtnErr + } + if !strings.EqualFold(*storageSize, "") { + vmInfo.RootDiskSize = *storageSize + } + if !strings.EqualFold(*deviceName, "") { + vmInfo.RootDeviceName = *deviceName + } + + dataDiskList, err := vmHandler.GetVmDataDiskList(NcpInstance.ServerInstanceNo) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Data Disk List : ", err) + return irs.VMInfo{}, rtnErr + } + if len(dataDiskList) > 0 { + vmInfo.DataDiskIIDs = dataDiskList + } + + // Set VM Zone Info + if NcpInstance.Zone != nil { + vmInfo.Region.Zone = *NcpInstance.Zone.ZoneCode + // *NcpInstance.Zone.ZoneCode or *NcpInstance.Zone.ZoneName etc... + } + + // To Get the VPC Name from Tag of the VM instance + vpcName, subnetName, error := vmHandler.GetVPCnSubnetNameFromTag(NcpInstance.ServerInstanceNo) + if error != nil { + cblogger.Error(error.Error()) + cblogger.Errorf("Failed to Get VPC Name from Tag of the VM instance!!") + // return irs.VMInfo{}, error // Caution!! + } else { + cblogger.Infof("# vpcName : [%s]", vpcName) + cblogger.Infof("# subnetName : [%s]", subnetName) + } + + if len(vpcName) < 1 { + cblogger.Errorf("Failed to Get VPC Name from Tag!!") + } else { + // To get the VPC info. + vpcHandler := NcpVPCHandler { + CredentialInfo: vmHandler.CredentialInfo, + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + vpcInfo, err := vpcHandler.GetVPC(irs.IID{SystemId: vpcName}) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find the VPC : ", err) + return irs.VMInfo{}, rtnErr + } + + vmInfo.VpcIID.NameId = vpcName + vmInfo.VpcIID.SystemId = vpcInfo.IId.SystemId + vmInfo.SubnetIID.NameId = subnetName + for _, curSubnet := range vpcInfo.SubnetInfoList { + cblogger.Infof("Subnet NameId : [%s]", curSubnet.IId.NameId) + if strings.EqualFold(curSubnet.IId.NameId, subnetName) { + vmInfo.SubnetIID.SystemId = curSubnet.IId.SystemId + break + } + } + } + cblogger.Infof("NCP Instance Uptime : [%s]", *NcpInstance.Uptime) + + // Note : NCP VPC PlatformType : LNX32, LNX64, WND32, WND64, UBD64, UBS64 + if strings.Contains(*NcpInstance.PlatformType.Code, "LNX") || strings.Contains(*NcpInstance.PlatformType.Code, "UB") { + vmInfo.VMUserId = lnxUserName + vmInfo.Platform = irs.LINUX_UNIX + } else if strings.Contains(*NcpInstance.PlatformType.Code, "WND") { + vmInfo.VMUserId = winUserName + vmInfo.Platform = irs.WINDOWS + } + return vmInfo, nil +} + +func (vmHandler *NcpVMHandler) GetVM(vmIID irs.IID) (irs.VMInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called GetVM()!!") + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "GetVM()") + + instanceNumList := []*string{ncloud.String(vmIID.SystemId)} + // spew.Dump(instanceNumList) + + curStatus, errStatus := vmHandler.GetVMStatus(vmIID) + if errStatus != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Status : ", errStatus) + return irs.VMInfo{}, rtnErr + } + cblogger.Info("===> VM Status : ", curStatus) + + // Since it's impossible to get VM info. during Creation, ... + switch string(curStatus) { + case "Creating", "Booting": + cblogger.Infof("Wait for the VM creation before inquiring VM info. The VM status : [%s]", string(curStatus)) + return irs.VMInfo{}, errors.New("The VM status is 'Creating' or 'Booting', wait for the VM creation before inquiring VM info. : " + vmIID.SystemId) + default: + cblogger.Infof("===> The VM status not 'Creating' or 'Booting', you can get the VM info.") + } + + regionNo, err := vmHandler.GetRegionNo(vmHandler.RegionInfo.Region) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Region No :", err) + return irs.VMInfo{}, rtnErr + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Zone No of the Zone Code :", err) + return irs.VMInfo{}, rtnErr + } + instanceReq := server.GetServerInstanceListRequest{ + ServerInstanceNoList: instanceNumList, + RegionNo: regionNo, + ZoneNo: zoneNo, + } + callLogStart := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get VM list from NCP :", err) + return irs.VMInfo{}, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.ServerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Find Any VM info with the SystemId : [%s]", vmIID.SystemId) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + + vmInfo, err := vmHandler.MappingServerInfo(*result.ServerInstanceList[0]) + if err != nil { + LoggingError(callLogInfo, err) + return irs.VMInfo{}, err + } + return vmInfo, nil +} + +func (vmHandler *NcpVMHandler) SuspendVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCP Classic Cloud driver: called SuspendVM()!!") + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "SuspendVM()") + + var serverInstanceNo []*string + serverInstanceNo = []*string{ncloud.String(vmIID.SystemId)} + var resultStatus string + + cblogger.Info("Start Get VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Status : ", err) + return irs.VMStatus("Failed. "), rtnErr + } else { + cblogger.Infof("Succeeded in Getting the VM Status of [%s] : [%s]", vmIID.SystemId, vmStatus) + } + + if strings.EqualFold(string(vmStatus), "Suspending") { + resultStatus = "The VM is already in the process of Suspending." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + } else if strings.EqualFold(string(vmStatus), "Suspended") { + resultStatus = "The VM is already Suspended." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Rebooting") { + resultStatus = "The VM is in the process of Rebooting." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Terminating") { + resultStatus = "The VM is in the process of Terminating." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Booting") { + resultStatus = "The VM is in the process of Booting." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else { + cblogger.Infof("vmID : [%s]", *serverInstanceNo[0]) + + stopReq := server.StopServerInstancesRequest{ + ServerInstanceNoList: serverInstanceNo, + } + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.StopServerInstances(&stopReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Stop the VM instance : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + } + return irs.VMStatus("Suspending"), nil +} + +func (vmHandler *NcpVMHandler) ResumeVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCP Classic Cloud driver: called ResumeVM()!") + cblogger.Infof("vmID : " + vmIID.SystemId) + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "ResumeVM()") + + serverInstanceNo := []*string{ncloud.String(vmIID.SystemId)} + var resultStatus string + + cblogger.Info("Start Get VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Status : ", err) + return irs.VMStatus("Failed. "), rtnErr + } else { + cblogger.Infof("Succeeded in Getting the VM Status of [%s] : [%s]", vmIID.SystemId, vmStatus) + } + + if strings.EqualFold(string(vmStatus), "Running") { + resultStatus = "The VM is Running. Cannot be Resumed!!" + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Suspending") { + resultStatus = "The VM is in the process of Suspending. Cannot be Resumed" + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Rebooting") { + resultStatus = "The VM is in the process of Rebooting. Cannot be Resumed" + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Terminating") { + resultStatus = "The VM is already in the process of Terminating. Cannot be Resumed" + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Booting") { + resultStatus = "The VM is in the process of Booting. Cannot be Resumed" + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Creating") { + resultStatus = "The VM is in the process of Creating. Cannot be Resumed" + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else { + cblogger.Infof("vmID : [%s]", *serverInstanceNo[0]) + + startReq := server.StartServerInstancesRequest{ + ServerInstanceNoList: serverInstanceNo, + } + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.StartServerInstances(&startReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Start the VM instance : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + + return irs.VMStatus("Resuming"), nil + } +} + +func (vmHandler *NcpVMHandler) RebootVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCP Classic Cloud driver: called RebootVM()!") + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "RebootVM()") + + var resultStatus string + serverInstanceNo := []*string{ncloud.String(vmIID.SystemId)} + + cblogger.Info("Start Get VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Status : ", err) + return irs.VMStatus("Failed. "), rtnErr + } else { + cblogger.Infof("Succeeded in Getting the VM Status of [%s] : [%s]", vmIID, vmStatus) + } + + if strings.EqualFold(string(vmStatus), "Suspending") { + resultStatus = "The VM is in the process of Suspending." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Suspended") { + resultStatus = "The VM is Suspended." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Rebooting") { + resultStatus = "The VM is already in the process of Rebooting." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Terminating") { + resultStatus = "The VM is in the process of Terminating." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Booting") { + resultStatus = "The VM is in the process of Booting." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else if strings.EqualFold(string(vmStatus), "Creating") { + resultStatus = "The VM is in the process of Creating." + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + + } else { + // spew.Dump(serverInstanceNo) + cblogger.Infof("vmID : [%s]", *serverInstanceNo[0]) + + req := server.RebootServerInstancesRequest{ + ServerInstanceNoList: serverInstanceNo, + } + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.RebootServerInstances(&req) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Reboot the VM instance : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + + return irs.VMStatus("Rebooting"), nil + } +} + +func (vmHandler *NcpVMHandler) TerminateVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCP Classic Cloud driver: called TerminateVM()!") + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "TerminateVM()") + + dataDiskList, err := vmHandler.GetVmDataDiskList(ncloud.String(vmIID.SystemId)) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Data Disk List : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + if len(dataDiskList) > 0 { + newErr := fmt.Errorf("Please Detach the Storage Attached to the VM and Try again.") + cblogger.Error(newErr.Error()) + return irs.VMStatus("Failed to Terminate the VM instance."), newErr + } + + serverInstanceNo := []*string{ncloud.String(vmIID.SystemId)} + + cblogger.Info("Start Get VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Status : ", err) + return irs.VMStatus("Failed. "), rtnErr + } else { + cblogger.Infof("Succeeded in Getting the VM Status of [%s] : [%s]", vmIID.SystemId, vmStatus) + } + + vmInfo, error := vmHandler.GetVM(vmIID) + if error != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Info : ", error) + return irs.VMStatus("Failed. "), rtnErr + } + + switch string(vmStatus) { + case "Suspended": + cblogger.Infof("VM Status : 'Suspended'. so it Can be Terminated!!") + cblogger.Infof("vmID : [%s]", *serverInstanceNo[0]) + + // To Delete Tags of the VM instance + Result, error := vmHandler.DeleteVMTags(serverInstanceNo[0]) + if error != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Delete Tags of the VM instance! : ", error) + return irs.VMStatus("Failed. "), rtnErr + } else { + cblogger.Infof("# DeleteVMTags Result : [%t]", Result) + } + + // To Terminate the VM instance + req := server.TerminateServerInstancesRequest{ + ServerInstanceNoList: serverInstanceNo, + } + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.TerminateServerInstances(&req) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Terminate the VM instance. : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + + // If the NCP instance has a 'Public IP', delete it after termination of the instance. + if ncloud.String(vmInfo.PublicIP) != nil { + // Delete the PublicIP of the VM + vmStatus, err := vmHandler.DeletePublicIP(vmInfo) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Delete the PublicIP. : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + cblogger.Info(vmStatus) + } + + return irs.VMStatus("Terminating"), nil + + case "Running": + cblogger.Infof("VM Status : 'Running'. so it Can be Terminated AFTER SUSPENSION !!") + + // spew.Dump(serverInstanceNo) + cblogger.Infof("vmID : [%s]", *serverInstanceNo[0]) + + cblogger.Info("Start Suspend VM !!") + result, err := vmHandler.SuspendVM(vmIID) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Suspend the VM. : ", err) + return irs.VMStatus("Failed. "), rtnErr + } else { + cblogger.Infof("Succeeded in Suspending the VM [%s] : [%s]", vmIID, result) + } + + //=================================== + // 15-second wait for Suspending + //=================================== + curRetryCnt := 0 + maxRetryCnt := 15 + for { + curStatus, errStatus := vmHandler.GetVMStatus(vmIID) + if errStatus != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Status : ", errStatus) + return irs.VMStatus("Failed. "), rtnErr + } + + cblogger.Info("===> VM Status : ", curStatus) + if curStatus != irs.VMStatus("Suspended") { + curRetryCnt++ + cblogger.Infof("The VM is not 'Suspended', so wait for a second more before inquiring Termination.") + time.Sleep(time.Second * 3) + if curRetryCnt > maxRetryCnt { + cblogger.Errorf("Despite waiting for a long time(%d sec), the VM is not 'suspended', so it is forcibly terminated.", maxRetryCnt) + } + } else { + break + } + } + + cblogger.Info("# SuspendVM() Finished") + + // To Delete Tags of the VM instance + Result, error := vmHandler.DeleteVMTags(serverInstanceNo[0]) + if error != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Delete Tags of the VM instance!! : ", error) + return irs.VMStatus("Failed. "), rtnErr + } else { + cblogger.Infof("# DeleteVMTags Result : [%t]", Result) + } + + // To Terminate the VM instance + req := server.TerminateServerInstancesRequest{ + ServerInstanceNoList: serverInstanceNo, + } + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.TerminateServerInstances(&req) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Terminate the NCP VM instance. : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + + // If the NCP instance has a 'Public IP', delete it after termination of the instance. + if ncloud.String(vmInfo.PublicIP) != nil { + // PublicIP 삭제 + vmStatus, err := vmHandler.DeletePublicIP(vmInfo) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Delete the PublicIP : ", err) + return irs.VMStatus("Failed. "), rtnErr + } + cblogger.Info(vmStatus) + } + + return irs.VMStatus("Terminateding"), nil + + default: + resultStatus := "The VM status is not 'Running' or 'Suspended'. so it Can NOT be Terminated!! Run or Suspend the VM before terminating." + + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + } +} + +/* +# NCP 'serverInstanceStatusName' : Not 'serverInstanceStatus' + : https://api.ncloud-docs.com/docs/en/common-apidatatype-serverinstance + +init +creating +booting //Caution!! : During Creating or Resuming +setting up + +running +rebooting +hard rebooting +shutting down //Caution!! : During Suspending +hard shutting down +terminating + +changingSpec +copying +repairing +*/ + +func ConvertVMStatusString(vmStatus string) (irs.VMStatus, error) { + var resultStatus string + + // cblogger.Infof("NCP VM Status : [%s]", vmStatus) + if strings.EqualFold(vmStatus, "creating") { + resultStatus = "Creating" + } else if strings.EqualFold(vmStatus, "init") { + resultStatus = "Creating" + } else if strings.EqualFold(vmStatus, "booting") { + //Caution!! + resultStatus = "Booting" + } else if strings.EqualFold(vmStatus, "setting up") { + resultStatus = "Creating" + } else if strings.EqualFold(vmStatus, "running") { + resultStatus = "Running" + } else if strings.EqualFold(vmStatus, "shutting down") { + //Caution!! + resultStatus = "Suspending" + } else if strings.EqualFold(vmStatus, "running") { + resultStatus = "Running" + } else if strings.EqualFold(vmStatus, "stopped") { + resultStatus = "Suspended" + } else if strings.EqualFold(vmStatus, "rebooting") { + resultStatus = "Rebooting" + } else if strings.EqualFold(vmStatus, "hard rebooting") { + resultStatus = "Rebooting" + } else if strings.EqualFold(vmStatus, "hard shutting down") { + resultStatus = "Terminating" + } else if strings.EqualFold(vmStatus, "terminating") { + resultStatus = "Terminating" + } else { + cblogger.Errorf("No mapping information found matching with the vmStatus [%s].", string(vmStatus)) + return irs.VMStatus("Failed. "), errors.New(vmStatus + "No mapping information found matching with the vmStatus.") + } + cblogger.Infof("Succeeded in Converting the VM Status : [%s] ==> [%s]", vmStatus, resultStatus) + return irs.VMStatus(resultStatus), nil +} + +func (vmHandler *NcpVMHandler) GetVMStatus(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCP Classic Cloud driver: called GetVMStatus()!") + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "GetVMStatus()") + + regionNo, err := vmHandler.GetRegionNo(vmHandler.RegionInfo.Region) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Region No :", err) + return irs.VMStatus(""), rtnErr + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Zone No of the Zone Code :", err) + return irs.VMStatus(""), rtnErr + } + instanceReq := server.GetServerInstanceListRequest{ + ServerInstanceNoList: []*string{ + ncloud.String(vmIID.SystemId), + }, + RegionNo: regionNo, + ZoneNo: zoneNo, + } + callLogStart := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*result.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.VMStatus(""), err // Caution!!) Do not fill in "Failed." + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.ServerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Find Any VM info with the SystemId : [%s]", vmIID.SystemId) + cblogger.Error(newErr.Error()) + return irs.VMStatus(""), newErr // Caution!!) Do not fill in "Failed." + } + cblogger.Info("Succeeded in Getting ServerInstanceList!!") + + for _, vm := range result.ServerInstanceList { + //*vm.ServerInstanceStatusName + vmStatus, errStatus := ConvertVMStatusString(*vm.ServerInstanceStatusName) + cblogger.Info("# Converted VM Status : " + vmStatus) + return vmStatus, errStatus + } + + return irs.VMStatus(""), errors.New("Can not get VM Status info!!") // Caution!!) Do not fill in "Failed." +} + +func (vmHandler *NcpVMHandler) ListVMStatus() ([]*irs.VMStatusInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called ListVMStatus()!") + + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, "ListVMStatus()", "ListVMStatus()") + + regionNo, err := vmHandler.GetRegionNo(vmHandler.RegionInfo.Region) + if err != nil { + cblogger.Errorf("Failed to Get RegionNo : [%v]", err) + return nil, err + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + cblogger.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + return nil, err + } + instanceReq := server.GetServerInstanceListRequest{ + ServerInstanceNoList: []*string{}, + RegionNo: regionNo, + ZoneNo: zoneNo, + } + callLogStart := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get GetServerInstanceList : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return []*irs.VMStatusInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + if len(result.ServerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Find Any VM info in the Zone : [%s]", vmHandler.RegionInfo.Zone) + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting ServerInstanceList in the Zone!!") + } + + var vmStatusList []*irs.VMStatusInfo + for _, vm := range result.ServerInstanceList { + //*vm.ServerInstanceStatusName + //*vm.ServerName + vmStatus, err := ConvertVMStatusString(*vm.ServerInstanceStatusName) + if err != nil { + cblogger.Error(err) + LoggingError(callLogInfo, err) + return []*irs.VMStatusInfo{}, err + } + cblogger.Info(" VM Status : ", vmStatus) + + vmStatusInfo := irs.VMStatusInfo{ + IId: irs.IID{NameId: *vm.ServerName, SystemId: *vm.ServerInstanceNo}, + VmStatus: vmStatus, + } + cblogger.Infof(" VM Status of [%s] : [%s]", vmStatusInfo.IId.SystemId, vmStatusInfo.VmStatus) + vmStatusList = append(vmStatusList, &vmStatusInfo) + } + return vmStatusList, err +} + +func (vmHandler *NcpVMHandler) ListVM() ([]*irs.VMInfo, error) { + cblogger.Info("NCP Classic Cloud driver: called ListVM()!") + InitLog() + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, "ListVM()", "ListVM()") + + regionNo, err := vmHandler.GetRegionNo(vmHandler.RegionInfo.Region) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Region No :", err) + return nil, rtnErr + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get NCP Zone No of the Zone Code :", err) + return nil, rtnErr + } + + instanceReq := server.GetServerInstanceListRequest{ + ServerInstanceNoList: []*string{}, + RegionNo: regionNo, + ZoneNo: zoneNo, + } + callLogStart := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get GetServerInstanceList : [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.ServerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Find Any VM info in the Zone: [%s]", vmHandler.RegionInfo.Zone) + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting ServerInstanceList!!") + } + + var vmInfoList []*irs.VMInfo + for _, vm := range result.ServerInstanceList { + cblogger.Info("NCP VM Instance Info. inquiry : ", *vm.ServerInstanceNo) + + curStatus, errStatus := vmHandler.GetVMStatus(irs.IID{SystemId: *vm.ServerInstanceNo}) + if errStatus != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get the VM Status : ", errStatus) + return nil, rtnErr + } else { + cblogger.Infof("Succeeded to Get the VM Status of [%s] : [%s]", irs.IID{SystemId: *vm.ServerInstanceNo}, curStatus) + } + cblogger.Info("===> VM Status : ", curStatus) + + switch string(curStatus) { + case "Creating", "Booting": + cblogger.Errorf("The VM status : [%s], Can Not Get the VM info.", string(curStatus)) + return nil, nil + + default: + cblogger.Infof("===> The VM status not 'Creating' or 'Booting', you can get the VM info.") + vmInfo, error := vmHandler.GetVM(irs.IID{SystemId: *vm.ServerInstanceNo}) + if error != nil { + cblogger.Error(error.Error()) + return nil, error + } + vmInfoList = append(vmInfoList, &vmInfo) + } + } + return vmInfoList, nil +} + +// Waiting for up to 300 seconds until VM info. can be get +func (vmHandler *NcpVMHandler) WaitToGetInfo(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("======> As VM info. cannot be retrieved immediately after VM creation, it waits until running.") + + curRetryCnt := 0 + maxRetryCnt := 500 + + for { + curStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Status of the VM : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMStatus("Failed. "), newErr + } else { + cblogger.Infof("Succeeded in Getting the VM Status of [%s] : [%s]", vmIID.SystemId, curStatus) + } + cblogger.Infof("===> VM Status : [%s]", curStatus) + + switch string(curStatus) { + case "Creating", "Booting": + curRetryCnt++ + cblogger.Infof("The VM is still 'Creating', so wait for a second more before inquiring the VM info.") + time.Sleep(time.Second * 3) + if curRetryCnt > maxRetryCnt { + cblogger.Errorf("Despite waiting for a long time(%d sec), the VM status is %s, so it is forcibly finishied.", maxRetryCnt, curStatus) + return irs.VMStatus("Failed. "), errors.New("Despite waiting for a long time, the VM status is 'Creating', so it is forcibly finishied.") + } + + default: + cblogger.Infof("===> ### The VM Creation is finished, stopping the waiting.") + return irs.VMStatus(curStatus), nil + //break + } + } +} + +// Waiting for up to 300 seconds until Public IP can be deleted. +func (vmHandler *NcpVMHandler) WaitToDelPublicIp(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("======> As Public IP cannot be deleted immediately after VM termination call, it waits until termination is finished.") + + curRetryCnt := 0 + maxRetryCnt := 600 + + for { + curStatus, errStatus := vmHandler.GetVMStatus(vmIID) + if errStatus != nil { + cblogger.Errorf("Failed to Get the VM Status of : [%s]", vmIID) + cblogger.Error(errStatus.Error()) + // return irs.VMStatus("Failed. "), errors.New("Failed to Get the VM Status.") // Caution!! + } else { + cblogger.Infof("Succeeded in Getting the VM Status of [%s] : [%s]", vmIID, curStatus) + } + cblogger.Info("===> VM Status : ", curStatus) + + switch string(curStatus) { + case "Suspended", "Terminating": + curRetryCnt++ + cblogger.Infof("The VM is still 'Terminating', so wait for a second more before inquiring the VM info.") + time.Sleep(time.Second * 3) + if curRetryCnt > maxRetryCnt { + cblogger.Errorf("Despite waiting for a long time(%d sec), the VM status is '%s', so it is forcibly finished.", maxRetryCnt, curStatus) + return irs.VMStatus("Failed"), errors.New("Despite waiting for a long time, the VM status is 'Creating', so it is forcibly finishied.") + } + + default: + cblogger.Infof("===>### The VM Termination is finished, so stopping the waiting.") + return irs.VMStatus(curStatus), nil + //break + } + } +} + +// Whenever a VM is terminated, Delete the public IP that the VM has +func (vmHandler *NcpVMHandler) DeletePublicIP(vmInfo irs.VMInfo) (irs.VMStatus, error) { + cblogger.Info("NCP Classic Cloud driver: called DeletePublicIP()!") + + var publicIPId string + + // Use Key/Value info of the vmInfo. + for _, keyInfo := range vmInfo.KeyValueList { + if keyInfo.Key == "PublicIpID" { + publicIPId = keyInfo.Value + break + } + } + + // spew.Dump(vmInfo.PublicIP) + // spew.Dump(publicIPId) + + //========================================= + // Wait for that the VM is terminated + //========================================= + curStatus, errStatus := vmHandler.WaitToDelPublicIp(vmInfo.IId) + if errStatus != nil { + cblogger.Error(errStatus.Error()) + // return irs.VMStatus("Failed. "), errStatus // Caution!! + } + cblogger.Infof("==> VM status of [%s] : [%s]", vmInfo.IId.NameId, curStatus) + + deleteReq := server.DeletePublicIpInstancesRequest{ + PublicIpInstanceNoList: []*string{ + ncloud.String(publicIPId), + }, + } + cblogger.Infof("DeletePublicIPReq Ready!!") + result, err := vmHandler.VMClient.V2Api.DeletePublicIpInstances(&deleteReq) + if err != nil { + cblogger.Error(*result.ReturnMessage) + newErr := fmt.Errorf("Failed to Delete the PublicIP of the instance : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMStatus("Failed. "), newErr + } + if *result.TotalRows < 1 { + return irs.VMStatus("Failed to Delete any PublicIP of the instance. [%v]"), err + } else { + cblogger.Infof(" ### Succeeded in Deleting the PublicIP of the instance.!!") + } + + return irs.VMStatus("Terminating"), nil +} + +func (vmHandler *NcpVMHandler) GetVmIdByName(vmNameID string) (string, error) { + cblogger.Info("NCP Classic Cloud driver: called GetVmIdByName()!") + + var vmId string + // Get VM list + vmList, err := vmHandler.ListVM() + if err != nil { + return "", err + } + + // Search VM by Name in the VM list + for _, vm := range vmList { + if strings.EqualFold(vm.IId.NameId, vmNameID) { + vmId = vm.IId.SystemId + break + } + } + + // Error handling when the VM is not found + if vmId == "" { + newErr := fmt.Errorf("Failed to Find the VM with the name : [%s]", vmNameID) + return "", newErr + } else { + return vmId, nil + } +} + +func (vmHandler *NcpVMHandler) CreateVPCnSubnetTag(vmID *string, vpcName string, subnetName string) (bool, error) { + cblogger.Info("NCP Classic Cloud driver: called CreateVPCnSubnetTag()!") + + var instanceNos []*string + var instanceTags []*server.InstanceTagParameter + + tagKey := []string {"VPCName", "SubnetName"} + + instanceNos = append(instanceNos, vmID) + instanceTags = []*server.InstanceTagParameter { + { + TagKey: ncloud.String(tagKey[0]), + TagValue: ncloud.String(vpcName), + }, + { + TagKey: ncloud.String(tagKey[1]), + TagValue: ncloud.String(subnetName), + }, + } + // cblogger.Info("\n instanceTags : ") + // spew.Dump(instanceTags) + + tagReq := server.CreateInstanceTagsRequest{ + InstanceNoList: instanceNos, + InstanceTagList: instanceTags, + } + // cblogger.Info("\n tagReq : ") + // spew.Dump(tagReq) + tagResult, err := vmHandler.VMClient.V2Api.CreateInstanceTags(&tagReq) + if err != nil { + cblogger.Errorf("Failed to Create NCP VM Tag. : [%v]", err) + cblogger.Error(*tagResult.ReturnMessage) + return false, err + } else { + cblogger.Infof("tagResult.ReturnMessage : [%s]", *tagResult.ReturnMessage) + } + + return true, nil +} + +func (vmHandler *NcpVMHandler) GetVPCnSubnetNameFromTag(vmID *string) (string, string, error) { + cblogger.Info("NCP Classic Cloud driver: called GetVPCnSubnetNameFromTag()!") + + var instanceNos []*string + instanceNos = append(instanceNos, vmID) + var vpcName string + var subnetName string + + instanceTagReq := server.GetInstanceTagListRequest{InstanceNoList: instanceNos} + // spew.Dump(instanceTagReq) + getTagListResult, err := vmHandler.VMClient.V2Api.GetInstanceTagList(&instanceTagReq) + if err != nil { + cblogger.Error(*getTagListResult.ReturnMessage) + newErr := fmt.Errorf("Failed to Find VM Tag List from NCP : [%v]", err) + return "", "", newErr + } + if len(getTagListResult.InstanceTagList) < 1 { + newErr := fmt.Errorf("Failed to Find Any Tag from the VM SystemID!!") + return "", "", newErr + } else { + cblogger.Infof("getTagListResult.ReturnMessage : [%s]", *getTagListResult.ReturnMessage) + // spew.Dump("\n getTagListResult : ", *getTagListResult) + } + cblogger.Infof("Succeeded in Getting Tag info from the VM!!") + + for _, curTag := range getTagListResult.InstanceTagList { + if ncloud.StringValue(curTag.TagKey) == "VPCName" { + vpcName = ncloud.StringValue(curTag.TagValue) + } else if ncloud.StringValue(curTag.TagKey) == "SubnetName" { + subnetName = ncloud.StringValue(curTag.TagValue) + } + } + if len(vpcName) < 1 { + cblogger.Errorf("Failed to Get VPC Name from the Tag!!") + return "", "", errors.New("Failed to Get VPC Name from the Tag!!") + } + if len(subnetName) < 1 { + cblogger.Errorf("Failed to Get Subnet Name from the Tag!!") + return "", "", errors.New("Failed to Get Subnet Name from the Tag!!") + } + return vpcName, subnetName, nil +} + +func (vmHandler *NcpVMHandler) DeleteVMTags(vmID *string) (bool, error) { + cblogger.Info("NCP Classic Cloud driver: called DeleteVMTags()!") + + var instanceNos []*string + instanceNos = append(instanceNos, vmID) + + tagReq := server.DeleteInstanceTagsRequest { + InstanceNoList: instanceNos, + } + tagResult, err := vmHandler.VMClient.V2Api.DeleteInstanceTags(&tagReq) + if err != nil { + cblogger.Errorf("Failed to Delete NCP VM Tag. : [%v]", err) + cblogger.Error(*tagResult.ReturnMessage) + return false, err + } else { + cblogger.Infof("tagResult.ReturnMessage : [%s]", *tagResult.ReturnMessage) + } + + return true, nil +} + +func (vmHandler *NcpVMHandler) GetNcpVMInfo(instanceId string) (*server.ServerInstance, error) { + cblogger.Info("NCP Classic Cloud driver: called GetNcpVMInfo()") + + vmIID := irs.IID{SystemId: instanceId} + instanceNumList := []*string{ncloud.String(instanceId)} + + curStatus, errStatus := vmHandler.GetVMStatus(vmIID) + if errStatus != nil { + newErr := fmt.Errorf("Failed to Get the Status of the VM : [%v]", errStatus) + cblogger.Error(newErr.Error()) + return nil, newErr + } + cblogger.Info("===> VM Status : ", curStatus) + + // Since it's impossible to get VM info. during Creation, ... + switch string(curStatus) { + case "Creating", "Booting": + cblogger.Infof("Wait for the VM creation before inquiring VM info. The VM status : [%s]", string(curStatus)) + return nil, errors.New("The VM status is 'Creating' or 'Booting', wait for the VM creation before inquiring VM info. : " + vmIID.SystemId) + default: + cblogger.Infof("===> The VM status not 'Creating' or 'Booting', you can get the VM info.") + } + + regionNo, err := vmHandler.GetRegionNo(vmHandler.RegionInfo.Region) + if err != nil { + cblogger.Errorf("Failed to Get RegionNo : [%v]", err) + return nil, err + } + zoneNo, err := vmHandler.GetZoneNo(vmHandler.RegionInfo.Zone) + if err != nil { + cblogger.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + return nil, err + } + instanceReq := server.GetServerInstanceListRequest{ + ServerInstanceNoList: instanceNumList, + RegionNo: regionNo, + ZoneNo: zoneNo, + } + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find VM list with the SystemId from NCP : [%s], [%v]", vmIID.SystemId, err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if len(result.ServerInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Find Any VM info with the SystemId : [%s]", vmIID.SystemId) + cblogger.Error(newErr.Error()) + return nil, newErr + } + return result.ServerInstanceList[0], nil +} + +func (vmHandler *NcpVMHandler) GetVmRootDiskInfo(vmId *string) (*string, *string, error) { + cblogger.Info("NCPVPC Cloud driver: called GetVmRootDiskInfo()!!") + + if strings.EqualFold(*vmId, "") { + newErr := fmt.Errorf("Invalid VM ID!!") + cblogger.Error(newErr.Error()) + return nil, nil, newErr + } + + storageReq := server.GetBlockStorageInstanceListRequest { + ServerInstanceNo: vmId, + } + storageResult, err := vmHandler.VMClient.V2Api.GetBlockStorageInstanceList(&storageReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get Block Storage List!! : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, nil, newErr + } + + if *storageResult.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Get any BlockStorage Info!! : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, nil, newErr + } else { + cblogger.Info("Succeeded in Getting BlockStorage Info!!") + } + + var storageSize string + var deviceName *string + for _, disk := range storageResult.BlockStorageInstanceList { + if strings.EqualFold(*disk.ServerInstanceNo, *vmId) && strings.EqualFold(*disk.BlockStorageType.Code, "BASIC") { + storageSize = strconv.FormatFloat(float64(*disk.BlockStorageSize)/(1024*1024*1024), 'f', 0, 64) + deviceName = disk.DeviceName + break + } + } + return &storageSize, deviceName, nil +} + +func (vmHandler *NcpVMHandler) GetVmDataDiskList(vmId *string) ([]irs.IID, error) { + cblogger.Info("NCP Classic Cloud driver: called GetVmDataDiskList()") + + if strings.EqualFold(*vmId, "") { + newErr := fmt.Errorf("Invalid VM Instance ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + storageReq := server.GetBlockStorageInstanceListRequest { + ServerInstanceNo: vmId, + } + storageResult, err := vmHandler.VMClient.V2Api.GetBlockStorageInstanceList(&storageReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get Block Storage List!! : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + if len(storageResult.BlockStorageInstanceList) < 1 { + newErr := fmt.Errorf("Failed to Get any BlockStorage Info!! : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting BlockStorage Info!!") + } + + var dataDiskIIDList []irs.IID + for _, disk := range storageResult.BlockStorageInstanceList { + if strings.EqualFold(*disk.ServerInstanceNo, *vmId) && !strings.EqualFold(*disk.BlockStorageType.Code, "BASIC") { + dataDiskIIDList = append(dataDiskIIDList, irs.IID{NameId: *disk.BlockStorageName, SystemId: *disk.BlockStorageInstanceNo}) + // break + } + } + return dataDiskIIDList, nil +} + +func (vmHandler *NcpVMHandler) CreateLinuxInitUserData(imageIID irs.IID, keyPairId string) (*string, error) { + cblogger.Info("NCPVPC Cloud driver: called CreateLinuxInitScript()!!") + + myImageHandler := NcpMyImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + var getErr error + originImagePlatform, getErr := myImageHandler.GetOriginImageOSPlatform(imageIID) + if getErr != nil { + newErr := fmt.Errorf("Failed to Get OriginImageOSPlatform of the Image : [%v]", getErr) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + var initFilePath string + switch originImagePlatform { + case "UBUNTU" : + initFilePath = os.Getenv("CBSPIDER_ROOT") + ubuntuCloudInitFilePath + case "CENTOS" : + initFilePath = os.Getenv("CBSPIDER_ROOT") + centosCloudInitFilePath + default: + initFilePath = os.Getenv("CBSPIDER_ROOT") + centosCloudInitFilePath + } + cblogger.Infof("\n# initFilePath : [%s]", initFilePath) + + openFile, err := os.Open(initFilePath) + if err != nil { + newErr := fmt.Errorf("Failed to Find and Open the Cloud-Init File : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Infof("Succeeded in Finding and Opening the Cloud-Init File : ") + } + defer openFile.Close() + + cmdStringByte, readErr := io.ReadAll(openFile) + if readErr != nil { + newErr := fmt.Errorf("Failed to Read the open file : [%v]", readErr) + cblogger.Error(newErr.Error()) + return nil, newErr + } + cmdString := string(cmdStringByte) + + // For GetKey() + strList:= []string{ + vmHandler.CredentialInfo.ClientId, + vmHandler.CredentialInfo.ClientSecret, + } + + hashString, err := keycommon.GenHash(strList) + if err != nil { + newErr := fmt.Errorf("Failed to Generate Hash String : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + // Get the publicKey from DB // Caution!! ~.KeyPairIID."SystemId" + keyValue, getKeyErr := keycommon.GetKey("NCP", hashString, keyPairId) + if getKeyErr != nil { + newErr := fmt.Errorf("Failed to Get the Public Key from DB : [%v]", getKeyErr) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + // Set Linux cloud-init script + cmdString = strings.ReplaceAll(cmdString, "{{username}}", lnxUserName) + cmdString = strings.ReplaceAll(cmdString, "{{public_key}}", keyValue.Value) + // cblogger.Info("cmdString : ", cmdString) + return &cmdString, nil +} + +func (vmHandler *NcpVMHandler) CreateWinInitUserData(passWord string) (*string, error) { + cblogger.Info("NCPVPC Cloud driver: called createInitScript()!!") + + // Preparing for UserData String + initFilePath := os.Getenv("CBSPIDER_ROOT") + winCloudInitFilePath + openFile, err := os.Open(initFilePath) + if err != nil { + newErr := fmt.Errorf("Failed to Find and Open the Cloud-Init File : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Infof("Succeeded in Finding and Opening the S/G file: ") + } + defer openFile.Close() + + cmdStringByte, readErr := io.ReadAll(openFile) + if readErr != nil { + newErr := fmt.Errorf("Failed to Read the open file : [%v]", readErr) + cblogger.Error(newErr.Error()) + return nil, newErr + } + cmdString := string(cmdStringByte) + + // Set Windows cloud-init script + cmdString = strings.ReplaceAll(cmdString, "{{PASSWORD}}", passWord) + // cblogger.Info("cmdString : ", cmdString) + return &cmdString, nil +} + +func (vmHandler *NcpVMHandler) GetRegionNo(regionCode string) (*string, error) { + cblogger.Info("NCP Classic Cloud driver: called GetRegionNo()!") + // Search NCP Instance Region'No' corresponding to the NCP Region'Code' + + var vmRegionNo *string + vmRegionNo = nil + + if len(vmHandler.RegionInfo.Region) < 1 { + return nil, errors.New("RegionInfo.Region is Empty!!") + } + + regionListReq := server.GetRegionListRequest{} + regionListResult, err := vmHandler.VMClient.V2Api.GetRegionList(®ionListReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get RegionList from NCP Cloud : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if len(regionListResult.RegionList) < 1 { + newErr := fmt.Errorf("Failed to Find Any Region Info.") + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + // cblogger.Info("# Supported Region count : ", len(regionListResult.RegionList)) + } + + for _, region := range regionListResult.RegionList { + //cblogger.Info("# Search criteria NCP RegionCode : ", *region.RegionCode) + if ncloud.StringValue(region.RegionCode) == vmHandler.RegionInfo.Region { + vmRegionNo = region.RegionNo + cblogger.Info("# Result regionNo : ", ncloud.StringValue(vmRegionNo)) + break + } + } + return vmRegionNo, err +} + +func (vmHandler *NcpVMHandler) GetZoneNo(zoneCode string) (*string, error) { + cblogger.Info("NCP Classic Cloud driver: called GetZoneNo()!") + // Search NCP Instance Zone'No' corresponding to the NCP Zone'Code' + + var vmZoneNo *string + vmZoneNo = nil + + if len(vmHandler.RegionInfo.Zone) < 1 { + return vmZoneNo, errors.New("RegionInfo.Zone is Empty!!") + } + + regionListReq := server.GetRegionListRequest{} + regionListResult, err := vmHandler.VMClient.V2Api.GetRegionList(®ionListReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get RegionList from NCP Cloud : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if len(regionListResult.RegionList) < 1 { + newErr := fmt.Errorf("Failed to Find Any Region Info.") + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + // cblogger.Info("# Supported Region count : ", len(regionListResult.RegionList)) + } + + for _, region := range regionListResult.RegionList { + // cblogger.Info("# 기준 NCP Region No : ", *region.RegionNo) + zoneListReq := server.GetZoneListRequest{ + RegionNo: region.RegionNo, + //RegionNo: nil, //CAUTION!! : 이렇게 조회하면 zone이 한국 zone 두개만 나옴. + } + zoneListResult, err := vmHandler.VMClient.V2Api.GetZoneList(&zoneListReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get zoneList from NCP Cloud : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + for _, zone := range zoneListResult.ZoneList { + //cblogger.Info("# Search criteria NCP ZoneCode : ", *zone.ZoneCode) + if ncloud.StringValue(zone.ZoneCode) == vmHandler.RegionInfo.Zone { + vmZoneNo = zone.ZoneNo + cblogger.Info("# Result zoneNo : ", ncloud.StringValue(vmZoneNo)) + break + } + } + } + return vmZoneNo, err +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go new file mode 100644 index 000000000..c8b48595f --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VMSpecHandler.go @@ -0,0 +1,379 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VM Spec Handler +// +// by ETRI, 2020.09. + +package resources + +import ( + "errors" + "fmt" + "strconv" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + 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" +) + +type NcpVMSpecHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VMSpecHandler") +} + +func (vmSpecHandler *NcpVMSpecHandler) ListVMSpec() ([]*irs.VMSpecInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called ListVMSpec()!") + + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMIMAGE, "ListVMSpec()", "ListVMSpec()") + + ncpRegion := vmSpecHandler.RegionInfo.Region + cblogger.Infof("Region : [%s]", ncpRegion) + + vmHandler := NcpVMHandler{ + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(vmSpecHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + zoneNo, err := vmHandler.GetZoneNo(vmSpecHandler.RegionInfo.Zone) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + imageHandler := NcpImageHandler{ + CredentialInfo: vmSpecHandler.CredentialInfo, + RegionInfo: vmSpecHandler.RegionInfo, //CAUTION!! + VMClient: vmSpecHandler.VMClient, + } + imageListResult, err := imageHandler.ListImage() + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Image list!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Info("Image list Count : ", len(imageListResult)) + // spew.Dump(imageListResult) + } + + // Note : var vmProductList []*server.Product //NCP Product(Spec) Info. + var vmSpecInfoList []*irs.VMSpecInfo //Cloud-Barista Spec Info. + + for _, image := range imageListResult { + cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + + vmSpecReq := server.GetServerProductListRequest{ + RegionNo: regionNo, + ZoneNo: zoneNo, + ServerImageProductCode: ncloud.String(image.IId.SystemId), // ***** Caution : ImageProductCode is mandatory. ***** + // GenerationCode: ncloud.String("G2"), // # Caution!! : Generations are divided only in the Korean Region. + } + result, err := vmSpecHandler.VMClient.V2Api.GetServerProductList(&vmSpecReq) + if err != nil { + cblogger.Error(*result.ReturnMessage) + cblogger.Error(fmt.Sprintf("Failed to Get VMSpec list from NCP : [%v]", err)) + 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)) + } + + for _, product := range result.ProductList { + vmSpecInfo := MappingVMSpecInfo(ncpRegion, image.IId.SystemId, *product) + vmSpecInfoList = append(vmSpecInfoList, &vmSpecInfo) + } + } + cblogger.Infof("# 총 VMSpec 수 : [%d]", len(vmSpecInfoList)) + return vmSpecInfoList, err +} + +func (vmSpecHandler *NcpVMSpecHandler) GetVMSpec(Name string) (irs.VMSpecInfo, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetVMSpec()!") + + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, Name, "GetVMSpec()") + + ncpRegion := vmSpecHandler.RegionInfo.Region + cblogger.Infof("Region : [%s] / SpecName : [%s]", ncpRegion, Name) + + vmHandler := NcpVMHandler{ + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(vmSpecHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMSpecInfo{}, newErr + } + zoneNo, err := vmHandler.GetZoneNo(vmSpecHandler.RegionInfo.Zone) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMSpecInfo{}, newErr + } + + imgHandler := NcpImageHandler{ + CredentialInfo: vmSpecHandler.CredentialInfo, + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + cblogger.Infof("imgHandler.RegionInfo.Zone : [%s]", imgHandler.RegionInfo.Zone) //Need to Check the value!! + + imgListResult, err := imgHandler.ListImage() + if err != nil { + cblogger.Infof("Failed to Find Image list!! : ", err) + return irs.VMSpecInfo{}, errors.New("Failed to Find Image list!!") + } else { + cblogger.Info("Succeeded in Getting Image list!!") + // cblogger.Info(imgListResult) + cblogger.Infof("Image list Count : [%d]", len(imgListResult)) + // spew.Dump(imgListResult) + } + + for _, image := range imgListResult { + cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + + specReq := server.GetServerProductListRequest{ + RegionNo: regionNo, + ZoneNo: zoneNo, + ProductCode: &Name, + ServerImageProductCode: ncloud.String(image.IId.SystemId), // ***** Caution : ImageProductCode is mandatory. ***** + } + callLogStart := call.Start() + result, err := vmSpecHandler.VMClient.V2Api.GetServerProductList(&specReq) + if err != nil { + cblogger.Error(*result.ReturnMessage) + newErr := fmt.Errorf("Failed to Find VMSpec list from NCP : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMSpecInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + // spew.Dump(result) + + if len(result.ProductList) > 0 { + specInfo := MappingVMSpecInfo(ncpRegion, image.IId.SystemId, *result.ProductList[0]) + return specInfo, nil + } + } + return irs.VMSpecInfo{}, errors.New("Not found : VMSpec Name'" + Name + "' Not found!!") +} + +func (vmSpecHandler *NcpVMSpecHandler) ListOrgVMSpec() (string, error) { + cblogger.Info("NCP Classic Cloud Driver: called ListOrgVMSpec()!") + + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMIMAGE, "ListOrgVMSpec()", "ListOrgVMSpec()") + + ncpRegion := vmSpecHandler.RegionInfo.Region + cblogger.Infof("Region : [%s]", ncpRegion) + + vmHandler := NcpVMHandler{ + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(vmSpecHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + zoneNo, err := vmHandler.GetZoneNo(vmSpecHandler.RegionInfo.Zone) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + imageHandler := NcpImageHandler{ + CredentialInfo: vmSpecHandler.CredentialInfo, + RegionInfo: vmSpecHandler.RegionInfo, //CAUTION!! + VMClient: vmSpecHandler.VMClient, + } + imageListResult, err := imageHandler.ListImage() + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Image list!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } else { + cblogger.Info("Image list Count : ", len(imageListResult)) + // spew.Dump(imageListResult) + } + + var productList []*server.Product //NCP Product(Spec) Info. + for _, image := range imageListResult { + cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + + vmSpecReq := server.GetServerProductListRequest{ + RegionNo: regionNo, + ZoneNo: zoneNo, + ServerImageProductCode: ncloud.String(image.IId.SystemId), // ***** Caution : ImageProductCode is mandatory. ***** + // GenerationCode: ncloud.String("G2"), // # Caution!! : Generations are divided only in the Korean Region. + } + result, err := vmSpecHandler.VMClient.V2Api.GetServerProductList(&vmSpecReq) + if err != nil { + cblogger.Error(*result.ReturnMessage) + cblogger.Error(fmt.Sprintf("Failed to Get VMSpec list from NCP : [%v]", err)) + 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)) + } + + for _, product := range result.ProductList { + productList = append(productList, product) + } + } + cblogger.Infof("# 총 VMSpec 수 : [%d]", len(productList)) + + jsonString, jsonErr := ConvertJsonString(productList) + if jsonErr != nil { + cblogger.Error(jsonErr) + return "", jsonErr + } + return jsonString, jsonErr +} + +func (vmSpecHandler *NcpVMSpecHandler) GetOrgVMSpec(Name string) (string, error) { + cblogger.Info("NCP Classic Cloud Driver: called GetOrgVMSpec()!") + + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, Name, "GetOrgVMSpec()") + + ncpRegion := vmSpecHandler.RegionInfo.Region + cblogger.Infof("Region : [%s] / SpecName : [%s]", ncpRegion, Name) + + vmHandler := NcpVMHandler{ + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + regionNo, err := vmHandler.GetRegionNo(vmSpecHandler.RegionInfo.Region) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP Region No of the Region Code: [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + zoneNo, err := vmHandler.GetZoneNo(vmSpecHandler.RegionInfo.Zone) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Zone No of the Zone Code : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + imgHandler := NcpImageHandler{ + CredentialInfo: vmSpecHandler.CredentialInfo, + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + cblogger.Infof("imgHandler.RegionInfo.Zone : [%s]", imgHandler.RegionInfo.Zone) //Need to Check the value!! + + imgListResult, err := imgHandler.ListImage() + if err != nil { + cblogger.Infof("Failed to Find Image list!! : ", err) + return "", errors.New("Failed to Find Image list!!") + } else { + cblogger.Info("Succeeded in Getting Image list!!") + // cblogger.Info(imgListResult) + cblogger.Infof("Image list Count : [%d]", len(imgListResult)) + // spew.Dump(imgListResult) + } + + for _, image := range imgListResult { + cblogger.Infof("# 기준 NCP Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + + specReq := server.GetServerProductListRequest{ + RegionNo: regionNo, + ZoneNo: zoneNo, + ProductCode: &Name, + ServerImageProductCode: ncloud.String(image.IId.SystemId), // ***** Caution : ImageProductCode is mandatory. ***** + } + callLogStart := call.Start() + result, err := vmSpecHandler.VMClient.V2Api.GetServerProductList(&specReq) + if err != nil { + cblogger.Error(*result.ReturnMessage) + newErr := fmt.Errorf("Failed to Find VMSpec list from NCP : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + LoggingInfo(callLogInfo, callLogStart) + // spew.Dump(result) + + if len(result.ProductList) > 0 { + jsonString, jsonErr := ConvertJsonString(*result.ProductList[0]) + if jsonErr != nil { + cblogger.Error(jsonErr) + return "", jsonErr + } + return jsonString, jsonErr + } + } + + return "", nil +} + +func MappingVMSpecInfo(Region string, ImageId string, NcpVMSpec server.Product) irs.VMSpecInfo { + // server ProductList type : []*Product + cblogger.Infof("*** Mapping VMSpecInfo : Region: [%s] / SpecName: [%s]", Region, *NcpVMSpec.ProductCode) + // spew.Dump(vmSpec) + + // vmSpec에 리전 정보는 없기 때문에 받은 리전 정보로 기입 + // NOTE 주의 : 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"}, + + // server.Product에 GPU 정보는 없음. + Gpu: []irs.GpuInfo{{Count: "N/A", Model: "N/A"}}, + + KeyValueList: []irs.KeyValue{ + // {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}, + }, + } + + // 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) + + return vmSpecInfo +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncp/resources/VPCHandler.go b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VPCHandler.go new file mode 100644 index 000000000..bb339a134 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncp/resources/VPCHandler.go @@ -0,0 +1,379 @@ +// Cloud Driver Interface of CB-Spider. +// The CB-Spider is a sub-Framework of the Cloud-Barista Multi-Cloud Project. +// The CB-Spider Mission is to connect all the clouds with a single interface. +// +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VPC Handler +// +// by ETRI, 2021.12. +// Updated by ETRI, 2023.10. + +package resources + +import ( + "os" + "io" + "fmt" + "encoding/json" + "errors" + "strings" + + // "github.com/davecgh/go-spew/spew" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server" + cblog "github.com/cloud-barista/cb-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" +) + +type NcpVPCHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *server.APIClient +} + +const ( + vpcDir string = "/cloud-driver-libs/.vpc-ncp/" +) + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC Handler") +} + +type VPC struct { + IID IId `json:"IId"` + Cidr string `json:"IPv4_CIDR"` + Subnet_List []Subnet `json:"SubnetInfoList"` + KeyValue_List []KeyValue `json:"KeyValueList"` +} + +type Subnet struct { + IID IId `json:"IId"` + Cidr string `json:"IPv4_CIDR"` + KeyValue_List []KeyValue `json:"KeyValueList"` +} + +type KeyValue struct { + Key string `json:"Key"` + Value string `json:"Value"` +} + +type IId struct { + NameID string `json:"NameId"` + SystemID string `json:"SystemId"` +} + +func (VPCHandler *NcpVPCHandler) CreateVPC(vpcReqInfo irs.VPCReqInfo) (irs.VPCInfo, error) { + cblogger.Info("NCP Cloud Driver: called CreateVPC()!") + + // Check if the VPC Name already Exists + vpcInfo, _ := VPCHandler.GetVPC(irs.IID{SystemId: vpcReqInfo.IId.NameId}) // '_' : For when there is no VPC. + + if vpcInfo.IId.SystemId != "" { + newErr := fmt.Errorf("The VPC already exists.") + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + + zoneId := VPCHandler.RegionInfo.Zone + if zoneId == "" { + newErr := fmt.Errorf("Failed to Get Zone info. from the connection info..") + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } else { + cblogger.Infof("ZoneId : %s", zoneId) + } + + var subnetList []irs.SubnetInfo + for _, curSubnet := range vpcReqInfo.SubnetInfoList { + cblogger.Infof("Subnet NameId : %s", curSubnet.IId.NameId) + newSubnet, subnetErr := VPCHandler.CreateSubnet(curSubnet) + if subnetErr != nil { + return irs.VPCInfo{}, subnetErr + } + subnetList = append(subnetList, newSubnet) + } + + newVpcInfo := irs.VPCInfo{ + IId: irs.IID{ + NameId: vpcReqInfo.IId.NameId, + // Note!! : vpcReqInfo.IId.NameId -> SystemId + SystemId: vpcReqInfo.IId.NameId, + }, + IPv4_CIDR: vpcReqInfo.IPv4_CIDR, + SubnetInfoList: subnetList, + KeyValueList: []irs.KeyValue{ + {Key: "NCP-VPC-info.", Value: "This VPC info. is temporary."}, + }, + } + // spew.Dump(newVpcInfo) + + vpcPath := os.Getenv("CBSPIDER_ROOT") + vpcDir + vpcFilePath := vpcPath + zoneId + "/" + jsonFileName := vpcFilePath + vpcReqInfo.IId.NameId + ".json" + // cblogger.Infof("jsonFileName to Create : [%s]", jsonFileName) + + // Check if the VPC Folder Exists, and Create it + if err := CheckFolderAndCreate(vpcPath); err != nil { + newErr := fmt.Errorf("Failed to Create the VPC File Dir : %s, [%v]" + vpcPath, err) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + + // Check if the VPC Folder Exists, and Create it + if err := CheckFolderAndCreate(vpcFilePath); err != nil { + newErr := fmt.Errorf("Failed to Create the VPC File Path : %s, [%v]" + vpcFilePath, err) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + + // Write 'newVpcInfo' to a JSON File + file, _ := json.MarshalIndent(newVpcInfo, "", " ") + writeErr := os.WriteFile(jsonFileName, file, 0644) + if writeErr != nil { + newErr := fmt.Errorf("Failed to write the file : %s, [%v]", jsonFileName, writeErr) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + // cblogger.Infof("Succeeded in writing the VPC info on file : [%s]", jsonFileName) + // cblogger.Infof("Succeeded in Creating the VPC : [%s]", newVpcInfo.IId.NameId) + + // Because it's managed as a file, there's no SystemId created. + // Return the created SecurityGroup info. + vpcInfo, vpcErr := VPCHandler.GetVPC(irs.IID{SystemId: vpcReqInfo.IId.NameId}) + if vpcErr != nil { + newErr := fmt.Errorf("Failed to Get the VPC Info : [%v]", vpcErr) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + return vpcInfo, nil +} + +func (VPCHandler *NcpVPCHandler) GetVPC(vpcIID irs.IID) (irs.VPCInfo, error) { + cblogger.Info("NCP Cloud Driver: called GetVPC()!") + + // Note!! + if vpcIID.SystemId != "" { + vpcIID.NameId = vpcIID.SystemId + } + + zoneId := VPCHandler.RegionInfo.Zone + if zoneId == "" { + newErr := fmt.Errorf("Failed to Get Zone info. from the connection info.") + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } else { + cblogger.Infof("ZoneId : %s", zoneId) + } + + vpcPath := os.Getenv("CBSPIDER_ROOT") + vpcDir + vpcFilePath := vpcPath + zoneId + "/" + jsonFileName := vpcFilePath + vpcIID.NameId + ".json" + + // cblogger.Infof("vpcIID.NameId : %s", vpcIID.NameId) + // cblogger.Infof("jsonFileName : %s", jsonFileName) + + // Check if the VPC Folder Exists, and Create it + if err := CheckFolderAndCreate(vpcPath); err != nil { + newErr := fmt.Errorf("Failed to Create the VPC File Dir : %s, [%v]" + vpcPath, err) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + + // Check if the VPC Folder Exists, and Create it + if err := CheckFolderAndCreate(vpcFilePath); err != nil { + newErr := fmt.Errorf("Failed to Create the VPC File Path : %s, [%v]" + vpcFilePath, err) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + + jsonFile, err := os.Open(jsonFileName) + if err != nil { + newErr := fmt.Errorf("Failed to Find the VPC file : %s, [%v]"+ jsonFileName +" ", err) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + defer jsonFile.Close() + // cblogger.Info("Succeeded in Finding and Opening the VPC file: "+ jsonFileName) + + var vpcJSON VPC + byteValue, readErr := io.ReadAll(jsonFile) + if readErr != nil { + newErr := fmt.Errorf("Failed to Read the VPC file : %s, [%v]"+ jsonFileName, readErr) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + json.Unmarshal(byteValue, &vpcJSON) + + vpcInfo, vpcInfoErr := VPCHandler.MappingVPCInfo(vpcJSON) + if vpcInfoErr != nil { + newErr := fmt.Errorf("Failed to Map the VPC Info : [%v]", vpcInfoErr) + cblogger.Error(newErr.Error()) + return irs.VPCInfo{}, newErr + } + return vpcInfo, nil +} + +func (VPCHandler *NcpVPCHandler) ListVPC() ([]*irs.VPCInfo, error) { + cblogger.Info("NCP Cloud Driver: called ListVPC()!") + + var vpcIID irs.IID + var vpcInfoList []*irs.VPCInfo + + zoneId := VPCHandler.RegionInfo.Zone + if zoneId == "" { + newErr := fmt.Errorf("Failed to Get Zone info. from the connection info.") + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Infof("ZoneId : %s", zoneId) + } + + vpcFilePath := os.Getenv("CBSPIDER_ROOT") + vpcDir + zoneId + "/" + // File list on the local directory + dirFiles, readErr := os.ReadDir(vpcFilePath) + if readErr != nil { + newErr := fmt.Errorf("Failed to Read the VPC file : [%v]", readErr) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + for _, file := range dirFiles { + fileName := strings.TrimSuffix(file.Name(), ".json") // 접미사 제거 + vpcIID.NameId = fileName + cblogger.Infof("# VPC Name : " + vpcIID.NameId) + + vpcInfo, vpcErr := VPCHandler.GetVPC(irs.IID{SystemId: vpcIID.NameId}) + if vpcErr != nil { + newErr := fmt.Errorf("Failed to Get the VPC Info : [%v]", vpcErr) + cblogger.Error(newErr.Error()) + return nil, newErr + } + vpcInfoList = append(vpcInfoList, &vpcInfo) + } + return vpcInfoList, nil +} + +func (VPCHandler *NcpVPCHandler) DeleteVPC(vpcIID irs.IID) (bool, error) { + cblogger.Info("NCP Cloud Driver: called DeleteVPC()!") + + if vpcIID.SystemId != "" { + vpcIID.NameId = vpcIID.SystemId + } + + //To check whether the VPC exists. + _, vpcErr := VPCHandler.GetVPC(irs.IID{SystemId: vpcIID.NameId}) + if vpcErr != nil { + newErr := fmt.Errorf("Failed to Get the VPC Info : [%v]", vpcErr) + cblogger.Error(newErr.Error()) + return false, newErr + } + + zoneId := VPCHandler.RegionInfo.Zone + if zoneId == "" { + newErr := fmt.Errorf("Failed to Get Zone info. from the connection info.") + cblogger.Error(newErr.Error()) + return false, newErr + } else { + cblogger.Infof("ZoneId : %s", zoneId) + } + + vpcPath := os.Getenv("CBSPIDER_ROOT") + vpcDir + vpcFilePath := vpcPath + zoneId + "/" + jsonFileName := vpcFilePath + vpcIID.NameId + ".json" + + cblogger.Infof("VPC info file to Delete : [%s]", jsonFileName) + + // Check if the VPC Folder Exists, and Create it + if err := CheckFolderAndCreate(vpcPath); err != nil { + newErr := fmt.Errorf("Failed to Create the VPC File Dir : %s, [%v]" + vpcPath, err) + cblogger.Error(newErr.Error()) + return false, newErr + } + + // Check if the VPC Folder Exists, and Create it + if err := CheckFolderAndCreate(vpcFilePath); err != nil { + newErr := fmt.Errorf("Failed to Create the VPC File Path : %s, [%v]" + vpcFilePath, err) + cblogger.Error(newErr.Error()) + return false, newErr + } + + // To Remove the VPC file on the Local machine. + delErr := os.Remove(jsonFileName) + if delErr != nil { + newErr := fmt.Errorf("Failed to Delete the file : %s, [%v]", jsonFileName, delErr) + cblogger.Error(newErr.Error()) + return false, newErr + } + cblogger.Infof("Succeeded in Deleting the VPC : " + vpcIID.NameId) + + return true, nil +} + +func (VPCHandler *NcpVPCHandler) AddSubnet(vpcIID irs.IID, subnetInfo irs.SubnetInfo) (irs.VPCInfo, error) { + cblogger.Info("NCP cloud driver: called AddSubnet()!!") + return irs.VPCInfo{}, errors.New("Does not support AddSubnet() yet!!") +} + +func (VPCHandler *NcpVPCHandler) RemoveSubnet(vpcIID irs.IID, subnetIID irs.IID) (bool, error) { + cblogger.Info("NCP cloud driver: called GetImage()!!") + return true, errors.New("Does not support RemoveSubnet() yet!!") +} + +func (VPCHandler *NcpVPCHandler) CreateSubnet(subnetReqInfo irs.SubnetInfo) (irs.SubnetInfo, error) { + cblogger.Info("NCP cloud driver: called CreateSubnet()!!") + + newSubnetInfo := irs.SubnetInfo{ + IId: irs.IID{ + NameId: subnetReqInfo.IId.NameId, + // Note!! : subnetReqInfo.IId.NameId -> SystemId + SystemId: subnetReqInfo.IId.NameId, + }, + IPv4_CIDR: subnetReqInfo.IPv4_CIDR, + KeyValueList: []irs.KeyValue{ + {Key: "NCP-Subnet-info.", Value: "This Subnet info. is temporary."}, + }, + } + return newSubnetInfo, nil +} + +func (VPCHandler *NcpVPCHandler) MappingVPCInfo(vpcJSON VPC) (irs.VPCInfo, error) { + cblogger.Info("NCP cloud driver: called MappingVPCInfo()!!") + + var subnetInfoList []irs.SubnetInfo + var subnetInfo irs.SubnetInfo + var subnetKeyValue irs.KeyValue + var subnetKeyValueList []irs.KeyValue + var vpcKeyValue irs.KeyValue + var vpcKeyValueList []irs.KeyValue + + for i := 0; i < len(vpcJSON.Subnet_List); i++ { + subnetInfo.IId.NameId = vpcJSON.Subnet_List[i].IID.NameID + subnetInfo.IId.SystemId = vpcJSON.Subnet_List[i].IID.SystemID + subnetInfo.IPv4_CIDR = vpcJSON.Subnet_List[i].Cidr + + for j := 0; j < len(vpcJSON.Subnet_List[i].KeyValue_List); j++ { + subnetKeyValue.Key = vpcJSON.Subnet_List[i].KeyValue_List[j].Key + subnetKeyValue.Value = vpcJSON.Subnet_List[i].KeyValue_List[j].Value + subnetKeyValueList = append(subnetKeyValueList, subnetKeyValue) + } + subnetInfo.KeyValueList = subnetKeyValueList + subnetInfoList = append(subnetInfoList, subnetInfo) + } + + for k := 0; k < len(vpcJSON.KeyValue_List); k++ { + vpcKeyValue.Key = vpcJSON.KeyValue_List[k].Key + vpcKeyValue.Value = vpcJSON.KeyValue_List[k].Value + vpcKeyValueList = append(vpcKeyValueList, vpcKeyValue) + } + + vpcInfo := irs.VPCInfo{ + //VPC 정보는 CB에서 파일로 관리되므로 SystemId는 NameId와 동일하게 + IId: irs.IID{NameId: vpcJSON.IID.NameID, SystemId: vpcJSON.IID.NameID}, + IPv4_CIDR: vpcJSON.Cidr, + SubnetInfoList: subnetInfoList, + KeyValueList: vpcKeyValueList, + } + return vpcInfo, nil +} diff --git a/go.mod b/go.mod index d8d1a22fc..79e28eede 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/golang-jwt/jwt/v4 v4.0.0 github.com/golang/protobuf v1.5.3 - github.com/gophercloud/gophercloud v0.18.0 + github.com/gophercloud/gophercloud v1.3.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/natefinch/lumberjack v2.0.0+incompatible @@ -57,7 +57,9 @@ require ( require ( github.com/IBM/platform-services-go-sdk v0.30.0 + github.com/NaverCloudPlatform/ncloud-sdk-go-v2 v1.6.6 github.com/go-openapi/strfmt v0.21.3 + github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 github.com/hashicorp/go-version v1.6.0 github.com/jeremywohl/flatten v1.0.1 github.com/labstack/echo/v4 v4.9.0 @@ -69,6 +71,7 @@ require ( ) require ( + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect diff --git a/go.sum b/go.sum index 174361ad1..be1eddc4e 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6Xge github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NaverCloudPlatform/ncloud-sdk-go-v2 v1.6.6 h1:Od8shFxV5SCIECjYCE3Q5H7iAWqfVcLiLjmfJXTEQ/U= +github.com/NaverCloudPlatform/ncloud-sdk-go-v2 v1.6.6/go.mod h1:sDa6EITv6z/l6+d4VJk4OiRZnXuO0uG2Cm30qtqF4TU= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -340,8 +342,10 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gophercloud/gophercloud v0.18.0 h1:V6hcuMPmjXg+js9flU8T3RIHDCjV7F5CG5GD0MRhP/w= -github.com/gophercloud/gophercloud v0.18.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= +github.com/gophercloud/gophercloud v1.3.0 h1:RUKyCMiZoQR3VlVR5E3K7PK1AC3/qppsWYo6dtBiqs8= +github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 h1:sH7xkTfYzxIEgzq1tDHIMKRh1vThOEOGNsettdEeLbE= +github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56/go.mod h1:VSalo4adEk+3sNkmVJLnhHoOyOYYS8sTWLG4mv5BKto= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -370,6 +374,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -662,6 +668,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -698,10 +705,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -739,6 +747,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -788,6 +797,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -817,6 +828,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -885,12 +897,18 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -902,6 +920,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -969,6 +989,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=