From a9ecec0b3204dd1d6c6d49ef78b8640b82e8daa4 Mon Sep 17 00:00:00 2001 From: Sean Oh Date: Mon, 13 Nov 2023 20:59:15 +0900 Subject: [PATCH] [+NCP VPC conn. driver] Add NCP VPC Driver Codes --- .gitignore | 6 +- build_all_driver_lib.sh | 2 +- .../drivers/ncpvpc-plugin/NcpVpcDriver-lib.go | 136 ++ .../drivers/ncpvpc/NcpVpcDriver.go | 134 ++ .../cloud-driver/drivers/ncpvpc/README.md | 165 ++ .../ncpvpc/connect/NcpVpcCloudConnection.go | 160 ++ .../drivers/ncpvpc/main/Test_DiskHandler.go | 263 +++ .../drivers/ncpvpc/main/Test_ImageHandler.go | 272 +++ .../ncpvpc/main/Test_KeyPairHandler.go | 261 +++ .../ncpvpc/main/Test_MyImageHandler.go | 237 +++ .../drivers/ncpvpc/main/Test_NLBHandler.go | 347 ++++ .../ncpvpc/main/Test_RegionZoneHandler.go | 244 +++ .../ncpvpc/main/Test_SecurityHandler.go | 482 +++++ .../drivers/ncpvpc/main/Test_VMHandler.go | 364 ++++ .../drivers/ncpvpc/main/Test_VMSpecHandler.go | 256 +++ .../drivers/ncpvpc/main/Test_VPCHandler.go | 304 +++ .../ncpvpc/main/config/config.yaml.sample | 23 + .../drivers/ncpvpc/main/config/gov-setup.env | 2 + .../drivers/ncpvpc/main/gov-cloud-setup.sh | 4 + .../drivers/ncpvpc/main/test_disk.sh | 3 + .../drivers/ncpvpc/main/test_image.sh | 3 + .../drivers/ncpvpc/main/test_keypair.sh | 3 + .../drivers/ncpvpc/main/test_myimage.sh | 3 + .../drivers/ncpvpc/main/test_nlb.sh | 3 + .../drivers/ncpvpc/main/test_region-zone.sh | 3 + .../drivers/ncpvpc/main/test_security.sh | 3 + .../drivers/ncpvpc/main/test_vm.sh | 3 + .../drivers/ncpvpc/main/test_vmspec.sh | 3 + .../drivers/ncpvpc/main/test_vpc.sh | 3 + .../ncpvpc/resources/CommonNcpVpcFunc.go | 122 ++ .../drivers/ncpvpc/resources/DiskHandler.go | 768 ++++++++ .../drivers/ncpvpc/resources/ImageHandler.go | 223 +++ .../ncpvpc/resources/KeyPairHandler.go | 262 +++ .../ncpvpc/resources/MyImageHandler.go | 437 +++++ .../drivers/ncpvpc/resources/NLBHandler.go | 1667 ++++++++++++++++ .../ncpvpc/resources/RegionZoneHandler.go | 257 +++ .../ncpvpc/resources/SecurityHandler.go | 1117 +++++++++++ .../drivers/ncpvpc/resources/VMHandler.go | 1715 +++++++++++++++++ .../drivers/ncpvpc/resources/VMSpecHandler.go | 246 +++ .../drivers/ncpvpc/resources/VPCHandler.go | 913 +++++++++ 40 files changed, 11417 insertions(+), 2 deletions(-) create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc-plugin/NcpVpcDriver-lib.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/NcpVpcDriver.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/README.md create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/connect/NcpVpcCloudConnection.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_DiskHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_ImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_KeyPairHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_MyImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_NLBHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_RegionZoneHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_SecurityHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMSpecHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VPCHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml.sample create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/gov-setup.env create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/gov-cloud-setup.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_disk.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_image.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_keypair.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_myimage.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_nlb.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_region-zone.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_security.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_vm.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_vmspec.sh create mode 100755 cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_vpc.sh create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/CommonNcpVpcFunc.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/DiskHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/ImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/KeyPairHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/MyImageHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/NLBHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/RegionZoneHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/SecurityHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VMHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VMSpecHandler.go create mode 100644 cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VPCHandler.go diff --git a/.gitignore b/.gitignore index 58157e57c..323fb2106 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ *.swp *.pid +*_bak +*_old +*-old .DS_Store @@ -59,4 +62,5 @@ 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 +cloud-control-manager/cloud-driver/drivers/ncp/main/config/config.yaml +cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml diff --git a/build_all_driver_lib.sh b/build_all_driver_lib.sh index a201065fe..c21d6f2fa 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 ncp-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 ncpvpc-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/ncpvpc-plugin/NcpVpcDriver-lib.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc-plugin/NcpVpcDriver-lib.go new file mode 100644 index 000000000..7866929d5 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc-plugin/NcpVpcDriver-lib.go @@ -0,0 +1,136 @@ +// 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 +// +// NCPVPC Cloud Driver PoC +// +// by ETRI, 2020.12. +// by ETRI, 2022.03. updated + +package main + +import ( + // "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + + 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" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + vserver "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + vpc "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vpc" + vlb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vloadbalancer" + + // ncpvpccon "github.com/cloud-barista/ncpvpc/ncpvpc/connect" // For local testing + ncpvpccon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc/connect" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCPVPC Handler") +} + +type NcpVpcDriver struct { +} + +func (NcpVpcDriver) GetDriverVersion() string { + return "TEST NCP VPC DRIVER Version 1.0" +} + +func (NcpVpcDriver) 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 + drvCapabilityInfo.NLBHandler = true + + return drvCapabilityInfo +} + +func getVmClient(connectionInfo idrv.ConnectionInfo) (*vserver.APIClient, error) { + + // NOTE 주의!! + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + + // NOTE for just test + // cblogger.Info(apiKeys.AccessKey) + // cblogger.Info(apiKeys.SecretKey) + + // Create NCPVPC service client + client := vserver.NewAPIClient(vserver.NewConfiguration(&apiKeys)) + + return client, nil +} + +func getVpcClient(connectionInfo idrv.ConnectionInfo) (*vpc.APIClient, error) { + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + + // Create NCP VPC service client + client := vpc.NewAPIClient(vpc.NewConfiguration(&apiKeys)) + + return client, nil +} + +func getVlbClient(connectionInfo idrv.ConnectionInfo) (*vlb.APIClient, error) { + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + + // Create NCP VPC Load Balancer service client + client := vlb.NewAPIClient(vlb.NewConfiguration(&apiKeys)) + + return client, nil +} + +func (driver *NcpVpcDriver) 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 + } + + vpcClient, err := getVpcClient(connectionInfo) + if err != nil { + return nil, err + } + + vlbClient, err := getVlbClient(connectionInfo) + if err != nil { + return nil, err + } + + iConn := ncpvpccon.NcpVpcCloudConnection{ + CredentialInfo: connectionInfo.CredentialInfo, + RegionInfo: connectionInfo.RegionInfo, + VmClient: vmClient, + VpcClient: vpcClient, + VlbClient: vlbClient, + } + + return &iConn, nil +} + +var CloudDriver NcpVpcDriver diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/NcpVpcDriver.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/NcpVpcDriver.go new file mode 100644 index 000000000..72f444780 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/NcpVpcDriver.go @@ -0,0 +1,134 @@ +// 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 +// +// NCPVPC Cloud Driver PoC +// +// by ETRI, 2020.12. +// by ETRI, 2022.10. updated + +package ncpvpc + +import ( + // "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + + 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" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + vserver "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + vpc "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vpc" + vlb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vloadbalancer" + + // ncpvpccon "github.com/cloud-barista/ncpvpc/ncpvpc/connect" // For local testing + ncpvpccon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc/connect" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCPVPC Handler") +} + +type NcpVpcDriver struct { +} + +func (NcpVpcDriver) GetDriverVersion() string { + return "TEST NCP VPC DRIVER Version 1.0" +} + +func (NcpVpcDriver) 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 + drvCapabilityInfo.NLBHandler = true + + return drvCapabilityInfo +} + +func getVmClient(connectionInfo idrv.ConnectionInfo) (*vserver.APIClient, error) { + + // NOTE 주의!! + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + + // NOTE for just test + // cblogger.Info(apiKeys.AccessKey) + // cblogger.Info(apiKeys.SecretKey) + + // Create NCPVPC service client + client := vserver.NewAPIClient(vserver.NewConfiguration(&apiKeys)) + + return client, nil +} + +func getVpcClient(connectionInfo idrv.ConnectionInfo) (*vpc.APIClient, error) { + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + + // Create NCP VPC service client + client := vpc.NewAPIClient(vpc.NewConfiguration(&apiKeys)) + + return client, nil +} + +func getVlbClient(connectionInfo idrv.ConnectionInfo) (*vlb.APIClient, error) { + apiKeys := ncloud.APIKey{ + AccessKey: connectionInfo.CredentialInfo.ClientId, + SecretKey: connectionInfo.CredentialInfo.ClientSecret, + } + + // Create NCP VPC Load Balancer service client + client := vlb.NewAPIClient(vlb.NewConfiguration(&apiKeys)) + + return client, nil +} + +func (driver *NcpVpcDriver) 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 + } + + vpcClient, err := getVpcClient(connectionInfo) + if err != nil { + return nil, err + } + + vlbClient, err := getVlbClient(connectionInfo) + if err != nil { + return nil, err + } + + iConn := ncpvpccon.NcpVpcCloudConnection{ + CredentialInfo: connectionInfo.CredentialInfo, + RegionInfo: connectionInfo.RegionInfo, + VmClient: vmClient, + VpcClient: vpcClient, + VlbClient: vlbClient, + } + + return &iConn, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/README.md b/cloud-control-manager/cloud-driver/drivers/ncpvpc/README.md new file mode 100644 index 000000000..79bf68d43 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/README.md @@ -0,0 +1,165 @@ +### NCP (Naver Cloud Platform) VPC Connection 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 VPC 연동 driver 적용 방법 + +​ 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 VPC driver 등록 과정을 거치고 사용 + +


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


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


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


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


+ +#### # NHN Cloud driver 사용시 참고 및 주의 사항 + O NCP VPC 버전 driver이 지원하는 region 및 zone은 아래의 파일을 참고 +``` + ./ncpvpc/ncpvpc/main/config/config.yaml.sample + ./cb-spider/api-runtime/rest-runtime/test/connect-config/14.ncpvpc-conn-config.sh +``` + + ​O NCP VPC driver를 이용해 VM 생성시 VPC, Subnet, Network Interface에 대해 다음 사항을 참고 + - VPC의 private IP address 범위는, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 대역 내에서 /16~/28 범위여야함. + - Subnet의 private IP address 범위는, VPC의 private address 범위 이하로만 지정이 가능하며, 생성 이후에는 Network ACL만 변경이 가능함. + - 본 driver에서 VM의 Network Interface는 VPC 생성시 자동으로 생성되는 Default Network Interface를 사용하도록 개발되어있음. + + O Security Group에 inbound rule이나 outbound rule을 생성 혹은 추가할때 다음 사항을 참고 + - 다음과 같이 지정하면 모든 protocol에 대해, 모든 port를 open하는 rule이 생성/추가됨(CIDR : '0.0.0.0/0'로 기본 설정됨.) + - Rule 생성/추가시 사용자 지정 값 : IPProtocol : 'All', FromPort : '-1', ToPort : '-1' + + ​O NCP VPC driver를 이용해 VM 생성시 ImageType에 대해 다음 사항을 참고 + - VM 생성시 ImageType을 'default', ''(지정하지 않음), or 'PublicImage'로 지정하면, NCP VPC에서 제공하는 Public Image를 사용하여 VM을 생성할 수 있음. + - VM 생성시 ImageType을 'MyImage'로 지정하면, MyImage 기능으로 VM에 대해 snapshot을 하여 VM의 RootDisk와 DataDisk들을 image로 생성하여 만든 image를 사용하여 VM을 생성할 수 있음. + - MyImage를 이용하여 VM을 생성한 경우, snapshot 대상이었던 VM의 모든 disk가 그대로 신규 VM의 disk로 생성됨. + + ​O NCP VPC driver를 이용해 VM 생성시 Root disk에 대해 다음 사항을 참고 + - VM 생성시 option으로 RootDiskSize 및 RootDiskType 지정은 지원하지 않음. + - NCP VPC는 고정된 disk size로서, Linux 계열은 50GB, Windows 계열은 100GB를 지원함. + - Disk type으로는 HDD와 SDD를 지원하는데, VMSpec type에따라 지원하는 type이 다르니 VMSpec 선정시 disk type 확인이 필요함. + + O NCP VPC driver를 이용해 Root disk 외의 추가 Disk Volume(Block Storage) 생성시 다음 사항을 참고 + - (주의-1) NCP VPC에서 추가로 disk를 생성하기 위해서는 해당 region에 최소 하나의 VM이 생성되어있어야함.(Suspended or Running 상태의 VM) + - (주의-2) 추가로 생성된 disk를 특정 VM에 data disk로 attach 한 후에 다음 사항을 주의 + - Data disk가 attach된 그 VM을 바로 삭제할 수 없고, 그 disk를 detach 한 후에 VM을 삭제할 수 있음. + - 그 data disk를 삭제할 경우에도, VM에 attach된 상태에서는 삭제할 수 없고 detach 한 후에 삭제할 수 있음. + - Disk Voulme 생성시 option으로 DiskType과 DiskSize를 다음과 같이 지정할 수 있음. + - DiskType : 'default', 'SSD' or 'HDD' ('default'로 지정하면 'SSD'로 생성됨.) + - DiskSize : 'default' or 10~2000(GB)의 범위로 숫자만 기입. ('default'로 지정하면 10GB가 생성됨.) + + O NCP VPC driver를 이용해 LoadBalancer 생성시 다음 사항을 참고('Network' Type LoadBalancer 기준임) + - (주의) NLB 생성을 위해서는 타 CSP와 다르게 LB 전용(LB type)의 subnet을 이용해야하므로, NLB 생성시 driver 자체에서 LB 전용 subnet 유무를 확인 후 없으면 자동으로 생성함.(해당 VPC의 마지막 LB 삭제시, 이 subnet도 자동 삭제됨) + - LB 전용 subnet의 CIDR은 driver에서 VPC CIDR 내의 'X.X.X.240/28'으로 생성되니 VPC 내에서 일반 subnet 생성시 이 CIDR 범위는 사용되지 않아야함. + - VPC, 일반 subnet, LB 전용 Subnet 생성 예 + - VPC CIDR : '10.0.0.0/16' + - 일반 subnet CIDR : '10.0.0.0/28' + - LB 전용 Subnet CIDR : '10.0.0.240/28'(Driver에서 자동 생성됨) + - LB 전용 subnet name은 'ncpvpc-subnet-for-nlb-XXXXXXXX' 과 같은 형식으로 자동 부여됨. + - NCP VPC의 경우, 'SGN'(Singapore), 'JPN'(Japan) region에서만 internet gateway를 지원하는 public용 NLB를 생성할 수 있음.('KOR'(Korea) region에서는 private용 NLB만 지원) + - 'SGN'(Singapore), 'JPN'(Japan) region에서 NLB 생성시 public IP가 지정됨. + - NLB 생성시 option으로 NLB Network Type을 다음과 같이 지정할 수 있음. + - 'default', ''(지정하지 않음), or 'PUBLIC'으로 지정하면, NCP VPC의 'PUBLIC' network type NLB가 생성됨. + - 'INTERNAL'으로 지정하면, NCP VPC의 'PRIVATE' network type NLB가 생성됨. + - NCP VPC NLB에서 지원하는 protocol은 다음과 같음. + - Listener protocol type : 'Network' Load Balancer는 TCP/UDP만 지원 + - 단, UDP protocol은 'SGN'(Singapore), 'JPN'(Japan) region에서만 이용 가능 + - VMGroup protocol type : 'Network' Load Balancer는 TCP/UDP만 지원 + - 단, UDP protocol은 'SGN'(Singapore), 'JPN'(Japan) region에서만 이용 가능 + - HealthChecker protocol type : 'Network' Load Balancer는 TCP만 지원 + - HealthChecker Iimeout 값 : LB type이 'NETWORK' 가 아닌 경우에만 유효(NLB에서는 무의미함.) + - HealthChecker Interval 값 범위 : 5 ~ 300 (seconds). '-1' 입력시, default 값 '30' (seconds) 입력됨. + - HealthChecker Threshold 값 범위 : 2 ~ 10. '-1' 입력시, default 값 '2' 입력됨. + +​ O NCP CSP 정책상, 생성되는 public IP 개수가 VM instance 수를 초과할 수 없으므로 다음 사항을 주의 + - 만약, NCP VPC console에서 수동으로 VM을 반납(termination) 할 경우에는 반드시 public IP도 반납하는것으로 체크 후 반납 필요 + - Public IP를 반납하지 않으면, NCP VPC driver를 통해 VM instance 신규 생성 요청시, driver에서 public IP를 추가 생성할때 public IP 수가 instance 개수보다 많게 되어 error를 return 하게됨. + - 단, NCP driver나 CB-Spider API를 이용해 NCP VM 반납시에는 VM 반납 후 자동으로 public IP까지 반납됨. + + O NCP 정책상, VM이 생성된 후 한번 정지시킨 상태에서 연속으로 최대 90일, 12개월 누적 180일을 초과하여 정지할 수 없으며, 해당 기간을 초과할 경우 반납(Termination)하도록 안내하고 있음. diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/connect/NcpVpcCloudConnection.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/connect/NcpVpcCloudConnection.go new file mode 100644 index 000000000..2bb486b2e --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/connect/NcpVpcCloudConnection.go @@ -0,0 +1,160 @@ +// 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.12. +// by ETRI, 2022.10. updated + +package connect + +import ( + "fmt" + "github.com/sirupsen/logrus" + "github.com/davecgh/go-spew/spew" + + 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" + + vserver "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + vpc "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vpc" + vlb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vloadbalancer" + + // ncpvpcrs "github.com/cloud-barista/ncpvpc/ncpvpc/resources" // For local testing + ncpvpcrs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources" +) + +type NcpVpcCloudConnection struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VmClient *vserver.APIClient + VpcClient *vpc.APIClient + VlbClient *vlb.APIClient +} + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC Connect") +} + +func (cloudConn *NcpVpcCloudConnection) CreateVMHandler() (irs.VMHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateVMHandler()!") + + //NOTE Just for Test!! + // cblogger.Info("cloudConn.CredentialInfo.ClientId : ") + // spew.Dump(cloudConn.CredentialInfo.ClientId) + // cblogger.Info("cloudConn.RegionInfo : ") + // spew.Dump(cloudConn.RegionInfo) + + vmHandler := ncpvpcrs.NcpVpcVMHandler{ + CredentialInfo: cloudConn.CredentialInfo, + RegionInfo: cloudConn.RegionInfo, + VMClient: cloudConn.VmClient, + } + + return &vmHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateVMSpecHandler() (irs.VMSpecHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateVMSpecHandler()!") + vmspecHandler := ncpvpcrs.NcpVpcVMSpecHandler{CredentialInfo: cloudConn.CredentialInfo, RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + + return &vmspecHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateImageHandler() (irs.ImageHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateImagehandler()!") + imageHandler := ncpvpcrs.NcpVpcImageHandler{CredentialInfo: cloudConn.CredentialInfo, RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + + return &imageHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateKeyPairHandler() (irs.KeyPairHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateKeyPairHandler()!") + keypairHandler := ncpvpcrs.NcpVpcKeyPairHandler{CredentialInfo: cloudConn.CredentialInfo, RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + + return &keypairHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateSecurityHandler() (irs.SecurityHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateSecurityHandler()!") + sgHandler := ncpvpcrs.NcpVpcSecurityHandler{CredentialInfo: cloudConn.CredentialInfo, RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + + return &sgHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateVPCHandler() (irs.VPCHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateVPCHandler()!") + vpcHandler := ncpvpcrs.NcpVpcVPCHandler{CredentialInfo: cloudConn.CredentialInfo, RegionInfo: cloudConn.RegionInfo, VPCClient: cloudConn.VpcClient} + + return &vpcHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateNLBHandler() (irs.NLBHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateNLBHandler()!") + nlbHandler := ncpvpcrs.NcpVpcNLBHandler{CredentialInfo: cloudConn.CredentialInfo, RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient, VPCClient: cloudConn.VpcClient, VLBClient: cloudConn.VlbClient} + + return &nlbHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateDiskHandler() (irs.DiskHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateDiskHandler()!") + cblogger.Info("\n### cloudConn.RegionInfo : ") + spew.Dump(cloudConn.RegionInfo) + cblogger.Info("\n") + + diskHandler := ncpvpcrs.NcpVpcDiskHandler{RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + + return &diskHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateMyImageHandler() (irs.MyImageHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateMyImageHandler()!") + myimageHandler := ncpvpcrs.NcpVpcMyImageHandler{RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + + return &myimageHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) CreateClusterHandler() (irs.ClusterHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateClusterHandler()!") + + return nil, fmt.Errorf("NCP VPC Cloud Driver does not support CreateClusterHandler yet.") +} + +func (cloudConn *NcpVpcCloudConnection) CreateAnyCallHandler() (irs.AnyCallHandler, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateAnyCallHandler()!") + + return nil, fmt.Errorf("NCP VPC Cloud Driver does not support CreateAnyCallHandler yet.") +} + +func (cloudConn *NcpVpcCloudConnection) CreateRegionZoneHandler() (irs.RegionZoneHandler, error) { + cblogger.Info("NCP Cloud Driver: called CreateRegionZoneHandler()!") + + regionZoneHandler := ncpvpcrs.NcpRegionZoneHandler{RegionInfo: cloudConn.RegionInfo, VMClient: cloudConn.VmClient} + return ®ionZoneHandler, nil +} + +func (cloudConn *NcpVpcCloudConnection) IsConnected() (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called IsConnected()!") + if cloudConn == nil { + return false, nil + } + + if cloudConn.VmClient.V2Api == nil { + return false, nil + } + + return true, nil +} + +func (cloudConn *NcpVpcCloudConnection) Close() error { + cblogger.Info("NCP VPC Cloud Driver: called Close()!") + + return nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_DiskHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_DiskHandler.go new file mode 100644 index 000000000..bfd18eb1c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_DiskHandler.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, 2022.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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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: "14812735", + } + + createReqInfo := irs.DiskInfo{ + IId: irs.IID{ + NameId: "ncpvpc-disk-05", + }, + // DiskType: "default", + DiskType: "HDD", + // DiskType: "SSD", + // DiskSize: "default", + DiskSize: "50", + } + + vmIId := irs.IID{ // To attach disk + SystemId: "13149859", + } + + newDiskSize := "160" + + 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 VPC Resource Test") + handleDisk() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_ImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_ImageHandler.go new file mode 100644 index 000000000..9b1554048 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_ImageHandler.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" + "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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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. ListImage()") + fmt.Println("2. GetImage()") + fmt.Println("3. CheckWindowsImage()") + fmt.Println("4. CreateImage() (TBD)") + fmt.Println("5. DeleteImage() (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: "SW.VSVR.OS.LNX64.UBNTU.SVR1804.B050"}, //NCP : ubuntu-18.04, Ubuntu Server 64-bit + + // NCP VPC 공공 + IId: irs.IID{NameId: "Test OS Image", SystemId: "SW.VSVR.OS.LNX64.UBNTU.SVR2004.B050"}, //NCP VPC 공공 : Ubuntu Server 20.04 (64-bit) + + // IId: irs.IID{NameId: "Test OS Image", SystemId: "SW.VSVR.OS.WND64.WND.SVR2019EN.B100"}, //NCP : Windows Server 2019 (64-bit) English Edition + } + + 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) + fmt.Println("\n") + + cblogger.Infof("전체 Image list 개수 : [%d]", 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 Check 테스트", imageReqInfo.IId.NameId) + checkResult, err := handler.CheckWindowsImage(imageReqInfo.IId) + if err != nil { + cblogger.Infof(imageReqInfo.IId.NameId, " Image Check 실패 : ", err) + } else { + cblogger.Infof("Image 생성 결과 : ", checkResult) + spew.Dump(checkResult) + } + + case 4: + cblogger.Infof("[%s] Image Check 테스트", 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 5: + // 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 VPC Resource Test") + + handleImage() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_KeyPairHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_KeyPairHandler.go new file mode 100644 index 000000000..c2f6ec3e4 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_KeyPairHandler.go @@ -0,0 +1,261 @@ +// 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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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-01" + 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 조회 결과 : ") + 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}, + } + result, err := keyPairHandler.CreateKey(keyPairReqInfo) + if err != nil { + cblogger.Infof(keyPairName, " KeyPair 생성 실패 : ", err) + } else { + cblogger.Infof("[%s] KeyPair 생성 결과 : \n", keyPairName) + 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", keyPairName) + 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 삭제 결과 : ", keyPairName) + spew.Dump(result) + } + + cblogger.Info("\nDeleteKey Test Finished") + } + } + } +} + +func main() { + cblogger.Info("NCP VPC Resource Test") + + handleKeyPair() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +//환경 설정 파일 읽기 +//환경변수 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/ncpvpc/ncpvpc/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/ncpvpc/main/Test_MyImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_MyImageHandler.go new file mode 100644 index 000000000..5dd1cc95c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_MyImageHandler.go @@ -0,0 +1,237 @@ +// 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, 2022.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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +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: "ncpvpc-ubuntuimage-01", + SystemId: "13233784", + } + + snapshotReqInfo := irs.MyImageInfo{ + IId: irs.IID{ + NameId: "ncpvpc-winimage-01", + }, + SourceVM: irs.IID{ + NameId: "ncp-vm-3", + SystemId: "14917892", + }, + } + + 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(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_NLBHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_NLBHandler.go new file mode 100644 index 000000000..0ce792975 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_NLBHandler.go @@ -0,0 +1,347 @@ +// 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, 2022.07. + +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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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 VPC Region : [%s]", config.Ncp.Region) + cblogger.Info("\n # Select Num : ") + + nlbIId := irs.IID{ + NameId: "new-lb-1", + SystemId: "13230864", + } + + nlbCreateReqInfo := irs.NLBInfo{ + IId: irs.IID{ + NameId: "new-nlb-1", + }, + VpcIID: irs.IID{ + NameId: "ncp-vpc-01", + // NameId: "ncp-vpc-01", + }, + Listener: irs.ListenerInfo{ + Protocol: "TCP", + Port: "8080", + }, + VMGroup: irs.VMGroupInfo{ + Protocol: "TCP", + Port: "8080", + VMs: &[]irs.IID{ + {NameId: "ncp-vm-1"}, + // {NameId: "ncp-vm-2"}, + // {NameId: "s18431a1837f"}, + }, + }, + HealthChecker: irs.HealthCheckerInfo{ + Protocol: "TCP", + Port: "8080", + Interval: -1, + Timeout: -1, + Threshold: -1, + }, + // HealthChecker: irs.HealthCheckerInfo{ + // Protocol: "TCP", + // Port: "8080", + // Interval: 30, + // Timeout: 5, + // Threshold: 3, + // }, + } + + updateListener := irs.ListenerInfo{ + Protocol: "TCP", + Port: "8087", + } + + updateVMGroups := irs.VMGroupInfo{ + Protocol: "TCP", + Port: "8087", + } + + addVMs := []irs.IID{ + {NameId: "ncp-vm-1"}, + // {NameId: "ncp-vm-01-ccuki71jcupot8j6d8t0"}, + // {NameId: "s18431a1837f"}, + } + + removeVMs := []irs.IID{ + {NameId: "ncp-vm-1"}, + // {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 VPC Resource Test") + + handleNLB() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_RegionZoneHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_RegionZoneHandler.go new file mode 100644 index 000000000..41795b581 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_RegionZoneHandler.go @@ -0,0 +1,244 @@ +// 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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCPVPC 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("NCPVPC Resource Test") + + handleRegionZone() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_SecurityHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_SecurityHandler.go new file mode 100644 index 000000000..0ced66af7 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_SecurityHandler.go @@ -0,0 +1,482 @@ +// 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, 2022.03. + +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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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 ]") + fmt.Println("1. List Security") + fmt.Println("2. Get Security") + fmt.Println("3. Create Security") + fmt.Println("4. Add Rules") + fmt.Println("5. Remove Rules") + fmt.Println("6. Delete Security") + fmt.Println("0. Quit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + var commandNum int + + securityName := "ncp-sg-006" + securityId := "78628" + vpcId := "19368" + + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + panic(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + return + + case 1: + result, err := handler.ListSecurity() + if err != nil { + cblogger.Infof("SecurityGroup list 조회 실패 : ", err) + } else { + cblogger.Info("SecurityGroup 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 2: + cblogger.Infof("[%s] SecurityGroup 정보 조회 테스트", securityId) + result, err := handler.GetSecurity(irs.IID{SystemId: securityId}) + if err != nil { + cblogger.Infof(securityId, " SecurityGroup 조회 실패 : ", err) + } else { + cblogger.Infof("[%s] SecurityGroup 조회 결과 : [%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{ // Security Rules 설정 + // { + // Direction: "inbound", + // IPProtocol: "tcp", + // FromPort: "20", + // ToPort: "22", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "inbound", + // IPProtocol: "tcp", + // FromPort: "80", + // ToPort: "80", + // CIDR: "172.16.0.0/16", + // }, + // { + // Direction: "inbound", + // IPProtocol: "tcp", + // FromPort: "-1", + // ToPort: "-1", + // CIDR: "172.16.0.0/16", + // }, + // { + // Direction: "inbound", + // IPProtocol: "udp", + // FromPort: "8080", + // ToPort: "8080", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "inbound", + // IPProtocol: "icmp", + // FromPort: "-1", + // ToPort: "-1", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "outbound", + // IPProtocol: "tcp", + // FromPort: "443", + // ToPort: "443", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "outbound", + // IPProtocol: "tcp", + // FromPort: "8443", + // ToPort: "9999", + // CIDR: "172.16.0.0/16", + // }, + + // All traffic 허용 rule + { + Direction: "inbound", + IPProtocol: "ALL", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + { + Direction: "outbound", + IPProtocol: "ALL", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + }, + } + + result, err := handler.CreateSecurity(securityReqInfo) + if err != nil { + cblogger.Infof(securityName, " Security 생성 실패 : ", err) + } else { + cblogger.Infof("[%s] Security 생성 결과 : [%v]", securityName, result) + spew.Dump(result) + } + cblogger.Info("\nCreateSecurity Test Finished") + + case 4: + cblogger.Infof("[%s] Security Rule 추가 테스트", securityName) + + securityRuleReqInfo := &[]irs.SecurityRuleInfo{ + { + Direction: "inbound", + IPProtocol: "tcp", + FromPort: "20", + ToPort: "22", + CIDR: "0.0.0.0/0", + }, + { + Direction: "inbound", + IPProtocol: "tcp", + FromPort: "80", + ToPort: "80", + CIDR: "172.16.0.0/16", + }, + { + Direction: "inbound", + IPProtocol: "tcp", + FromPort: "-1", + ToPort: "-1", + CIDR: "172.16.0.0/16", + }, + { + Direction: "inbound", + IPProtocol: "udp", + FromPort: "8080", + ToPort: "8080", + CIDR: "0.0.0.0/0", + }, + { + Direction: "inbound", + IPProtocol: "icmp", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + { + Direction: "outbound", + IPProtocol: "tcp", + FromPort: "443", + ToPort: "443", + CIDR: "0.0.0.0/0", + }, + { + Direction: "outbound", + IPProtocol: "tcp", + FromPort: "8443", + ToPort: "9999", + CIDR: "172.16.0.0/16", + }, + + + // // All traffic 허용 rule + { + Direction: "inbound", + IPProtocol: "ALL", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + { + Direction: "outbound", + IPProtocol: "ALL", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + } + + result, err := handler.AddRules(irs.IID{SystemId: securityId}, securityRuleReqInfo) + if err != nil { + cblogger.Infof(securityName, " Security Rule Add failed : ", err) + } else { + cblogger.Infof("[%s] Security Rule 추가 결과 : [%v]", securityName, result) + spew.Dump(result) + } + cblogger.Info("\nAddRules Test Finished") + + case 5: + cblogger.Infof("[%s] Security Rule 제거 테스트", securityName) + + securityRuleReqInfo := &[]irs.SecurityRuleInfo{ + // { + + // Direction: "inbound", + // IPProtocol: "tcp", + // FromPort: "20", + // ToPort: "22", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "inbound", + // IPProtocol: "tcp", + // FromPort: "80", + // ToPort: "80", + // CIDR: "172.16.0.0/16", + // }, + // { + // Direction: "inbound", + // IPProtocol: "tcp", + // FromPort: "-1", + // ToPort: "-1", + // CIDR: "172.16.0.0/16", + // }, + // { + // Direction: "inbound", + // IPProtocol: "udp", + // FromPort: "8080", + // ToPort: "8080", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "inbound", + // IPProtocol: "icmp", + // FromPort: "-1", + // ToPort: "-1", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "outbound", + // IPProtocol: "tcp", + // FromPort: "443", + // ToPort: "443", + // CIDR: "0.0.0.0/0", + // }, + // { + // Direction: "outbound", + // IPProtocol: "tcp", + // FromPort: "8443", + // ToPort: "9999", + // CIDR: "172.16.0.0/16", + // }, + + + // // All traffic 허용 rule + { + Direction: "inbound", + IPProtocol: "ALL", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + { + Direction: "outbound", + IPProtocol: "ALL", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + } + + result, err := handler.RemoveRules(irs.IID{SystemId: securityId}, securityRuleReqInfo) + if err != nil { + cblogger.Infof(securityName, " Security Rule Remove failed : ", err) + } else { + cblogger.Infof("[%s] Security Rule 제거 결과 : [%v]", securityName, result) + spew.Dump(result) + } + cblogger.Info("\nRemoveRules Test Finished") + + case 6: + 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) + } + cblogger.Info("\nDeleteSecurity Test Finished") + } + } + } +} + +func testErr() error { + return errors.New("") +} + +func main() { + cblogger.Info("NCP VPC Resource Test") + + handleSecurity() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMHandler.go new file mode 100644 index 000000000..be11fa013 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMHandler.go @@ -0,0 +1,364 @@ +// 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 ( + "errors" + "fmt" + "os" + "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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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: "18308242"} + + 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{ + // # NCP에서는 VM instance 이름에 대문자 허용 안되므로, VMHandler 내부에서 소문자로 변환되어 반영됨. + IId: irs.IID{NameId: "MyImage-VM-1"}, + + // ImageType: "PublicImage", // "", "default", "PublicImage" or "MyImage" + ImageType: "MyImage", // "", "default", "PublicImage" or "MyImage" + + // # NCP VPC infra service와 Classic 2세대 service는 ImageID, VMSpecName 체계가 다름. + // ImageIID: irs.IID{NameId: "ubuntu-18.04", SystemId: "SW.VSVR.OS.LNX64.UBNTU.SVR1804.B050"}, + // ImageIID: irs.IID{NameId: "Windows-Server-2016(64bit)", SystemId: "SW.VSVR.OS.WND64.WND.SVR2016EN.B100"}, + // ImageIID: irs.IID{NameId: "CentOS 7.8 (64-bit)", SystemId: "SW.VSVR.OS.LNX64.CNTOS.0708.B050"}, + // ImageIID: irs.IID{NameId: "Rocky Linux 8.6", SystemId: "SW.VSVR.OS.LNX64.ROCKY.0806.B050"}, + + // # For MyImage Test + ImageIID: irs.IID{NameId: "ubuntu-18.04", SystemId: "18306970"}, + // ImageIID: irs.IID{NameId: "ubuntu-18.04", SystemId: "13233382"}, // In case of "MyImage" + // ImageIID: irs.IID{NameId: "ncpvpc-winimage-02", SystemId: "14917995"}, // In case of "MyImage" + + // ### Caution!! ### : NCP Classic 2세대 infra가 아닌 NCP VPC infra service에서는 VPC, subnet 지정 필수!! + VpcIID: irs.IID{SystemId: "41565"}, // ncp-vpc-01 + SubnetIID: irs.IID{SystemId: "92493"}, // ncp-subnet-01 + // VpcIID: irs.IID{SystemId: "1363"}, + // SubnetIID: irs.IID{SystemId: "3325"}, + + // VMSpecName: "SVR.VSVR.HICPU.C004.M008.NET.SSD.B050.G002", // For Image : "SW.VSVR.OS.LNX64.UBNTU.SVR1804.B050" + // VMSpecName: "SVR.VSVR.HICPU.C002.M004.NET.SSD.B100.G002", // For Image : "SW.VSVR.OS.WND64.WND.SVR2016EN.B100" + // VMSpecName: "SVR.VSVR.HICPU.C004.M008.NET.SSD.B050.G002", // For Image : "SW.VSVR.OS.LNX64.CNTOS.0708.B050" + VMSpecName: "SVR.VSVR.HICPU.C004.M008.NET.SSD.B050.G002", // For Image : "SW.VSVR.OS.LNX64.ROCKY.0806.B050" + + KeyPairIID: irs.IID{SystemId: "ns01-ncpv-cij7lb1jcupork04fnr0"}, // Caution : Not NameId!! + + // ### Caution!! ### : AccessControlGroup은 NCP console상의 VPC 메뉴의 'Network ACL'이 아닌 Server 메뉴의 'ACG'에 해당됨. + // SecurityGroupIIDs: []irs.IID{{SystemId: "44518"}}, // ncp-sg-02 + SecurityGroupIIDs: []irs.IID{{SystemId: "114954"}}, // ncp-vpc-01-default-acg + // SecurityGroupIIDs: []irs.IID{{SystemId: "3486"}}, + + VMUserPasswd: "cdcdcd353535**", + } + + vmInfo, err := vmHandler.StartVM(vmReqInfo) + if err != nil { + //panic(err) + cblogger.Error(err) + } else { + cblogger.Info("VM 생성 완료!!", vmInfo) + spew.Dump(vmInfo) + } + //cblogger.Info(vm) + + cblogger.Info("\nCreateVM Test Finished") + + case 2: + vmInfo, err := vmHandler.GetVM(VmID) + if err != nil { + cblogger.Errorf("Failed Get the VM info.: [%s]", VmID) + cblogger.Error(err) + } else { + cblogger.Infof("VM info. of [%s]", VmID) + cblogger.Info(vmInfo) + 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 실행 성공") + //cblogger.Info(vmStatusInfos) + 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 목록 ================") + // cblogger.Info(vmList) + spew.Dump(vmList) + cblogger.Infof("=========== VM 목록 수 : [%d] ================", len(vmList)) + if len(vmList) > 0 { + VmID = vmList[0].IId + } + } + + cblogger.Info("\nListVM Test Finished") + + } + } + } +} + +func main() { + cblogger.Info("NCP VPC Resource Test") + + handleVM() +} + +// handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +// (예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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) + + cblogger.Info(connectionInfo.RegionInfo.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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMSpecHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMSpecHandler.go new file mode 100644 index 000000000..b872caad6 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VMSpecHandler.go @@ -0,0 +1,256 @@ +// 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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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 := "SVR.VSVR.HICPU.C016.M032.NET.SSD.B050.G002" //When Region is 'KR'. vCPU 16EA, Memory 32GB, [SSD]Disk 50GB", Image ID : SW.VSVR.OS.LNX64.UBNTU.SVR1804.B050 + + 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 count for [%s] : [%d]", reqRegion, 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) + } + + 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) + } + + 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("\nGetOrgVMSpec() Test Finished") + + case 0: + fmt.Println("Exit") + return + } + } + } +} + +func main() { + cblogger.Info("NCP VPC Resource Test") + + handleVMSpec() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VPCHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VPCHandler.go new file mode 100644 index 000000000..531e73505 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/Test_VPCHandler.go @@ -0,0 +1,304 @@ +// 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/sirupsen/logrus" + "gopkg.in/yaml.v3" + "github.com/davecgh/go-spew/spew" + + 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" + + // ncpvpcdrv "github.com/cloud-barista/ncpvpc/ncpvpc" // For local test + ncpvpcdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ncpvpc" +) + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC 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. AddSubnet()") + fmt.Println("5. RemoveSubnet()") + fmt.Println("6. DeleteVPC()") + fmt.Println("0. Exit") + fmt.Println("\n Select a number above!! : ") + fmt.Println("============================================================================================") + + reqVPCName := "ncp-vpc-01" + vpcId := "647" + subnetId := "3176" + + vpcIId := irs.IID{NameId: reqVPCName, SystemId: vpcId} + subnetIId := irs.IID{SystemId: subnetId} + + cblogger.Info("reqVPCName : ", reqVPCName) + + vpcReqInfo := irs.VPCReqInfo { + IId: irs.IID {NameId: reqVPCName, SystemId: vpcId}, + IPv4_CIDR: "10.0.0.0/16", + // IPv4_CIDR: "172.16.0.0/24", + SubnetInfoList: []irs.SubnetInfo { + { + IId: irs.IID{ + NameId: "ncp-subnet-for-vm", + }, + IPv4_CIDR: "10.0.0.0/28", + // IPv4_CIDR: "172.16.0.0/28", + }, + // { + // IId: irs.IID{ + // NameId: "ncp-subnet-04", + // }, + // IPv4_CIDR: "172.16.1.0/28", + // }, + }, + } + + subnetInfo := irs.SubnetInfo { + IId: irs.IID{ + NameId: "ncp-subnet-05", + }, + IPv4_CIDR: "172.16.2.0/24", + } + + 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 AddSubnet() ...") + if result, err := handler.AddSubnet(vpcIId, subnetInfo); err != nil { + cblogger.Error(err) + cblogger.Error("Subnet 추가 실패 : ", err) + } else { + cblogger.Info("Subnet 추가 성공!!") + spew.Dump(result) + } + fmt.Println("\nAddSubnet() Test Finished") + + case 5: + fmt.Println("Start RemoveSubnet() ...") + if result, err := handler.RemoveSubnet(vpcIId, subnetIId); err != nil { + cblogger.Error(err) + cblogger.Error("Subnet 제거 실패 : ", err) + } else { + cblogger.Info("Subnet 제거 성공!!") + spew.Dump(result) + } + fmt.Println("\nRemoveSubnet() Test Finished") + + case 6: + 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 VPC Resource Test") + + handleVPC() +} + +//handlerType : resources폴더의 xxxHandler.go에서 Handler이전까지의 문자열 +//(예) ImageHandler.go -> "Image" +func getResourceHandler(handlerType string) (interface{}, error) { + var cloudDriver idrv.CloudDriver + cloudDriver = new(ncpvpcdrv.NcpVpcDriver) + + 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:"ncpvpc"` +} + +func readConfigFile() Config { + // # Set Environment Value of Project Root Path + // goPath := os.Getenv("GOPATH") + // rootPath := goPath + "/src/github.com/cloud-barista/ncp/ncp/main" + // cblogger.Debugf("Test Config file : [%]", rootPath+"/config/config.yaml") + rootPath := os.Getenv("CBSPIDER_ROOT") + configPath := rootPath + "/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml" + cblogger.Debugf("Test Config file : [%s]", configPath) + + data, err := os.ReadFile(configPath) + if err != nil { + panic(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + panic(err) + } + cblogger.Info("ConfigFile Loaded ...") + + // Just for test + cblogger.Debug(config.Ncp.NcpAccessKeyID, " ", config.Ncp.Region) + + return config +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml.sample b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml.sample new file mode 100644 index 000000000..ba8eea29a --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/config.yaml.sample @@ -0,0 +1,23 @@ +ncpvpc: + + # NCP VPC Credential Info + ncp_access_key_id: XXXXXXXXXXXXXXXXXXXXXXXXXXX + ncp_secret_key: XXXXXXXXXXXXXXXXXXXXXXXXXXX + + ### (NOte) 현재 NCP VPC는 한국, 싱가포르, 일본 region만 지원!! + region: KR + zone: KR-1 + # zone: KR-2 + + # region: SGN + # zone: SGN-4 + # zone: SGN-5 + + # region: JPN + # zone: JPN-4 + # zone: JPN-5 + + # Note!! : Supporting Regions and Zones + # region: KR, zone: KR-1 or KR-2 + # region: SGN, zone: SGN-4 or SGN-5 + # region: JPN, zone: JPN-4 or JPN-5 diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/gov-setup.env b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/gov-setup.env new file mode 100644 index 000000000..222a1a537 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/config/gov-setup.env @@ -0,0 +1,2 @@ +#!/bin/bash +export NCLOUD_API_GW="https://ncloud.apigw.gov-ntruss.com" diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/gov-cloud-setup.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/gov-cloud-setup.sh new file mode 100755 index 000000000..ddd709035 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/gov-cloud-setup.sh @@ -0,0 +1,4 @@ +source ./config/gov-setup.env + +echo "NCLOUD_API_GW : " +echo $NCLOUD_API_GW diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_disk.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_disk.sh new file mode 100755 index 000000000..d3d396c3b --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_image.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_image.sh new file mode 100755 index 000000000..aabad167c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_keypair.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_keypair.sh new file mode 100755 index 000000000..02d1639a5 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_myimage.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_myimage.sh new file mode 100755 index 000000000..91211174a --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_nlb.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_nlb.sh new file mode 100755 index 000000000..db56e1923 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_region-zone.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_region-zone.sh new file mode 100755 index 000000000..595e3b5f5 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_security.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_security.sh new file mode 100755 index 000000000..252ea90f4 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_vm.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_vm.sh new file mode 100755 index 000000000..b65b1d5af --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_vmspec.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_vmspec.sh new file mode 100755 index 000000000..17ec78feb --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/main/test_vpc.sh b/cloud-control-manager/cloud-driver/drivers/ncpvpc/main/test_vpc.sh new file mode 100755 index 000000000..a62a0061c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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/ncpvpc/resources/CommonNcpVpcFunc.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/CommonNcpVpcFunc.go new file mode 100644 index 000000000..fb3dc7755 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/CommonNcpVpcFunc.go @@ -0,0 +1,122 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VPC Connection Driver +// +// by ETRI, 2020.10. + +package resources + +import ( + "encoding/json" + "fmt" + "sync" + "time" + // "strconv" + "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 + +func InitLog() { + once.Do(func() { + // cblog is a global variable. + cblogger = cblog.GetLogger("CB-SPIDER") + calllogger = call.GetLogger("HISCALL") + }) +} + +// Convert Cloud Object to JSON String type +func ConvertJsonString(v interface{}) (string, error) { + jsonBytes, err := json.Marshal(v) + if err != nil { + newErr := fmt.Errorf("Failed to Convert Json to String. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + return "", newErr + } + 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 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.NCPVPC, apiName)) + + return call.CLOUDLOGSCHEMA{ + CloudOS: call.NCPVPC, + 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 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) +} + +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 +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/DiskHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/DiskHandler.go new file mode 100644 index 000000000..db8f8b958 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/DiskHandler.go @@ -0,0 +1,768 @@ +// 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, 2022.09. + +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/vserver" + + 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 NcpVpcDiskHandler struct { + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +// Caution : Incase of NCP VPC, there must be a created VM to create a new disk volume. +func (diskHandler *NcpVpcDiskHandler) CreateDisk(diskReqInfo irs.DiskInfo) (irs.DiskInfo, error) { + cblogger.Info("NCP VPC Driver: called CreateDisk()") + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskReqInfo.IId.NameId, "CreateDisk()") // HisCall logging + + if strings.EqualFold(diskReqInfo.IId.NameId, "") { + newErr := fmt.Errorf("Invalid Disk NameId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + + // To get created VM info. + instanceList, err := diskHandler.GetNcpVMList() + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP VPC Instacne List. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + + instanceNo := *instanceList[0].ServerInstanceNo // InstanceNo of any VM on the Zone + cblogger.Infof("# 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 Int32 + i, err := strconv.ParseInt(reqDiskSize, 10, 32) + if err != nil { + panic(err) + } + reqDiskSizeInt := int32(i) + + if reqDiskSizeInt < 10 || reqDiskSizeInt > 2000 { // Range : 10~2000(GB) + newErr := fmt.Errorf("Invalid Disk Size. Disk Size Must be between 10 and 2000(GB).") + cblogger.Error(newErr.Error()) + return irs.DiskInfo{}, newErr + } + + storageReq := vserver.CreateBlockStorageInstanceRequest{ + RegionCode: ncloud.String(diskHandler.RegionInfo.Region), + BlockStorageName: ncloud.String(diskReqInfo.IId.NameId), + BlockStorageSize: &reqDiskSizeInt, // *** Required (Not Optional) + BlockStorageDiskDetailTypeCode: ncloud.String(reqDiskType), + ServerInstanceNo: ncloud.String(instanceNo), // *** Required (Not Optional) + ZoneCode: ncloud.String(diskHandler.RegionInfo.Zone), + } + + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.CreateBlockStorageInstance(&storageReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create New Disk Volume. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Find the Created New Disk Volume Info!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } else { + cblogger.Info("Succeeded in Creating the 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 { + newErr := fmt.Errorf("Failed to Wait for the Disk Creation. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + cblogger.Infof("==> New Disk Volume Status : [%s]", curStatus) + + // Wait for Disk Attachment finished + curStatus, waitErr := diskHandler.WaitForDiskAttachment(newDiskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Wait for the Disk Attachement. [%v]", waitErr.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + cblogger.Infof("==> Disk Status : [%s]", string(curStatus)) + + // Caution!! + // Incase of NCP VPC, 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 { + newErr := fmt.Errorf("Failed to Detach the Disk Volume : [%v] ", err) + cblogger.Error(newErr.Error()) + return irs.DiskInfo{}, newErr + } else if !isDetached { + newErr := fmt.Errorf("Failed to Detach the Disk Volume!!") + cblogger.Error(newErr.Error()) + return irs.DiskInfo{}, newErr + } + + newDiskInfo, err := diskHandler.GetDisk(newDiskIID) + if err != nil { + newErr := fmt.Errorf("Failed to the Get Disk Info!! : [%v] ", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + return newDiskInfo, nil +} + +func (diskHandler *NcpVpcDiskHandler) ListDisk() ([]*irs.DiskInfo, error) { + cblogger.Info("NCP VPC Driver: called ListDisk()") + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, "ListDisk()", "ListDisk()") // HisCall logging + + storageReq := vserver.GetBlockStorageInstanceListRequest{ + RegionCode: ncloud.String(diskHandler.RegionInfo.Region), // $$$ Caution!! + } + + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.GetBlockStorageInstanceList(&storageReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get Block Storage List : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var diskInfoList []*irs.DiskInfo + if *result.TotalRows < 1 { + cblogger.Info("### Block Storage does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting Block Storage list from NCP VPC.") + for _, storage := range result.BlockStorageInstanceList { + storageInfo, err := diskHandler.MappingDiskInfo(*storage) + if err != nil { + newErr := fmt.Errorf("Failed to Map Block Storage Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + diskInfoList = append(diskInfoList, &storageInfo) + } + } + // cblogger.Infof("# DiskInfo List count : [%d]", len(diskInfoList)) + return diskInfoList, nil +} + +func (diskHandler *NcpVpcDiskHandler) GetDisk(diskIID irs.IID) (irs.DiskInfo, error) { + cblogger.Info("NCP VPC Driver: called GetDisk()") + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "GetDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + + ncpDiskInfo, err := diskHandler.GetNcpDiskInfo(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Info : [%v] ", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + + storageInfo, err := diskHandler.MappingDiskInfo(*ncpDiskInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Map the Block Storage Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + return storageInfo, nil +} + +func (diskHandler *NcpVpcDiskHandler) ChangeDiskSize(diskIID irs.IID, size string) (bool, error) { + cblogger.Info("NCP VPC Driver: called ChangeDiskSize()") + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "ChangeDiskSize()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + intSize, _ := strconv.Atoi(size) + int32Size := int32(intSize) + changeReq := vserver.ChangeBlockStorageVolumeSizeRequest { + RegionCode: ncloud.String(diskHandler.RegionInfo.Region), + BlockStorageInstanceNo: ncloud.String(diskIID.SystemId), + BlockStorageSize: &int32Size, + } + + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.ChangeBlockStorageVolumeSize(&changeReq) + if err != nil { + newErr := fmt.Errorf("Failed to Change the Block Storage Volume Size : %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 Change the Block Storage Volume Size!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Changing the Block Storage Volume Size.") + } + cblogger.Infof("\n# Chaneged Size : [%s](GB)", strconv.FormatInt(*result.BlockStorageInstanceList[0].BlockStorageSize/(1024*1024*1024), 10)) + + return true, nil +} + +func (diskHandler *NcpVpcDiskHandler) DeleteDisk(diskIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Driver: called DeleteDisk()") + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "DeleteDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Status : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + if strings.EqualFold(string(curStatus), string(irs.DiskAttached)) { + newErr := fmt.Errorf("The Block Storage is Attached to a VM. First Detach it before Deleting!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + storageNoList := []*string{ncloud.String(diskIID.SystemId),} + delReq := vserver.DeleteBlockStorageInstancesRequest { + RegionCode: ncloud.String(diskHandler.RegionInfo.Region), + BlockStorageInstanceNoList: storageNoList, + } + + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.DeleteBlockStorageInstances(&delReq) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the Block Storage : %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 Block Storage!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Deleting the Block Storage.") + } + + return true, nil +} + +func (diskHandler *NcpVpcDiskHandler) AttachDisk(diskIID irs.IID, vmIID irs.IID) (irs.DiskInfo, error) { + cblogger.Info("NCP VPC Driver: called AttachDisk()") + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "AttachDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } else if strings.EqualFold(vmIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr } + + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Status : [%v] ", err) + cblogger.Error(newErr.Error()) + return irs.DiskInfo{}, newErr + } else if strings.EqualFold(string(curStatus), string(irs.DiskAttached)) { + newErr := fmt.Errorf("Failed to Attach the Disk Volume. The Disk is already 'Attached'.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + + attachReq := vserver.AttachBlockStorageInstanceRequest{ + RegionCode: ncloud.String(diskHandler.RegionInfo.Region), + ServerInstanceNo: ncloud.String(vmIID.SystemId), + BlockStorageInstanceNo: ncloud.String(diskIID.SystemId), + } + + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.AttachBlockStorageInstance(&attachReq) + if err != nil { + newErr := fmt.Errorf("Failed to Attach the Block Storage : %v", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if !strings.EqualFold(*result.ReturnMessage, "success") { + newErr := fmt.Errorf("Failed to Attach the Block Storage!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } else { + cblogger.Info("Succeeded in Attaching the Block Storage.") + } + + // Wait for Disk Attachment finished + curStatus, waitErr := diskHandler.WaitForDiskAttachment(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Wait for the Disk Attachment. [%v]", waitErr.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + cblogger.Infof("==> Disk Status : [%s]", string(curStatus)) + + diskInfo, err := diskHandler.GetDisk(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get Disk Info!! : [%v] ", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.DiskInfo{}, newErr + } + return diskInfo, nil +} + +func (diskHandler *NcpVpcDiskHandler) DetachDisk(diskIID irs.IID, ownerVM irs.IID) (bool, error) { + cblogger.Info("NCP VPC Driver: called DetachDisk()") + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, diskIID.SystemId, "DetachDisk()") // HisCall logging + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + curStatus, err := diskHandler.GetDiskStatus(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Status : [%v] ", err) + cblogger.Error(newErr.Error()) + return false, newErr + } else if !strings.EqualFold(string(curStatus), string(irs.DiskAttached)) { + newErr := fmt.Errorf("Failed to Detach the Disk Volume. The Disk Status is Not 'Attached'.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + isBasicBlockStorage, err := diskHandler.IsBasicBlockStorage(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Disk Info. : [%v] ", err) + cblogger.Error(newErr.Error()) + return false, newErr + } else if isBasicBlockStorage { + newErr := fmt.Errorf("Failed to Detach the Disk Volume. The Disk is Basic(Bootable) Disk Volume and Attached'.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + storageNoList := []*string{ncloud.String(diskIID.SystemId),} + detachReq := vserver.DetachBlockStorageInstancesRequest{ + RegionCode: ncloud.String(diskHandler.RegionInfo.Region), + BlockStorageInstanceNoList: storageNoList, + } + + callLogStart := call.Start() + result, err := diskHandler.VMClient.V2Api.DetachBlockStorageInstances(&detachReq) + if err != nil { + newErr := fmt.Errorf("Failed to Detach the Block Storage : %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 Detach the Block Storage!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Detaching the Block Storage.") + } + + // Wait for Disk Detachment finished + curStatus, waitErr := diskHandler.WaitForDiskDetachment(diskIID) + if err != nil { + newErr := fmt.Errorf("Failed to Wait to Get Disk Info. [%v]", waitErr.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + cblogger.Infof("==> Disk Status : [%s]", string(curStatus)) + + return true, nil +} + +func (diskHandler *NcpVpcDiskHandler) GetNcpDiskInfo(diskIID irs.IID) (*vserver.BlockStorageInstance, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNCPDiskInfo()") + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + storageReq := vserver.GetBlockStorageInstanceDetailRequest{ + RegionCode: ncloud.String(diskHandler.RegionInfo.Region), + BlockStorageInstanceNo: ncloud.String(diskIID.SystemId), + } + + result, err := diskHandler.VMClient.V2Api.GetBlockStorageInstanceDetail(&storageReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Block Storage Info : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if *result.TotalRows < 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 VPC 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 *NcpVpcDiskHandler) 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 *NcpVpcDiskHandler) 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), "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 *NcpVpcDiskHandler) 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), "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 *NcpVpcDiskHandler) GetDiskStatus(diskIID irs.IID) (irs.DiskStatus, error) { + cblogger.Info("NHN Cloud Driver: called GetDiskStatus()") + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + return irs.DiskError, newErr + } + + ncpDiskInfo, 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 VPC : [%s]", *ncpDiskInfo.BlockStorageInstanceStatusName) + return ConvertDiskStatus(*ncpDiskInfo.BlockStorageInstanceStatusName), nil +} + +func (diskHandler *NcpVpcDiskHandler) MappingDiskInfo(storage vserver.BlockStorageInstance) (irs.DiskInfo, error) { + cblogger.Info("NCP VPC 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.BlockStorageDiskDetailType.Code), + } + + if strings.EqualFold(ncloud.StringValue(storage.BlockStorageInstanceStatusName), "attached") { + vmHandler := NcpVpcVMHandler{ + 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: "ZoneCode", Value: ncloud.StringValue(storage.ZoneCode)}, + {Key: "BlockStorageType", Value: ncloud.StringValue(storage.BlockStorageType.CodeName)}, + {Key: "BlockStorageDiskType", Value: ncloud.StringValue(storage.BlockStorageDiskType.CodeName)}, + {Key: "MaxIOPS", Value: strconv.FormatInt(int64(*storage.MaxIopsThroughput), 10)}, + {Key: "IsReturnProtection", Value: strconv.FormatBool(*storage.IsReturnProtection)}, + {Key: "IsEncryptedVolume", Value: strconv.FormatBool(*storage.IsEncryptedVolume)}, + } + diskInfo.KeyValueList = keyValueList + + return diskInfo, nil +} + +func ConvertDiskStatus(diskStatus string) irs.DiskStatus { + cblogger.Info("NCP VPC 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 "detaching": + resultStatus = "Detaching" + default: + resultStatus = "Unknown" + } + + return resultStatus +} + +func (diskHandler *NcpVpcDiskHandler) GetNcpVMList() ([]*vserver.ServerInstance, error) { + cblogger.Info("Ncp VPC Cloud Driver: called GetNcpVMList()") + + callLogInfo := GetCallLogScheme(diskHandler.RegionInfo.Region, call.DISK, "GetNcpVMList()", "GetNcpVMList()") + + instanceReq := vserver.GetServerInstanceListRequest{ + RegionCode: &diskHandler.RegionInfo.Region, + } + + callLogStart := call.Start() + instanceResult, err := diskHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find the VM Instance list from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *instanceResult.TotalRows < 1 { + cblogger.Info("### VM Instance does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting VM Instance list from NCP VPC") + } + + return instanceResult.ServerInstanceList, nil +} + +func (diskHandler *NcpVpcDiskHandler) IsBasicBlockStorage(diskIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called IsBasicBlockStorage()") + + if strings.EqualFold(diskIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Disk SystemId!!") + cblogger.Error(newErr.Error()) + return false, newErr + } + + ncpDiskInfo, 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(*ncpDiskInfo.BlockStorageType.Code, "BASIC") { // Ex) Basic, SVRBS, ... + return true, nil + } else { + cblogger.Infof("# BlockStorageType : [%s]", *ncpDiskInfo.BlockStorageType.CodeName) // Ex) Basic BS, Server BS, ... + return false, nil + } +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/ImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/ImageHandler.go new file mode 100644 index 000000000..5607a217c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/ImageHandler.go @@ -0,0 +1,223 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VPC Image Handler +// +// by ETRI, 2020.12. + +package resources + +import ( + // "errors" + "fmt" + "strconv" + "strings" + + "github.com/davecgh/go-spew/spew" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + 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 NcpVpcImageHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC ImageHandler") +} + +func (imageHandler *NcpVpcImageHandler) GetImage(imageIID irs.IID) (irs.ImageInfo, error) { + cblogger.Info("NCP VPC Cloud driver: called GetImage()!!") + cblogger.Infof("NCP VPC image ID(ImageProductCode) : [%s]", imageIID.SystemId) + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Zone, call.VMIMAGE, imageIID.SystemId, "GetImage()") + + if imageIID.SystemId == "" { + createErr := fmt.Errorf("Invalid Image SystemId!!") + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return irs.ImageInfo{}, createErr + } + + imageReq := vserver.GetServerImageProductListRequest { + RegionCode: ncloud.String(imageHandler.RegionInfo.Region), + ProductCode: ncloud.String(imageIID.SystemId), + } + callLogStart := call.Start() + // Image ID와 NCP VPC의 Image ProductCode를 비교해서 + 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 irs.ImageInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var imageInfo irs.ImageInfo + if *result.TotalRows < 1 { + cblogger.Info("### Image info does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting NCP VPC Image info.") + imageInfo = MappingImageInfo(*result.ProductList[0]) + } + + return imageInfo, nil +} + +func (imageHandler *NcpVpcImageHandler) ListImage() ([]*irs.ImageInfo, error) { + cblogger.Info("NCP VPC Cloud driver: called ListImage()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Zone, call.VMIMAGE, "ListImage()", "ListImage()") + + ncpVpcRegion := imageHandler.RegionInfo.Region + cblogger.Infof("imageHandler.RegionInfo.Region : [%s}", ncpVpcRegion) + + // Search NCP VPC All Region + if len(ncpVpcRegion) > 0 { + regionListReq := vserver.GetRegionListRequest{} + + regionListResult, err := imageHandler.VMClient.V2Api.GetRegionList(®ionListReq) + if err != nil { + cblogger.Error(*regionListResult.ReturnMessage) + newErr := fmt.Errorf("Failed to Get Region list!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + } + + if *regionListResult.TotalRows < 1 { + cblogger.Info("### Region info does Not Exist!!") + } else { + cblogger.Infof("Succeeded in Getting NCP VPC Region list!! : ") + } + + cblogger.Infof("# Supporting All Region (by NCP VPC) Count : [%d]", len(regionListResult.RegionList)) + cblogger.Info("\n# Supporting All Region (by NCP VPC) List : ") + spew.Dump(regionListResult.RegionList) + } + + imageReq := vserver.GetServerImageProductListRequest{ + ProductCode: nil, + RegionCode: &ncpVpcRegion, // CAUTION!! : Searching VM Image Info by RegionCode (Not 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) + + var vmImageList []*irs.ImageInfo + if *result.TotalRows < 1 { + cblogger.Info("### Image info does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting NCP VPC Image list.") + for _, image := range result.ProductList { + imageInfo := MappingImageInfo(*image) + vmImageList = append(vmImageList, &imageInfo) + } + } + + cblogger.Infof("# Supported image count : [%d]", len(vmImageList)) + return vmImageList, nil +} + +func MappingImageInfo(serverImage vserver.Product) irs.ImageInfo { + cblogger.Infof("Mapping Image Info!! ") + + imageInfo := irs.ImageInfo { + // IId: irs.IID{*serverImage.ProductName, *serverImage.ProductCode}, + // NOTE 주의 : serverImage.ProductCode -> ProductName 으로 + IId: irs.IID{ + NameId: *serverImage.ProductCode, + SystemId: *serverImage.ProductCode, + }, + GuestOS: *serverImage.ProductDescription, + } + + keyValueList := []irs.KeyValue{ + {Key: "OSName(En)", 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)}, + } + + keyValueList = append(keyValueList, irs.KeyValue{Key: "OSType", Value: *serverImage.PlatformType.Code}) + imageInfo.KeyValueList = keyValueList + + return imageInfo +} + +func (imageHandler *NcpVpcImageHandler) CreateImage(imageReqInfo irs.ImageReqInfo) (irs.ImageInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateImage()!") + + return irs.ImageInfo{}, fmt.Errorf("Does not support CreateImage() yet!!") +} + +func (imageHandler *NcpVpcImageHandler) CheckWindowsImage(imageIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called CheckWindowsImage()") + + InitLog() + callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Region, call.VMIMAGE, imageIID.SystemId, "CheckWindowsImage()") // HisCall logging + + if strings.EqualFold(imageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + isWindowsImage := false + if strings.Contains(strings.ToUpper(imageIID.SystemId), "WND") { + isWindowsImage = true + } + return isWindowsImage, nil +} + +func (imageHandler *NcpVpcImageHandler) DeleteImage(imageIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called DeleteImage()!") + + return true, fmt.Errorf("Does not support DeleteImage() yet!!") +} + +func (imageHandler *NcpVpcImageHandler) isPublicImage(imageIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called isPublicImage()") + + InitLog() + callLogInfo := GetCallLogScheme(imageHandler.RegionInfo.Region, call.VMIMAGE, imageIID.SystemId, "isPublicImage()") // HisCall logging + + if strings.EqualFold(imageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + imageInfo, err := imageHandler.GetImage(imageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Image Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + isPublicImage := false + if strings.EqualFold(imageInfo.IId.SystemId, imageIID.SystemId) { + isPublicImage = true + } + return isPublicImage, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/KeyPairHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/KeyPairHandler.go new file mode 100644 index 000000000..d39a31e0e --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/KeyPairHandler.go @@ -0,0 +1,262 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VPC KeyPair Handler +// +// by ETRI, 2020.10. + +package resources + +import ( + "fmt" + "errors" + "strings" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + // "github.com/davecgh/go-spew/spew" + + 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" + 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" +) + +type NcpVpcKeyPairHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +func (keyPairHandler *NcpVpcKeyPairHandler) ListKey() ([]*irs.KeyPairInfo, error) { + cblogger.Info("NCP VPC cloud driver: called ListKey()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, "ListKey()", "ListKey()") + + keypairReq := vserver.GetLoginKeyListRequest{ + KeyName: nil, + } + + callLogStart := call.Start() + result, err := keyPairHandler.VMClient.V2Api.GetLoginKeyList(&keypairReq) + if err != nil { + cblogger.Errorf("Failed to Get KeyPairList : %v", err) + LoggingError(callLogInfo, err) + return nil, err + } + LoggingInfo(callLogInfo, callLogStart) + + var keyPairList []*irs.KeyPairInfo + if len(result.LoginKeyList) < 1 { + cblogger.Info("### Keypair info does Not Exist!!") + } else { + for _, keyPair := range result.LoginKeyList { + keyPairInfo := MappingKeyPairInfo(keyPair) + keyPairList = append(keyPairList, &keyPairInfo) + } + } + + return keyPairList, nil +} + +func (keyPairHandler *NcpVpcKeyPairHandler) CreateKey(keyPairReqInfo irs.KeyPairReqInfo) (irs.KeyPairInfo, error) { + cblogger.Info("NCP VPC cloud driver: called CreateKey()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, keyPairReqInfo.IId.NameId, "CreateKey()") + + cblogger.Infof("KeyPairName to Create : [%s]", keyPairReqInfo.IId.NameId) + + // To Generate Hash + strList:= []string{ + keyPairHandler.CredentialInfo.ClientId, + keyPairHandler.CredentialInfo.ClientSecret, + } + + hashString, err := keycommon.GenHash(strList) + if err != nil { + cblogger.Errorf("Failed to Generate Hash String : %v", err) + LoggingError(callLogInfo, err) + return irs.KeyPairInfo{}, err + } + + keypairReq := vserver.CreateLoginKeyRequest{ + KeyName: ncloud.String(keyPairReqInfo.IId.NameId), + } + + // Creates a new keypair with the given name + callLogStart := call.Start() + result, err := keyPairHandler.VMClient.V2Api.CreateLoginKey(&keypairReq) + if err != nil { + cblogger.Errorf("Failed to Create KeyPair: %s, %v.", keyPairReqInfo.IId.NameId, err) + LoggingError(callLogInfo, err) + return irs.KeyPairInfo{}, err + } + 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 { + cblogger.Errorf("Failed to Create PublicKey from PrivateKey : %v", makePublicKeyErr) + LoggingError(callLogInfo, makePublicKeyErr) + return irs.KeyPairInfo{}, makePublicKeyErr + } + + publicKey = strings.TrimSpace(publicKey) + " " + lnxUserName + + // Save the publicKey to DB in other to use on VMHandler(Cloud-init) + addKeyErr := keycommon.AddKey("NCPVPC", hashString, keyPairReqInfo.IId.NameId, publicKey) + if addKeyErr != nil { + cblogger.Errorf("Failed to Save the PublicKey to DB : %v", addKeyErr) + LoggingError(callLogInfo, addKeyErr) + return irs.KeyPairInfo{}, addKeyErr + } + + resultKey, keyError := keyPairHandler.GetKey(keyPairReqInfo.IId) + if keyError != nil { + cblogger.Errorf("Failed to Get the KeyPair Info : %v", keyError) + LoggingError(callLogInfo, keyError) + return irs.KeyPairInfo{}, keyError + } + + // 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, // Made above + PrivateKey: *result.PrivateKey, + VMUserID: lnxUserName, + } + + return keyPairInfo, nil +} + +func (keyPairHandler *NcpVpcKeyPairHandler) GetKey(keyIID irs.IID) (irs.KeyPairInfo, error) { + cblogger.Info("NCP VPC cloud driver: called GetKey()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, keyIID.NameId, "GetKey()") + + var keyNameId string + if keyIID.SystemId == "" { + keyNameId = keyIID.NameId + } + + // NCP VPC Key does not have SystemId, so the unique NameId value is also applied to the SystemId when create it. + keypairReq := vserver.GetLoginKeyListRequest{ + KeyName: ncloud.String(keyNameId), + } + + callLogStart := call.Start() + result, err := keyPairHandler.VMClient.V2Api.GetLoginKeyList(&keypairReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find the KeyPair list from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(result.LoginKeyList) < 1 { + newErr := fmt.Errorf("Failed to Find Any KeyPair Info with the Name.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.KeyPairInfo{}, newErr + } else { + keyPairInfo := MappingKeyPairInfo(result.LoginKeyList[0]) + return keyPairInfo, nil + } + + return irs.KeyPairInfo{}, errors.New("Failed to Find KeyPair Info with the Name!!") +} + +func (keyPairHandler *NcpVpcKeyPairHandler) DeleteKey(keyIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC cloud driver: called DeleteKey()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(keyPairHandler.RegionInfo.Zone, call.VMKEYPAIR, keyIID.NameId, "DeleteKey()") + + cblogger.Infof("KeyPairName to Delete : [%s]", keyIID.NameId) + // Delete the key pair by key 'Name' + + // To Generate Hash + strList:= []string{ + keyPairHandler.CredentialInfo.ClientId, + keyPairHandler.CredentialInfo.ClientSecret, + } + hashString, err := keycommon.GenHash(strList) + if err != nil { + cblogger.Errorf("Failed to Gen Hash String : %v", err) + LoggingError(callLogInfo, err) + return false, err + } + + // 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 { + cblogger.Errorf("There isn't any KeyPair with the Name : [%s]", keyIID.SystemId) + cblogger.Error(keyError) + return false, keyError + } + + keypairDelReq := vserver.DeleteLoginKeysRequest{ + KeyNameList: []*string{ + ncloud.String(keyIID.NameId), + }, + } + + // Caution!! : In case, server.~~ + // keypairDelReq := server.DeleteLoginKeyRequest{ + // KeyName: ncloud.String(keyIID.NameId), + // } + + callLogStart := call.Start() + result, err := keyPairHandler.VMClient.V2Api.DeleteLoginKeys(&keypairDelReq) + if err != nil { + cblogger.Errorf("Failed to Delete the KeyPair : %s, %v", keyIID.NameId, err) + LoggingError(callLogInfo, err) + return false, err + } + LoggingInfo(callLogInfo, callLogStart) + + // Delete the saved publicKey from DB + delKeyErr := keycommon.DelKey("NCPVPC", hashString, keyIID.NameId) + if delKeyErr != nil { + cblogger.Errorf("Failed to Delete the Key info form DB : %v", delKeyErr) + LoggingError(callLogInfo, delKeyErr) + return false, delKeyErr + } + + cblogger.Infof("(# result.ReturnMessage : %s ", ncloud.StringValue(result.ReturnMessage)) + cblogger.Infof("Succeeded in Deleting KeyPair Info : '%s' \n", keyIID.NameId) + + return true, nil +} + +// KeyPair 정보를 추출함 +func MappingKeyPairInfo(NcpKeyPairList *vserver.LoginKey) irs.KeyPairInfo { + cblogger.Infof("*** Mapping KeyPair Info of : %s", *NcpKeyPairList.KeyName) + + // 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", + // PublicKey: *NcpKeyPairList.PublicKey, // Creates Error + 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/ncpvpc/resources/MyImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/MyImageHandler.go new file mode 100644 index 000000000..6dde0036c --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/MyImageHandler.go @@ -0,0 +1,437 @@ +// 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, 2022.11. + +package resources + +import ( + "fmt" + "strings" + "time" + // "github.com/davecgh/go-spew/spew" + + // "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + vserver "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + + 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 NcpVpcMyImageHandler struct { + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +const ( + // NCP VPC Snapshop Options : FULL | INCREMENTAL, Default : FULL + NcpDefaultSnapshotTypeCode string = "FULL" +) + +// To Take a Snapshot with VM ID (To Create My Image) +func (myImageHandler *NcpVpcMyImageHandler) SnapshotVM(snapshotReqInfo irs.MyImageInfo) (irs.MyImageInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called SnapshotVM()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, snapshotReqInfo.IId.SystemId, "SnapshotVM()") // HisCall logging + + if strings.EqualFold(snapshotReqInfo.SourceVM.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + + snapshotReq := vserver.CreateMemberServerImageInstanceRequest{ // Not CreateBlockStorageSnapshotInstanceRequest{} + RegionCode: &myImageHandler.RegionInfo.Region, + MemberServerImageName: &snapshotReqInfo.IId.NameId, + ServerInstanceNo: &snapshotReqInfo.SourceVM.SystemId, + } + + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.CreateMemberServerImageInstance(&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 *result.TotalRows < 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.MemberServerImageInstanceList[0].MemberServerImageInstanceNo} + // 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 *NcpVpcMyImageHandler) ListMyImage() ([]*irs.MyImageInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called ListMyImage()") + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, "ListMyImage()", "ListMyImage()") // HisCall logging + + imageListReq := vserver.GetMemberServerImageInstanceListRequest{ // Not GetBlockStorageSnapshotInstanceListRequest + RegionCode: &myImageHandler.RegionInfo.Region, + } + + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.GetMemberServerImageInstanceList(&imageListReq) // Caution : Not GetBlockStorageSnapshotInstanceList() + if err != nil { + newErr := fmt.Errorf("Failed to Get the Snapshot Image List from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var imageInfoList []*irs.MyImageInfo + if *result.TotalRows < 1 { + cblogger.Info("# Snapshot Image does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting the Snapshot Info List.") + for _, snapshotImage := range result.MemberServerImageInstanceList { + 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 *NcpVpcMyImageHandler) GetMyImage(myImageIID irs.IID) (irs.MyImageInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetMyImage()") + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "GetMyImage()") // HisCall logging + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } + + imageReq := vserver.GetMemberServerImageInstanceDetailRequest{ // Not GetBlockStorageSnapshotInstanceDetailRequest{} + RegionCode: &myImageHandler.RegionInfo.Region, + MemberServerImageInstanceNo: &myImageIID.SystemId, + } + + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.GetMemberServerImageInstanceDetail(&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 irs.MyImageInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Get the Snapshot Image Info.Snapshot Image does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.MyImageInfo{}, newErr + } else { + cblogger.Info("Succeeded in Getting the Snapshot Image Info.") + } + + imageInfo, err := myImageHandler.MappingMyImageInfo(result.MemberServerImageInstanceList[0]) + if err != nil { + newErr := fmt.Errorf("Failed to Map MyImage Info!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + } + return *imageInfo, nil +} + +func (myImageHandler *NcpVpcMyImageHandler) CheckWindowsImage(myImageIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called CheckWindowsImage()") + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "CheckWindowsImage()") // HisCall logging + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + myImageInfo, err := myImageHandler.GetMyImage(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 + } + + var originalImageProductCode string + // Use Key/Value info of the myImageInfo. + for _, keyInfo := range myImageInfo.KeyValueList { + if keyInfo.Key == "OriginalServerImageProductCode" { + originalImageProductCode = keyInfo.Value + break + } + } + cblogger.Infof("\n### OriginalServerImageProductCode : [%s]", originalImageProductCode) + + isWindowsImage := false + if strings.Contains(strings.ToUpper(originalImageProductCode), "WND") { + isWindowsImage = true + } + + return isWindowsImage, nil +} + +func (myImageHandler *NcpVpcMyImageHandler) DeleteMyImage(myImageIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called DeleteMyImage()") + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "DeleteMyImage()") // HisCall logging + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + snapshotImageNoList := []*string {&myImageIID.SystemId} + delReq := vserver.DeleteMemberServerImageInstancesRequest{ // Not DeleteBlockStorageSnapshotInstancesRequest{} + RegionCode: &myImageHandler.RegionInfo.Region, + MemberServerImageInstanceNoList: snapshotImageNoList, + } + + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.DeleteMemberServerImageInstances(&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 *NcpVpcMyImageHandler) 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 SystemId!!") + cblogger.Error(newErr.Error()) + return "", newErr + } + + curRetryCnt := 0 + maxRetryCnt := 500 + for { + curStatus, err := myImageHandler.GetImageStatus(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 *NcpVpcMyImageHandler) GetImageStatus(myImageIID irs.IID) (irs.MyImageStatus, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetImageStatus()") + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "GetImageStatus()") // HisCall logging + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + imageReq := vserver.GetMemberServerImageInstanceDetailRequest{ // Not GetBlockStorageSnapshotInstanceDetailRequest{} + RegionCode: &myImageHandler.RegionInfo.Region, + MemberServerImageInstanceNo: &myImageIID.SystemId, + } + + callLogStart := call.Start() + result, err := myImageHandler.VMClient.V2Api.GetMemberServerImageInstanceDetail(&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 "", newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Get the Snapshot Image Info.Snapshot Image does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } else { + cblogger.Info("Succeeded in Getting the Snapshot Image Info.") + } + + myImageStatus := ConvertImageStatus(*result.MemberServerImageInstanceList[0].MemberServerImageInstanceStatus.Code) + return myImageStatus, nil +} + +func ConvertImageStatus(myImageStatus string) irs.MyImageStatus { + cblogger.Info("NCP VPC 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 + case "CREAT" : // CREATED + resultStatus = irs.MyImageAvailable + default: + resultStatus = "Unknown" + } + + return resultStatus +} + +func (myImageHandler *NcpVpcMyImageHandler) MappingMyImageInfo(myImage *vserver.MemberServerImageInstance) (*irs.MyImageInfo, error) { + cblogger.Info("NCP VPC 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.MemberServerImageInstanceNo, + }, + SourceVM: irs.IID{SystemId: *myImage.OriginalServerInstanceNo}, + Status: ConvertImageStatus(*myImage.MemberServerImageInstanceStatus.Code), + CreatedTime: convertedTime, + } + + keyValueList := []irs.KeyValue{ + {Key: "Region", Value: myImageHandler.RegionInfo.Region}, + {Key: "OriginalServerImageProductCode", Value: *myImage.OriginalServerImageProductCode}, + {Key: "CreateDate", Value: *myImage.CreateDate}, + } + + myImageInfo.KeyValueList = keyValueList + return myImageInfo, nil +} + +func (myImageHandler *NcpVpcMyImageHandler) GetOriginImageOSPlatform(myImageIID irs.IID) (string, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetOriginImageOSPlatform()") + + InitLog() + callLogInfo := GetCallLogScheme(myImageHandler.RegionInfo.Region, call.MYIMAGE, myImageIID.SystemId, "GetOriginImageOSPlatform()") // HisCall logging + + if strings.EqualFold(myImageIID.SystemId, "") { + newErr := fmt.Errorf("Invalid SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + myImageInfo, err := myImageHandler.GetMyImage(myImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Get MyImage Info. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + var originalImageProductCode string + // Use Key/Value info of the myImageInfo. + for _, keyInfo := range myImageInfo.KeyValueList { + if keyInfo.Key == "OriginalServerImageProductCode" { + originalImageProductCode = keyInfo.Value + break + } + } + cblogger.Infof("\n### OriginalServerImageProductCode : [%s]", originalImageProductCode) + + var originImagePlatform string + if strings.Contains(strings.ToUpper(originalImageProductCode), "UBNTU") { + originImagePlatform = "UBUNTU" + } else if strings.Contains(strings.ToUpper(originalImageProductCode), "CNTOS") { + originImagePlatform = "CENTOS" + } else if strings.Contains(strings.ToUpper(originalImageProductCode), "ROCKY") { + originImagePlatform = "ROCKY" + } else if strings.Contains(strings.ToUpper(originalImageProductCode), "WND") { + originImagePlatform = "WINDOWS" + } else { + newErr := fmt.Errorf("Failed to Get OriginImageOSPlatform of the MyImage!!") + cblogger.Error(newErr.Error()) + return "", newErr + } + + return originImagePlatform, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/NLBHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/NLBHandler.go new file mode 100644 index 000000000..9740dea18 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/NLBHandler.go @@ -0,0 +1,1667 @@ +// 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, 2022.10. + +package resources + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/davecgh/go-spew/spew" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + vlb "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vloadbalancer" + vpc "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vpc" + vserver "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + + // cidr "github.com/apparentlymart/go-cidr/cidr" + + 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 NcpVpcNLBHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient + VPCClient *vpc.APIClient + VLBClient *vlb.APIClient +} + +const ( + // NCP VPC Cloud LB type code : 'APPLICATION' | 'NETWORK' | 'NETWORK_PROXY' + NcpLbType string = "NETWORK" + + // NCP VPC Cloud NLB network type code : 'PUBLIC' | 'PRIVATE' (Default: 'PUBLIC') + NcpPublicNlBType string = "PUBLIC" + NcpInternalNlBType string = "PRIVATE" + + // NCP LB performance(throughput) type code : 'SMALL' | 'MEDIUM' | 'LARGE' (Default: 'SMALL') + // You can only select 'SMALL' if the LB type is 'NETWORK' and the LB network type is 'PRIVATE'. + DefaultThroughputType string = "SMALL" + + // NCP VPC Cloud default value for Listener and Health Monitor + DefaultConnectionLimit int32 = 60 // Min : 1, Max : 3600 sec(Dedicated LB : 1 ~ 480000). Default : 60 sec + DefaultHealthCheckerInterval int32 = 30 // Min: 5, Max: 300 (seconds). Default: 30 seconds + DefaultHealthCheckerThreshold int32 = 2 // Min: 2, Max: 10. Default: 2 + + LbTypeSubnetDefaultCidr string = ".240/28" + LbTypeSubnetDefaultName string = "ncpvpc-subnet-for-nlb" +) + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC NLBHandler") +} + +// Note : Cloud-Barista supports only this case => [ LB : Listener : VMGroup : Health Checker = 1 : 1 : 1 : 1 ] +// ------ NLB Management +func (nlbHandler *NcpVpcNLBHandler) CreateNLB(nlbReqInfo irs.NLBInfo) (createNLB irs.NLBInfo, newErr error) { + cblogger.Info("NPC VPC Cloud Driver: called CreateNLB()") + + InitLog() // Caution!! + 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 + } + + // Note!! : NCP VPC LB type code : 'APPLICATION' | 'NETWORK' | 'NETWORK_PROXY' + lbType := NcpLbType + + // Note!! : Only valid if NcpLbType is Not a 'NETWORK' type. + // Min : 1, Max : 3600 sec(Dedicated LB : 1 ~ 480000). Default : 60 sec + timeOut := int32(nlbReqInfo.HealthChecker.Timeout) + if timeOut == -1 { + timeOut = DefaultConnectionLimit + } + if timeOut < 1 || timeOut > 3600 { + return irs.NLBInfo{}, fmt.Errorf("Invalid Timeout value. Must be a number between 1 and 3600.") // According to the NCP VPC API document. + } + + // Note!! : NCP VPC LB network type code : 'PUBLIC' | 'PRIVATE' (Default: 'PUBLIC') + 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 + } + + // LB performance(throughput) type code : 'SMALL' | 'MEDIUM' | 'LARGE' (Default: 'SMALL') + // You can only select 'SMALL' if the LB type is 'NETWORK' and the LB network type is 'PRIVATE'. + throughputType := DefaultThroughputType + + ncpVPCInfo, err := nlbHandler.GetNcpVpcInfoWithName(nlbReqInfo.VpcIID.NameId) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NPC VPC Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + cblogger.Infof("\n### ncpVPCInfo.VpcNo : [%s]", *ncpVPCInfo.VpcNo) + + // Caution!! : ### Need a Subnet for 'LB Only'('LB Type' Subnet) + lbTypeSubnetId, err := nlbHandler.GetSubnetIdForNlbOnly(*ncpVPCInfo.VpcNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get the SubnetId of LB Type subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + + cblogger.Infof("\n### ncpVPCInfo.Ipv4CidrBlock : [%s]", *ncpVPCInfo.Ipv4CidrBlock) + // VPC IP address ranges : /16~/28 in private IP range (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) + cidrBlock := strings.Split(*ncpVPCInfo.Ipv4CidrBlock, ".") + cidrForNlbSubnet := cidrBlock[0] + "." + cidrBlock[1] + "." + cidrBlock[2] + LbTypeSubnetDefaultCidr + // Ex) In case, VpcCIDR : "10.0.0.0/16", + // Subnet for VM : "10.0.0.0/28" + // LB Type Subnet : "10.0.0.240/28" + + // ### In case, there is No Subnet for 'LB Only'('LB Type' subnet), Create the 'LB Type' subnet. + if strings.EqualFold(lbTypeSubnetId, "") { + cblogger.Info("\n# There is No Subnet for 'LB Only'('LB Type' Subnet), so it will be Created.") + // NCP VPC Subnet Name Max length : 30 + // LbTypeSubnetDefaultName : "ncpvpc-subnet-for-nlb" => length : 21 + lbTypeSubnetName := LbTypeSubnetDefaultName + "-" + randSeq(8) + cblogger.Infof("\n### Subnet Name for LB Type subnet : [%s]", lbTypeSubnetName) + + subnetReqInfo := irs.SubnetInfo{ + IId: irs.IID{ + NameId: lbTypeSubnetName, + }, + IPv4_CIDR: cidrForNlbSubnet, + } + // Note : Create a 'LOADB' type of subnet ('LB Type' subnet for LB Only) + ncpNlbSubnetInfo, err := nlbHandler.CreatNcpSubnetForNlbOnly(irs.IID{SystemId: *ncpVPCInfo.VpcNo}, subnetReqInfo) // Waitting time Included + if err != nil { + newErr := fmt.Errorf("Failed to Create the 'LB Type' Subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + cblogger.Infof("'LB type' Subnet ID : [%s]", *ncpNlbSubnetInfo.SubnetNo) + lbTypeSubnetId = *ncpNlbSubnetInfo.SubnetNo + } + + // To Get Subnet No list + subnetNoList := []*string{ncloud.String(lbTypeSubnetId)} + cblogger.Infof("\n### ID list of 'LB Type' Subnet : ") + spew.Dump(subnetNoList) + + // Note!! : SubnetNoList[] : Range constraints: Minimum range of 1. Maximum range of 2. + if len(subnetNoList) < 1 || len(subnetNoList) > 2 { + newErr := fmt.Errorf("SubnetNoList range constraints : Min. range of 1. Max. range of 2.") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + + lbReq := vlb.CreateLoadBalancerInstanceRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + IdleTimeout: &timeOut, + LoadBalancerNetworkTypeCode: &lbNetType, + LoadBalancerTypeCode: &lbType, // *** Required (Not Optional) + LoadBalancerName: &nlbReqInfo.IId.NameId, + ThroughputTypeCode: &throughputType, + VpcNo: ncpVPCInfo.VpcNo, // *** Required (Not Optional) + SubnetNoList: subnetNoList, // *** Required (Not Optional) + } + + // ### LoadBalancerSubnetList > PublicIpInstanceNo + // Caution!! : About Public IP instance number + // It's only valid when loadBalancerNetworkTypeCode is 'PUBLIC'. + // It can only be used in the 'SGN'(Singapore) and 'JPN'(Japan)region. + // Default: A new public IP is created and assigned. + + // vserver.~ + // createPublicIpInstance() + // disassociatePublicIpFromServerInstance() + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.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 *result.TotalRows < 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 'provisioningStatus' is "Running" + 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 + } + + ncpVMGroupInfo, err := nlbHandler.CreateVMGroup(*ncpVPCInfo.VpcNo, nlbReqInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Create the VMGroup. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + cblogger.Infof("# VMGroupNo : [%s]", *ncpVMGroupInfo.TargetGroupNo) + + cblogger.Info("\n\n#### Waiting for Provisioning the New VMGroup!!") + time.Sleep(20 * time.Second) + + ncpListenerInfo, err := nlbHandler.CreateListener(newNlbIID.SystemId, nlbReqInfo, *ncpVMGroupInfo.TargetGroupNo) + if err != nil { + newErr := fmt.Errorf("Failed to Create the Listener. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.NLBInfo{}, newErr + } + cblogger.Infof("# LoadBalancerListenerNo : [%s]", *ncpListenerInfo.LoadBalancerListenerNo) + + cblogger.Info("\n\n#### Waiting for Changing the NLB Settings!!") + _, err = nlbHandler.WaitToGetNlbInfo(newNlbIID) // 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 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 *NcpVpcNLBHandler) ListNLB() ([]*irs.NLBInfo, error) { + cblogger.Info("NPC VPC Cloud Driver: called ListNLB()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", "ListNLB()", "ListNLB()") + + lbReq := vlb.GetLoadBalancerInstanceListRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, // CAUTION!! : Searching NLB Info by RegionCode (Not RegionNo) + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.GetLoadBalancerInstanceList(&lbReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find NLB list from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var nlbInfoList []*irs.NLBInfo + if *result.TotalRows < 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 *NcpVpcNLBHandler) GetNLB(nlbIID irs.IID) (irs.NLBInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNLB()") + + InitLog() // Caution!! + 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 VPC : [%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 *NcpVpcNLBHandler) DeleteNLB(nlbIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called DeleteNLB()") + + InitLog() // Caution!! + 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 := vlb.DeleteLoadBalancerInstancesRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + LoadBalancerInstanceNoList: lbNoList, + // ReturnPublicIpTogether: // It can only be used in the SGN(Singapore) and JPN(Japan) region. Default: 'true' + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.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. + } + + // Cleanup the rest resources(VMGroup, LB Type subnet) of the NLB + _, cleanErr := nlbHandler.CleanUpNLB(result.LoadBalancerInstanceList[0].VpcNo) + if cleanErr != nil { + newErr := fmt.Errorf("Failed to Cleanup the rest resources of the NLB with the VPC ID. [%v]", cleanErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + return true, nil +} + +func (nlbHandler *NcpVpcNLBHandler) AddVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (irs.VMGroupInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called AddVMs()") + + InitLog() // Caution!! + 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 + } + + nlbInfo, 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 + } + + vmHandler := NcpVpcVMHandler{ + 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)) // ncloud.String func(v string) *string + } + } 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 + } + + addReq := vlb.AddTargetRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + TargetGroupNo: &nlbInfo.VMGroup.CspID, + TargetNoList: newVmIdList, + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.AddTarget(&addReq) + 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 *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Add Any VM to the Target Group!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } else { + cblogger.Info("Succeeded in Adding New VM to the Target Group.") + } + + 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 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 *NcpVpcNLBHandler) RemoveVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called RemoveVMs()") + + InitLog() // Caution!! + 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 + } + + nlbInfo, 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 false, newErr + } + + // if len(*nlbInfo.VMGroup.VMs) < 1 { + // // newErr := fmt.Errorf("The NLB does Not have any VM Member!!") + // // cblogger.Error(newErr.Error()) + // // LoggingError(callLogInfo, newErr) + // // return false, newErr + // } else { + // } + + vmHandler := NcpVpcVMHandler{ + 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 VMGroup!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + removeReq := vlb.RemoveTargetRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + TargetGroupNo: &nlbInfo.VMGroup.CspID, + TargetNoList: vmIdList, + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.RemoveTarget(&removeReq) + 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 VMGroup!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Removing the VM from the VMGroup!!") + } + + 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 *NcpVpcNLBHandler) GetVMGroupHealthInfo(nlbIID irs.IID) (irs.HealthInfo, error) { + cblogger.Info("NCP VPC 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 + } + + nlbInfo, 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.HealthInfo{}, newErr + } + + vmMemberList, err := nlbHandler.GetNcpTargetVMList(nlbInfo.VMGroup.CspID) + if err != nil { + newErr := fmt.Errorf("Failed to Get VM Member list. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + return irs.HealthInfo{}, newErr + } + + var vmGroupHealthInfo irs.HealthInfo + if len(vmMemberList) > 0 { + var allVMs []irs.IID + var healthVMs []irs.IID + var unHealthVMs []irs.IID + + vmHandler := NcpVpcVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + + for _, member := range vmMemberList { + vm, err := vmHandler.GetNcpVMInfo(*member.TargetNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP VM Info with Target No. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.HealthInfo{}, newErr + } + + allVMs = append(allVMs, irs.IID{NameId: *vm.ServerName, SystemId: *vm.ServerInstanceNo}) // Caution : Not 'VM Member ID' but 'VM System ID' + + // HealthCheckStatus : UP(Health UP), DOWN(Health DOWN), UNUSED(Health UNUSED) + if strings.EqualFold(*member.HealthCheckStatus.Code, "UP") { + cblogger.Infof("\n### [%s] is Healthy VM.", "") + healthVMs = append(healthVMs, irs.IID{NameId: *vm.ServerName, SystemId: *vm.ServerInstanceNo}) + } else { + cblogger.Infof("\n### [%s] is Unhealthy VM.", "") + unHealthVMs = append(unHealthVMs, irs.IID{NameId: *vm.ServerName, SystemId: *vm.ServerInstanceNo}) // In case of "INACTIVE", ... + } + } + + vmGroupHealthInfo = irs.HealthInfo{ + AllVMs: &allVMs, + HealthyVMs: &healthVMs, + UnHealthyVMs: &unHealthVMs, + } + return vmGroupHealthInfo, nil + } else { + return irs.HealthInfo{}, nil + } +} + +func (nlbHandler *NcpVpcNLBHandler) CreateVMGroup(vpcId string, nlbReqInfo irs.NLBInfo) (*vlb.TargetGroup, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateVMGroup()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", "CreateVMGroup()", "CreateVMGroup()") + + // REST API and Resource Constraints Ref : + // https://api.ncloud-docs.com/docs/en/networking-vloadbalancer-targetgroup-createtargetgroup + + if strings.EqualFold(vpcId, "") { + newErr := fmt.Errorf("Invalid VPC ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + vmGroupPort, err := strconv.Atoi(nlbReqInfo.VMGroup.Port) + if err != nil { + newErr := fmt.Errorf("Invalid VMGroup Port. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + if vmGroupPort < 1 || vmGroupPort > 65535 { + newErr := fmt.Errorf("Invalid VMGroup Port.(Must be between 1 and 65535)") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + int32vmGroupPort := int32(vmGroupPort) + + // # The available protocol types for VM Group of NCP LB + // Network Load Balancer : TCP / UDP + // Network Proxy Load Balancer : PROXY_TCP + // Application Load Balancer : HTTP / HTTPS + // # Caution!! : The UDP protocol can only be used in the SGN(Singapore) and JPN(Japan) region. + vmGroupProtocol := strings.ToUpper(nlbReqInfo.VMGroup.Protocol) + switch vmGroupProtocol { + case "TCP", "UDP": + cblogger.Infof("\n# VMGroup Protocol : [%s]", vmGroupProtocol) + default: + newErr := fmt.Errorf("Invalid VMGroup Protocol Type. NCP VPC 'Network' Type LB VMGroup supports only TCP or UDP protocol!!") // According to the NCP VPC API document + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + healthCheckPort, err := strconv.Atoi(nlbReqInfo.HealthChecker.Port) + if err != nil { + newErr := fmt.Errorf("Invalid HealthChecker Port. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + if healthCheckPort < 1 || healthCheckPort > 65535 { + newErr := fmt.Errorf("Invalid HealthChecker Port.(Must be between 1 and 65535)") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + int32healthCheckPort := int32(healthCheckPort) + + // # The selectable health check protocol type is limited, depending on the VM Group protocol type. + // TCP / PROXY_TCP : TCP + // HTTP / HTTPS : HTTP / HTTPS + healthCheckProtocol := strings.ToUpper(nlbReqInfo.HealthChecker.Protocol) + if strings.EqualFold(vmGroupProtocol, "TCP") || strings.EqualFold(vmGroupProtocol, "PROXY_TCP") { + if strings.EqualFold(healthCheckProtocol, "TCP") { + cblogger.Infof("\n# HealthChecker Protocol : [%s]", healthCheckProtocol) + } else { + newErr := fmt.Errorf("Invalid HealthChecker Protocol Type!! (Must be 'TCP', when VMGroup Protocol is 'TCP' or 'PROXY_TCP' for NCP VPC Cloud.)") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + } + if strings.EqualFold(vmGroupProtocol, "HTTP") || strings.EqualFold(vmGroupProtocol, "HTTPS") { + if strings.EqualFold(healthCheckProtocol, "HTTP") || strings.EqualFold(healthCheckProtocol, "HTTPS") { + cblogger.Infof("\n# HealthChecker Protocol : [%s]", healthCheckProtocol) + } else { + newErr := fmt.Errorf("Invalid HealthChecker Protocol Type!! (Must be 'HTTP' or 'HTTPS', when VMGroup Protocol is 'HTTP' or 'HTTPS' for NCP VPC Cloud.)") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + } + + // Note!! : Range constraints: Min: 5, Max: 300 (seconds), Default: 30 seconds + healthCheckCycle := int32(nlbReqInfo.HealthChecker.Interval) + if healthCheckCycle == -1 { + healthCheckCycle = DefaultHealthCheckerInterval + } + if healthCheckCycle < 5 || healthCheckCycle > 300 { + return nil, fmt.Errorf("Invalid HealthChecker Interval value. Must be a number between 5 and 300 seconds.") // According to the NCP VPC API document. + } + + // Note!! : Range constraints: Min: 2, Max: 10, Default: 2 + healthCheckThreshold := int32(nlbReqInfo.HealthChecker.Threshold) + if healthCheckThreshold == -1 { + healthCheckThreshold = DefaultHealthCheckerThreshold + } + if healthCheckThreshold < 2 || healthCheckThreshold > 10 { + return nil, fmt.Errorf("Invalid HealthChecker Threshold value. Must be a number between 2 and 10.") // According to the NCP VPC API document. + } + + // To get TargetNoList + vmHandler := NcpVpcVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + + var targetNoList []*string + if len(*nlbReqInfo.VMGroup.VMs) > 0 { + for _, vmIID := range *nlbReqInfo.VMGroup.VMs { + 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 nil, newErr + } + targetNoList = append(targetNoList, ncloud.String(vmId)) // ncloud.String func(v string) *string + } + } + + // Note : TargetGroupProtocolTypeCode + // Network Load Balancer : 'TCP' / 'UDP' + // Network Proxy Load Balancer : 'PROXY_TCP' + // Application Load Balancer : 'HTTP' / 'HTTPS' + // ### The 'UDP' protocol can only be used in the SGN(Singapore) and JPN(Japan) region. + targetGroupReq := vlb.CreateTargetGroupRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + TargetGroupPort: &int32vmGroupPort, // Caution!! : Range constraints: Min: 1, Max: 65534 + TargetGroupProtocolTypeCode: &vmGroupProtocol, // *** Required (Not Optional) + HealthCheckCycle: &healthCheckCycle, // Caution!! : Range constraints: Min: 5, Max: 300 (seconds), Default: 30 seconds + HealthCheckPort: &int32healthCheckPort, + HealthCheckProtocolTypeCode: &healthCheckProtocol, // *** Required (Not Optional) + HealthCheckUpThreshold: &healthCheckThreshold, // Caution!! : Range constraints: Min: 2, Max: 10, Default: 2 + TargetNoList: targetNoList, + VpcNo: &vpcId, // *** Required (Not Optional) + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.CreateTargetGroup(&targetGroupReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create New TargetGroup : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create New TargetGroup. TargetGroup does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Info("Succeeded in Creating New TargetGroup.") + } + + return result.TargetGroupList[0], nil +} + +func (nlbHandler *NcpVpcNLBHandler) DeleteVMGroup(vmGroupId string) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called DeleteNLB()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", vmGroupId, "DeleteNcpVMGroup()") + + if strings.EqualFold(vmGroupId, "") { + newErr := fmt.Errorf("Invalid VMGroup ID!!") + cblogger.Error(newErr.Error()) + return false, newErr + } + + vmGroupNoList := []*string{ncloud.String(vmGroupId)} + vmGroupReq := vlb.DeleteTargetGroupsRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + TargetGroupNoList: vmGroupNoList, + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.DeleteTargetGroups(&vmGroupReq) + if err != nil { + newErr := fmt.Errorf("Failed to Delete 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 Delete the VMGroup!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } else { + cblogger.Info("Succeeded in Deleting the VMGroup.") + } + + return true, nil +} + +func (nlbHandler *NcpVpcNLBHandler) CreateListener(nlbId string, nlbReqInfo irs.NLBInfo, vmGroupNo string) (*vlb.LoadBalancerListener, error) { + cblogger.Info("NHN Cloud Driver: called CreateListener()") + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", nlbReqInfo.IId.NameId, "CreateListener()") + + if strings.EqualFold(nlbId, "") { + newErr := fmt.Errorf("Invalid NLB ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + portNum, err := strconv.Atoi(nlbReqInfo.Listener.Port) + if err != nil { + newErr := fmt.Errorf("Invalid Listener Port. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + if portNum < 1 || portNum > 65535 { + newErr := fmt.Errorf("Invalid Listener Port.(Must be between 1 and 65535)") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + listenerProtocol := strings.ToUpper(nlbReqInfo.Listener.Protocol) + switch listenerProtocol { + case "TCP", "UDP": + cblogger.Infof("\n# Listener Protocol : [%s]", listenerProtocol) + default: + newErr := fmt.Errorf("Invalid Listener Protocol Type. NCP VPC 'Network' Type LB Listener supports only TCP or UDP protocol!!") // According to the NCP VPC API document + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + int32PortNum := int32(portNum) + listenerReq := vlb.CreateLoadBalancerListenerRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + LoadBalancerInstanceNo: &nlbId, // *** Required (Not Optional) + Port: &int32PortNum, // *** Required (Not Optional) + ProtocolTypeCode: &listenerProtocol, // *** Required (Not Optional) + TargetGroupNo: &vmGroupNo, // *** Required (Not Optional) + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.CreateLoadBalancerListener(&listenerReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create New Listener : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create New Listener. Listener does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Info("Succeeded in Creating New Listener.") + } + + return result.LoadBalancerListenerList[0], nil +} + +func (nlbHandler *NcpVpcNLBHandler) GetListenerInfo(listenerId string, loadBalancerId string) (*irs.ListenerInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetListenerInfo()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", listenerId, "GetListenerInfo()") + + if strings.EqualFold(listenerId, "") { + newErr := fmt.Errorf("Invalid Listener ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + listenerReq := vlb.GetLoadBalancerListenerListRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, // *** Required (Not Optional) + LoadBalancerInstanceNo: &loadBalancerId, // *** Required (Not Optional) + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.GetLoadBalancerListenerList(&listenerReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find Listener list from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + // cblogger.Info("\n### GetLoadBalancerListenerList result") + // spew.Dump(result) + + var listenerInfo *irs.ListenerInfo + if *result.TotalRows < 1 { + cblogger.Info("### Listener does Not Exist!!") + } else { + cblogger.Info("Succeeded in Getting Listener list from NCP VPC.") + for _, listener := range result.LoadBalancerListenerList { + if strings.EqualFold(*listener.LoadBalancerListenerNo, listenerId) { + ncpListenerInfo, err := nlbHandler.MappingListenerInfo(*listener) + if err != nil { + newErr := fmt.Errorf("Failed to Map NLB Listener lnfo. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + listenerInfo = &ncpListenerInfo + break + } + } + } + return listenerInfo, nil +} + +func (nlbHandler *NcpVpcNLBHandler) GetVMGroupInfo(nlb vlb.LoadBalancerInstance) (irs.VMGroupInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetVMGroupInfo()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", *nlb.LoadBalancerInstanceNo, "GetVMGroupInfo()") + + if strings.EqualFold(*nlb.VpcNo, "") { + newErr := fmt.Errorf("Invalid LoadBalancer VPC 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 ] + ncpTargetGroupList, err := nlbHandler.GetNcpTargetGroupListWithVpcId(*nlb.VpcNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP TargetGroup List with the VPC ID. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + if len(ncpTargetGroupList) < 1 { + newErr := fmt.Errorf("Failed to Get Any NCP TargetGroup. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + + // cblogger.Info("\n### ncpTargetGroupList") + // spew.Dump(ncpTargetGroupList) + + vmGroupInfo := irs.VMGroupInfo{ + Protocol: *ncpTargetGroupList[0].TargetGroupProtocolType.Code, + Port: strconv.FormatInt(int64(*ncpTargetGroupList[0].TargetGroupPort), 10), + CspID: *ncpTargetGroupList[0].TargetGroupNo, + } + + targetVmList, err := nlbHandler.GetNcpTargetVMList(*ncpTargetGroupList[0].TargetGroupNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP VPC Target Members. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMGroupInfo{}, newErr + } + + // cblogger.Info("\n### targetList") + // spew.Dump(targetList) + + if len(targetVmList) > 0 { + vmHandler := NcpVpcVMHandler{ + RegionInfo: nlbHandler.RegionInfo, + VMClient: nlbHandler.VMClient, + } + + var vmIIds []irs.IID + for _, member := range targetVmList { + vm, err := vmHandler.GetNcpVMInfo(*member.TargetNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NCP VM Info with Target 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!!") + } + + keyValueList := []irs.KeyValue{ + {Key: "AlgorithmType", Value: *ncpTargetGroupList[0].AlgorithmType.CodeName}, + {Key: "TargetType", Value: *ncpTargetGroupList[0].TargetType.CodeName}, + } + vmGroupInfo.KeyValueList = keyValueList + + return vmGroupInfo, nil +} + +func (nlbHandler *NcpVpcNLBHandler) GetHealthCheckerInfo(nlb vlb.LoadBalancerInstance) (irs.HealthCheckerInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetHealthCheckerInfo()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", *nlb.LoadBalancerInstanceNo, "GetHealthCheckerInfo()") + + if strings.EqualFold(*nlb.VpcNo, "") { + newErr := fmt.Errorf("Invalid LoadBalancer VPC No.!!") + cblogger.Error(newErr.Error()) + return irs.HealthCheckerInfo{}, newErr + } + + // Note : Cloud-Barista supports only this case => [ LB : Listener : VM Group : Health Checker = 1 : 1 : 1 : 1 ] + ncpTargetGroupList, err := nlbHandler.GetNcpTargetGroupListWithVpcId(*nlb.VpcNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP TargetGroup List with the VPC ID. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.HealthCheckerInfo{}, newErr + } + if len(ncpTargetGroupList) < 1 { + newErr := fmt.Errorf("Failed to Get Any NCP TargetGroup. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.HealthCheckerInfo{}, newErr + } + + // cblogger.Info("\n### ncpTargetGroupList") + // spew.Dump(ncpTargetGroupList) + + healthCheckerInfo := irs.HealthCheckerInfo{ + Protocol: *ncpTargetGroupList[0].HealthCheckProtocolType.Code, + Port: strconv.FormatInt(int64(*ncpTargetGroupList[0].HealthCheckPort), 10), + Interval: int(*ncpTargetGroupList[0].HealthCheckCycle), + // Timeout: int, + Threshold: int(*ncpTargetGroupList[0].HealthCheckUpThreshold), + CspID: *ncpTargetGroupList[0].TargetGroupNo, + } + return healthCheckerInfo, nil +} + +func (nlbHandler *NcpVpcNLBHandler) GetNcpTargetGroupListWithVpcId(vpcId string) ([]*vlb.TargetGroup, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNcpTargetGroupListWithVpcId()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", vpcId, "GetNcpTargetGroupListWithVpcId()") + + if strings.EqualFold(vpcId, "") { + newErr := fmt.Errorf("Invalid VPC ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + targetGroupReq := vlb.GetTargetGroupListRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + VpcNo: &vpcId, + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.GetTargetGroupList(&targetGroupReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find TargetGroup List from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + cblogger.Info("### TargetGroup does Not Exist!!") + } + + return result.TargetGroupList, nil +} + +// Get VM Members of the NLB with the targetGroupId +func (nlbHandler *NcpVpcNLBHandler) GetNcpTargetVMList(targetGroupId string) ([]*vlb.Target, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNcpTargetVMList()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", targetGroupId, "GetNcpTargetVMList()") + + if strings.EqualFold(targetGroupId, "") { + newErr := fmt.Errorf("Invalid TargetGroup ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + targetReq := vlb.GetTargetListRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + TargetGroupNo: &targetGroupId, + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.GetTargetList(&targetReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find Target List from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + cblogger.Info("### The VMGroup does Not have any VM Member!!") + return nil, nil // Caution!! + } + + return result.TargetList, nil +} + +func (nlbHandler *NcpVpcNLBHandler) GetNcpVpcInfoWithName(vpcName string) (*vpc.Vpc, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNPCVpcInfoWithName()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", vpcName, "GetNPCVpcInfoWithName()") + + if strings.EqualFold(vpcName, "") { + newErr := fmt.Errorf("Invalid VPC Name!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + vpcListReq := vpc.GetVpcListRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + } + + callLogStart := call.Start() + result, err := nlbHandler.VPCClient.V2Api.GetVpcList(&vpcListReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get VPC List from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + cblogger.Info("### VPC does Not Exist!!") + } else { + for _, vpc := range result.VpcList { + if strings.EqualFold(*vpc.VpcName, vpcName) { + return vpc, nil + } + } + } + + return nil, fmt.Errorf("Failed to Find VPC Info with the name.") +} + +// Get SubnetId for 'LB Only' subnet('LB Type' subnet) +func (nlbHandler *NcpVpcNLBHandler) GetSubnetIdForNlbOnly(vpcId string) (string, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetSubnetIdForNLB()") + + vpcHandler := NcpVpcVPCHandler{ + RegionInfo: nlbHandler.RegionInfo, + VPCClient: nlbHandler.VPCClient, + } + + subnetInfoList, err := vpcHandler.ListSubnet(&vpcId) + if err != nil { + newErr := fmt.Errorf("Failed to Get SubnetList with the VPC No. : [%v]", err) + cblogger.Error(newErr.Error()) + return "", newErr + } + + if len(subnetInfoList) < 1 { + newErr := fmt.Errorf("### The VPC has No Subnet!!") + cblogger.Error(newErr.Error()) + return "", newErr + } + + var subnetId string + for _, subnetInfo := range subnetInfoList { + // Use Key/Value info of the subnetInfo + for _, keyInfo := range subnetInfo.KeyValueList { + if strings.EqualFold(keyInfo.Key, "UsageType") { + if strings.EqualFold(keyInfo.Value, "LOADB") { + subnetId = subnetInfo.IId.SystemId + break + } + } + } + } + return subnetId, nil +} + +func (nlbHandler *NcpVpcNLBHandler) WaitToGetNlbInfo(nlbIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC 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") { + return true, nil + } + 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 *NcpVpcNLBHandler) WaitForDelNlb(nlbIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC 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 Provisioning Status : [%v]", err) + cblogger.Error(newErr.Error()) + return false, newErr + } else if !strings.EqualFold(nlbStatus, "Running") && !strings.EqualFold(nlbStatus, "Terminating") { + return true, nil + } + time.Sleep(3 * time.Second) + if curRetryCnt > maxRetryCnt { + return false, fmt.Errorf("Failed to Del the NLB. Exceeded maximum retry count %d", maxRetryCnt) + } + } +} + +// NCP VPC LoadBalancerInstanceStatusName : Creating, Running, Changing, Terminating, Terminated, Repairing +func (nlbHandler *NcpVpcNLBHandler) GetNcpNlbStatus(nlbIID irs.IID) (string, error) { + cblogger.Info("NCP VPC 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 VPC NLB info!! [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + + cblogger.Infof("\n### NLB Status : [%s]", *ncpNlbInfo.LoadBalancerInstanceStatusName) + return *ncpNlbInfo.LoadBalancerInstanceStatusName, nil +} + +func (nlbHandler *NcpVpcNLBHandler) GetNcpNlbInfo(nlbIID irs.IID) (*vlb.LoadBalancerInstance, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNcpNlbInfo()") + + InitLog() // Caution!! + 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 + } + + lbReq := vlb.GetLoadBalancerInstanceDetailRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, // CAUTION!! : Searching NLB Info by RegionCode (Not RegionNo) + LoadBalancerInstanceNo: &nlbIID.SystemId, + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.GetLoadBalancerInstanceDetail(&lbReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get the NLB Info from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Get Any NLB Info with the ID from NCP VPC!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting the NLB Info.") + } + + return result.LoadBalancerInstanceList[0], nil +} + +func (nlbHandler *NcpVpcNLBHandler) GetNcpNlbListWithVpcId(vpcId *string) ([]*vlb.LoadBalancerInstance, error) { + cblogger.Info("NPC VPC Cloud Driver: called GetNcpNlbListWithVpcId()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", "GetNcpNlbListWithVpcId()", "GetNcpNlbListWithVpcId()") + + if strings.EqualFold(*vpcId, "") { + newErr := fmt.Errorf("Invalid VPC ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + lbReq := vlb.GetLoadBalancerInstanceListRequest{ + RegionCode: &nlbHandler.RegionInfo.Region, + VpcNo: vpcId, + } + + callLogStart := call.Start() + result, err := nlbHandler.VLBClient.V2Api.GetLoadBalancerInstanceList(&lbReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find NLB list from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + return result.LoadBalancerInstanceList, nil +} + +// Only When any Subnet exists already(because of NetworkACLNo) +// Creat a Subnet for 'LB Only'('LB Type' Subnet) +func (nlbHandler *NcpVpcNLBHandler) CreatNcpSubnetForNlbOnly(vpcIID irs.IID, subnetReqInfo irs.SubnetInfo) (*vpc.Subnet, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreatNcpSubnetForNlb()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Zone, call.VPCSUBNET, subnetReqInfo.IId.NameId, "CreatNcpSubnetForNlb()") + + if strings.EqualFold(vpcIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VPC SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + vpcHandler := NcpVpcVPCHandler{ + RegionInfo: nlbHandler.RegionInfo, + VPCClient: nlbHandler.VPCClient, + } + + // Check if the SubnetName Exists + subnetInfoList, err := vpcHandler.ListSubnet(&vpcIID.SystemId) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + // return irs.VPCInfo{}, err // Caution!! + } + + for _, subnet := range subnetInfoList { + if strings.EqualFold(subnet.IId.NameId, subnetReqInfo.IId.NameId) { + newErr := fmt.Errorf("Subnet with the name [%s] exists already!!", subnetReqInfo.IId.NameId) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + } + + // Get the Default NetworkACL No. of the VPC + netAclNo, getNoErr := vpcHandler.GetDefaultNetworkAclNo(vpcIID) + if getNoErr != nil { + newErr := fmt.Errorf("Failed to Get Network ACL No of the VPC : [%v]", getNoErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + // Note : subnetUsageType : 'GEN' (general) | 'LOADB' (Load balancer only) | 'BM' (Bare metal only) + subnetUsageType := "LOADB" + ncpSubnetInfo, err := vpcHandler.CreateSubnet(vpcIID, netAclNo, &subnetUsageType, subnetReqInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Create the Subnet for NLB Only : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + cblogger.Infof("New Subnet Name : [%s]", *ncpSubnetInfo.SubnetName) + + subnetStatus, err := vpcHandler.WaitForCreateSubnet(ncpSubnetInfo.SubnetNo) + if err != nil { + newErr := fmt.Errorf("Failed to Wait for Creating the subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + cblogger.Infof("\n### Subnet Status : [%s]", subnetStatus) + + return ncpSubnetInfo, nil +} + + +// Clean up the VMGroup and LB Type subnet +func (nlbHandler *NcpVpcNLBHandler) CleanUpNLB(vpcId *string) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called CleanUpNLB()") + callLogInfo := GetCallLogScheme(nlbHandler.RegionInfo.Region, "NETWORKLOADBALANCE", *vpcId, "CleanUpNLB()") + + if strings.EqualFold(*vpcId, "") { + newErr := fmt.Errorf("Invalid VPC ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + ncpNlbList, err := nlbHandler.GetNcpNlbListWithVpcId(vpcId) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP NLB List with the VPC ID. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + nlbCount := len(ncpNlbList) + cblogger.Infof("\n# NLB Count : [%d]", nlbCount) + + // Note : Cloud-Barista supports only this case => [ LB : Listener : VM Group : Health Checker = 1 : 1 : 1 : 1 ] + ncpTargetGroupList, err := nlbHandler.GetNcpTargetGroupListWithVpcId(*vpcId) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP VMGroup List with the VPC ID. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + if len(ncpTargetGroupList) < 1 { + cblogger.Info("# VMGroup does Not Exist!!") + } else { + cblogger.Infof("\n\n# VMGroup No to Delete : [%s]", *ncpTargetGroupList[0].TargetGroupNo) + delResult, err := nlbHandler.DeleteVMGroup(*ncpTargetGroupList[0].TargetGroupNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP VMGroup List with the VPC ID. [%v]", err.Error()) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + if !delResult { + newErr := fmt.Errorf("Failed to Delete the VMGroup!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + } + + // #### Note!! + // If the deleted LB was the last one to delete, Need to delete the 'LB Type' Subnet. + if nlbCount == 0 { + lbTypeSubnetId, err := nlbHandler.GetSubnetIdForNlbOnly(*vpcId) + if err != nil { + newErr := fmt.Errorf("Failed to Get the SubnetId of LB Type subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + vpcHandler := NcpVpcVPCHandler{ + RegionInfo: nlbHandler.RegionInfo, + VPCClient: nlbHandler.VPCClient, + } + + result, removeErr := vpcHandler.RemoveSubnet(irs.IID{SystemId: *vpcId}, irs.IID{SystemId: lbTypeSubnetId}) + if removeErr != nil { + newErr := fmt.Errorf("Failed to Remove the LB Type Subnet : [%v]", removeErr) + cblogger.Error(newErr.Error()) + return false, newErr + } + if result { + cblogger.Info("Succeeded in Removing the LB Type subnet.") + return true, nil + } + } + + return true, nil +} + +// NCP LB resource Def. : https://api.ncloud-docs.com/docs/en/common-vapidatatype-loadbalancerinstance +func (nlbHandler *NcpVpcNLBHandler) MappingNlbInfo(nlb vlb.LoadBalancerInstance) (irs.NLBInfo, error) { + cblogger.Info("NCP VPC 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) + + var nlbType string + if strings.EqualFold(*nlb.LoadBalancerNetworkType.CodeName, "PUBLIC") { + nlbType = "PUBLIC" + } else if strings.EqualFold(*nlb.LoadBalancerNetworkType.CodeName, "PRIVATE") { + 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, + } + + keyValueList := []irs.KeyValue{ + {Key: "RegionCode", Value: *nlb.RegionCode}, + {Key: "NLB1stSubnetZone", Value: *nlb.LoadBalancerSubnetList[0].ZoneCode}, + {Key: "NLB_Status", Value: *nlb.LoadBalancerInstanceStatusName}, + } + + if len(nlb.LoadBalancerListenerNoList) > 0 { + // 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.LoadBalancerListenerNoList[0], *nlb.LoadBalancerInstanceNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Listener Info : [%v]", err.Error()) + cblogger.Error(newErr.Error()) + return irs.NLBInfo{}, newErr + } + listenerInfo.IP = *nlb.LoadBalancerIpList[0] // Note : LoadBalancer IP is created already during LB creation. + nlbInfo.Listener = *listenerInfo + + listenerKeyValue := irs.KeyValue{Key: "ListenerId", Value: *nlb.LoadBalancerListenerNoList[0]} + keyValueList = append(keyValueList, listenerKeyValue) + + 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 + + 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 + + monitorKeyValue := irs.KeyValue{Key: "HealthCheckerId", Value: nlbInfo.HealthChecker.CspID} + keyValueList = append(keyValueList, monitorKeyValue) + } + } + + nlbInfo.KeyValueList = keyValueList + return nlbInfo, nil +} + +func (nlbHandler *NcpVpcNLBHandler) MappingListenerInfo(listener vlb.LoadBalancerListener) (irs.ListenerInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called MappingListenerInfo()") + + if strings.EqualFold(*listener.LoadBalancerListenerNo, "") { + newErr := fmt.Errorf("Invalid LoadBalancer Listener Info!!") + cblogger.Error(newErr.Error()) + return irs.ListenerInfo{}, newErr + } + + if *listener.Port < 1 || *listener.Port > 65535 { + newErr := fmt.Errorf("Invalid Listener Port.(Must be between 1 and 65535)") + cblogger.Error(newErr.Error()) + return irs.ListenerInfo{}, newErr + } + + listenerInfo := irs.ListenerInfo{ + Protocol: *listener.ProtocolType.Code, + Port: strconv.FormatInt(int64(*listener.Port), 10), + CspID: *listener.LoadBalancerListenerNo, + } + + keyValueList := []irs.KeyValue{ + {Key: "UseHttp2", Value: strconv.FormatBool(*listener.UseHttp2)}, + } + listenerInfo.KeyValueList = keyValueList + + return listenerInfo, nil +} + +// Note!! : Will be decided later if we would support bellow methoeds or not. +// ------ Frontend Control +func (nlbHandler *NcpVpcNLBHandler) ChangeListener(nlbIID irs.IID, listener irs.ListenerInfo) (irs.ListenerInfo, error) { + + return irs.ListenerInfo{}, fmt.Errorf("Does not support yet!!") +} + +// ------ Backend Control +func (nlbHandler *NcpVpcNLBHandler) ChangeVMGroupInfo(nlbIID irs.IID, vmGroup irs.VMGroupInfo) (irs.VMGroupInfo, error) { + + return irs.VMGroupInfo{}, fmt.Errorf("Does not support yet!!") +} + +func (nlbHandler *NcpVpcNLBHandler) 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/ncpvpc/resources/RegionZoneHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/RegionZoneHandler.go new file mode 100644 index 000000000..88da8bd18 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/RegionZoneHandler.go @@ -0,0 +1,257 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VPC RegionZone Handler +// +// Created by ETRI, 2023.09. +//================================================================================================== + +// RegionZoneInfo Fetch Speed Improvement and KeyValueList Omission Issue : +// https://github.com/cloud-barista/cb-spider/issues/930#issuecomment-1734817828 + +package resources + +import ( + // "errors" + "sync" + "strings" + // "github.com/davecgh/go-spew/spew" + + // ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + vserver "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + + 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 NcpRegionZoneHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +func (regionZoneHandler *NcpRegionZoneHandler) ListRegionZone() ([]*irs.RegionZoneInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called ListRegionZone()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, "ListRegionZone()", "ListRegionZone()") + + ncpVpcRegionList, err := regionZoneHandler.getNcpVpcRegionList("ListRegionZone()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get RegionList from NCP Cloud : ", err) + return nil, rtnErr + } + + var regionZoneInfoList []*irs.RegionZoneInfo + var wait sync.WaitGroup + var zoneListError error + for _, region := range ncpVpcRegionList { + wait.Add(1) + go func(region *vserver.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: "RegionCode", Value: *region.RegionCode}, + // }, + } + + ncpVpcZoneList, err := regionZoneHandler.getNcpVpcZoneList(region.RegionCode, "ListRegionZone()") + if err != nil { + zoneListError = err + return + } + + var zoneInfoList []irs.ZoneInfo + for _, zone := range ncpVpcZoneList { + zoneInfo := irs.ZoneInfo{ + Name: *zone.ZoneName, + DisplayName: *zone.ZoneDescription, + Status: irs.NotSupported, + // KeyValueList: []irs.KeyValue{ + // {Key: "ZoneCode", Value: *zone.ZoneCode}, + // }, + } + zoneInfoList = append(zoneInfoList, zoneInfo) + } + regionZoneInfo.ZoneList = zoneInfoList + regionZoneInfoList = append(regionZoneInfoList, ®ionZoneInfo) + }(region) + } + wait.Wait() + + if zoneListError != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Zone List!!", zoneListError) + return nil, rtnErr + } + + return regionZoneInfoList, nil +} + +func (regionZoneHandler NcpRegionZoneHandler) GetRegionZone(regionCode string) (irs.RegionZoneInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetRegionZone()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, regionCode, "GetRegionZone()") + + if len(regionCode) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Invalid RegionCode!!", "") + return irs.RegionZoneInfo{}, rtnErr + } + + ncpVpcRegionList, err := regionZoneHandler.getNcpVpcRegionList("GetRegionZone()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get RegionList from NCP Cloud : ", err) + return irs.RegionZoneInfo{}, rtnErr + } + + var regionZoneInfo irs.RegionZoneInfo + for _, region := range ncpVpcRegionList { + 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: "RegionCode", Value: *region.RegionCode}, + // }, + } + + ncpVpcZoneList, err := regionZoneHandler.getNcpVpcZoneList(region.RegionCode, "GetRegionZone()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get ZoneList from NCP Cloud : ", err) + return irs.RegionZoneInfo{}, rtnErr + } + + var zoneInfoList []irs.ZoneInfo + for _, zone := range ncpVpcZoneList { + zoneInfo := irs.ZoneInfo{ + Name: *zone.ZoneName, + DisplayName: *zone.ZoneDescription, + Status: irs.NotSupported, + // KeyValueList: []irs.KeyValue{ + // {Key: "ZoneCode", Value: *zone.ZoneCode}, + // }, + } + zoneInfoList = append(zoneInfoList, zoneInfo) + } + regionZoneInfo.ZoneList = zoneInfoList + } + } + return regionZoneInfo, nil +} + +func (regionZoneHandler *NcpRegionZoneHandler) ListOrgRegion() (string, error) { + cblogger.Info("NCP VPC Cloud Driver: called ListOrgRegion()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, "ListOrgRegion()", "ListOrgRegion()") + + // To return the results with a style similar to other CSPs. + type Regions struct { + RegionList []*vserver.Region // Must be a capital letter!! + } + + ncpVpcRegionList, err := regionZoneHandler.getNcpVpcRegionList("ListOrgRegion()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get RegionList from NCP Cloud : ", err) + return "", rtnErr + } + ncpRegionList := Regions{ + RegionList: ncpVpcRegionList, + } + jsonString, cvtErr := ConvertJsonString(ncpRegionList) + if cvtErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Convert the RegionList to Json format string.", cvtErr) + return "", rtnErr + } + return jsonString, cvtErr +} + +func (regionZoneHandler *NcpRegionZoneHandler) ListOrgZone() (string, error) { + cblogger.Info("NCP VPC Cloud Driver: called ListOrgZone()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, "ListOrgZone()", "ListOrgZone()") + + if len(regionZoneHandler.RegionInfo.Region) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Invalid Region Info!!", "") + return "", rtnErr + } + + // To return the results with a style similar to other CSPs. + type Zones struct { + ZoneList []*vserver.Zone // Must be a capital letter!! + } + + ncpVpcZoneList, err := regionZoneHandler.getNcpVpcZoneList(®ionZoneHandler.RegionInfo.Region, "ListOrgZone()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get ZoneList from NCP Cloud : ", err) + return "", rtnErr + } + + ncpZoneList := Zones{ + ZoneList: ncpVpcZoneList, + } + jsonString, cvtErr := ConvertJsonString(ncpZoneList) + if cvtErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Convert the ZoneList to Json format string.", cvtErr) + return "", rtnErr + } + return jsonString, cvtErr +} + +func (regionZoneHandler *NcpRegionZoneHandler) getNcpVpcRegionList(callLogfunc string) ([]*vserver.Region, error) { + cblogger.Info("NCP VPC Cloud Driver: called getNcpVpcRegionList()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, callLogfunc, callLogfunc) + + regionListReq := vserver.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) + } + return regionListResult.RegionList, nil +} + +func (regionZoneHandler *NcpRegionZoneHandler) getNcpVpcZoneList(regionCode *string, callLogfunc string) ([]*vserver.Zone, error) { + cblogger.Info("NCP VPC Cloud Driver: called getNcpVpcZoneList()!!") + + InitLog() + callLogInfo := GetCallLogScheme(regionZoneHandler.RegionInfo.Zone, call.REGIONZONE, *regionCode, callLogfunc) + + zoneListReq := vserver.GetZoneListRequest{RegionCode: regionCode} + 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 nil, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + if len(zoneListResult.ZoneList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "Failed to Find Any Zone Info.", "") + return nil, rtnErr + } else { + cblogger.Infof("# Supported Zone count [%s] : [%d]", *regionCode, len(zoneListResult.ZoneList)) + // spew.Dump(zoneListResult) + } + return zoneListResult.ZoneList, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/SecurityHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/SecurityHandler.go new file mode 100644 index 000000000..9427c30be --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/SecurityHandler.go @@ -0,0 +1,1117 @@ +// 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 Security Group Handler +// +// by ETRI, 2020.10. +// Updated by ETRI, 2022.11. + +package resources + +import ( + "fmt" + "errors" + "strconv" + "strings" + "time" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + "github.com/davecgh/go-spew/spew" + + cblog "github.com/cloud-barista/cb-log" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" + idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" + irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" +) + +type NcpVpcSecurityHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP Security Group Handler") +} + +func (securityHandler *NcpVpcSecurityHandler) CreateSecurity(securityReqInfo irs.SecurityReqInfo) (irs.SecurityInfo, error) { + cblogger.Info("NCP VPC cloud driver: called CreateSecurity()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Region, call.SECURITYGROUP, securityReqInfo.IId.NameId, "CreateSecurity()") + + if securityReqInfo.IId.NameId == "" { + createErr := fmt.Errorf("Invalid S/G Name") + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return irs.SecurityInfo{}, createErr + } + + // Check if the S/G exists + sgList, err := securityHandler.ListSecurity() + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + + for _, sg := range sgList { + if strings.EqualFold(sg.IId.NameId, securityReqInfo.IId.NameId) { + createErr := fmt.Errorf("Specified S/G [%s] already exists", securityReqInfo.IId.NameId) + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return irs.SecurityInfo{}, createErr + } + } + + // Create New S/G + sgReq := vserver.CreateAccessControlGroupRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupName: &securityReqInfo.IId.NameId, + VpcNo: &securityReqInfo.VpcIID.SystemId, + } + + callLogStart := call.Start() + ncpVpcSG, err := securityHandler.VMClient.V2Api.CreateAccessControlGroup(&sgReq) + if err != nil { + cblogger.Error(*ncpVpcSG.ReturnMessage) + newErr := fmt.Errorf("Failed to Create New S/G : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *ncpVpcSG.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create Any S/G!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } else { + cblogger.Infof("Succeeded in Creating New S/G : [%s]", *ncpVpcSG.AccessControlGroupList[0].AccessControlGroupName) + } + + sgNo := ncpVpcSG.AccessControlGroupList[0].AccessControlGroupNo + + // Create S/G Rules + for _, curRule := range *securityReqInfo.SecurityRules { + if curRule.Direction == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'Direction' Value in the requested rule!!") + } else if curRule.IPProtocol == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'IPProtocol' Value in the requested rule!!") + } else if curRule.FromPort == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'FromPort' Value in the requested rule!!") + } else if curRule.ToPort == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'ToPort' Value in the requested rule!!") + } else if curRule.CIDR == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'CIDR' Value in the requested rule!!") + } + + var ruleDirection string + if strings.EqualFold(curRule.Direction, "inbound") { + ruleDirection = "inbound" + } else if strings.EqualFold(curRule.Direction, "outbound") { + ruleDirection = "outbound" + } else { + return irs.SecurityInfo{}, errors.New("Specified Invalid Security Rule Direction!!") + } + + if strings.EqualFold(ruleDirection, "inbound") { + protocolType := strings.ToUpper(curRule.IPProtocol) // Caution : Valid values : [TCP, UDP, ICMP] + + if strings.EqualFold(protocolType, "ALL") { + if strings.EqualFold(curRule.FromPort, "-1") && strings.EqualFold(curRule.ToPort, "-1") { + allProtocolTypeCode := []string {"TCP", "UDP", "ICMP"} + var allPortRange string + allCIDR := "0.0.0.0/0" + + for _, curProtocolType := range allProtocolTypeCode { + if strings.EqualFold(curProtocolType, "ICMP") { + allPortRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + allPortRange = "1-65535" // All Range + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &allCIDR, + PortRange: &allPortRange, + ProtocolTypeCode: &curProtocolType, + } + + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + inboundReq := vserver.AddAccessControlGroupInboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: sgNo, + VpcNo: &securityReqInfo.VpcIID.SystemId, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgInboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupInboundRule(&inboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgInboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgInboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Create New S/G Inbound Rule!!") + } else { + cblogger.Infof("Succeeded in Creating New [%s] Inbound Rule!!", curProtocolType) + + time.Sleep(time.Second * 5) // Caution!! + } + } + } else { + return irs.SecurityInfo{}, errors.New("To Specify 'All Traffic Allow Rule', Specify '-1' as FromPort/ToPort!!") + } + } else { + var portRange string + + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else if strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) // string + } else if !strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) + "-"+ strings.ToLower(curRule.ToPort) // string + } + + if strings.EqualFold(curRule.FromPort, "-1") || strings.EqualFold(curRule.ToPort, "-1") { + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + portRange = "1-65535" // All Range + } + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &curRule.CIDR, + PortRange: &portRange, + ProtocolTypeCode: &protocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + inboundReq := vserver.AddAccessControlGroupInboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: sgNo, + VpcNo: &securityReqInfo.VpcIID.SystemId, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgInboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupInboundRule(&inboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgInboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgInboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Create S/G Inbound Rule!!") + } else { + cblogger.Infof("Succeeded in Creating New [%s] Inbound Rule!!", protocolType) + } + } + } + + if strings.EqualFold(ruleDirection, "outbound") { + protocolType := strings.ToUpper(curRule.IPProtocol) // Caution : Valid values : [TCP, UDP, ICMP] + + if strings.EqualFold(protocolType, "ALL") { + if strings.EqualFold(curRule.FromPort, "-1") && strings.EqualFold(curRule.ToPort, "-1") { + allProtocolTypeCode := []string {"TCP", "UDP", "ICMP"} + var allPortRange string // All Range + allCIDR := "0.0.0.0/0" + + for _, curProtocolType := range allProtocolTypeCode { + if strings.EqualFold(curProtocolType, "ICMP") { + allPortRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + allPortRange = "1-65535" // All Range + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &allCIDR, + PortRange: &allPortRange, + ProtocolTypeCode: &curProtocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + outboundReq := vserver.AddAccessControlGroupOutboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: sgNo, + VpcNo: &securityReqInfo.VpcIID.SystemId, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgOutboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupOutboundRule(&outboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgOutboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgOutboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Create New S/G Outbound Rule!!") + } else { + cblogger.Infof("Succeeded in Creating New [%s] Outbound Rule!!", curProtocolType) + + time.Sleep(time.Second * 5) // Caution!! + } + } + } else { + return irs.SecurityInfo{}, errors.New("To Specify 'All Traffic Allow Rule', Specify '-1' as FromPort/ToPort!!") + } + } else { + var portRange string + + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else if strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) // string + } else if !strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) + "-"+ strings.ToLower(curRule.ToPort) // string + } + + if strings.EqualFold(curRule.FromPort, "-1") || strings.EqualFold(curRule.ToPort, "-1") { + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + portRange = "1-65535" // All Range + } + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &curRule.CIDR, + PortRange: &portRange, + ProtocolTypeCode: &protocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + outboundReq := vserver.AddAccessControlGroupOutboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: sgNo, + VpcNo: &securityReqInfo.VpcIID.SystemId, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgOutboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupOutboundRule(&outboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgOutboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgOutboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Create New S/G Outbound Rule!!") + } else { + cblogger.Infof("Succeeded in Creating New [%s] Outbound Rule!!", protocolType) + } + } + } + } + + // Basically, Open 'Outbound' All Protocol for Any S/G (<= CB-Spider Rule) + openErr := securityHandler.OpenOutboundAllProtocol(irs.IID{SystemId: *sgNo}) + if openErr != nil { + cblogger.Error(openErr) + LoggingError(callLogInfo, openErr) + // return irs.SecurityInfo{}, openErr + } + + // Return Created S/G Info. + sgInfo, err := securityHandler.GetSecurity(irs.IID{SystemId: *sgNo}) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + + return sgInfo, nil +} + +func (securityHandler *NcpVpcSecurityHandler) GetSecurity(securityIID irs.IID) (irs.SecurityInfo, error) { + cblogger.Info("NCP VPC cloud driver: called GetSecurity()!!") + cblogger.Infof("NCP securityIID.SystemId : [%s]", securityIID.SystemId) + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Zone, call.SECURITYGROUP, securityIID.SystemId, "GetSecurity()") + + sgNumList := []*string{ncloud.String(securityIID.SystemId),} + sgReq := vserver.GetAccessControlGroupListRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNoList: sgNumList, + } + + // Search NCP VPC AccessControlGroup with securityIID.SystemId + callLogStart := call.Start() + ncpVpcSG, err := securityHandler.VMClient.V2Api.GetAccessControlGroupList(&sgReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*ncpVpcSG.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *ncpVpcSG.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Find Any S/G with the SystemId : [%s]", securityIID.SystemId) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SecurityInfo{}, newErr + } + + cblogger.Info("Succeeded in Getting S/G info.") + + sgInfo, sgInfoErr := securityHandler.MappingSecurityInfo(*ncpVpcSG.AccessControlGroupList[0]) + if sgInfoErr != nil { + cblogger.Error(sgInfoErr) + return irs.SecurityInfo{}, sgInfoErr + } + + return sgInfo, nil +} + +func (securityHandler *NcpVpcSecurityHandler) ListSecurity() ([]*irs.SecurityInfo, error) { + cblogger.Info("NCP VPC cloud driver: called ListSecurity()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Zone, call.SECURITYGROUP, "ListSecurity()", "ListSecurity()") + + var securityGroupList []*irs.SecurityInfo + + sgReq := vserver.GetAccessControlGroupListRequest{ + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNoList: nil, + } + + // Search NCP VPC AccessControlGroup list + callLogStart := call.Start() + sgList, err := securityHandler.VMClient.V2Api.GetAccessControlGroupList(&sgReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgList.ReturnMessage) + LoggingError(callLogInfo, err) + return nil, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgList.TotalRows < 1 { + return nil, errors.New("Failed to Find any S/G list!!") + } + + cblogger.Info("Succeeded in Getting S/G List.") + + for _, sg := range sgList.AccessControlGroupList { + cblogger.Infof("NCP VPC S/G No : [%s]", *sg.AccessControlGroupNo) + sgInfo, sgInfoErr := securityHandler.MappingSecurityInfo(*sg) + if sgInfoErr != nil { + cblogger.Error(sgInfoErr) + return nil, sgInfoErr + } + securityGroupList = append(securityGroupList, &sgInfo) + } + return securityGroupList, nil +} + +func (securityHandler *NcpVpcSecurityHandler) DeleteSecurity(securityIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC cloud driver: called DeleteSecurity()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Region, call.SECURITYGROUP, securityIID.SystemId, "DeleteSecurity()") + + if securityIID.SystemId == "" { + createErr := fmt.Errorf("Invalid S/G SystemId") + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return false, createErr + } + + // Check if the S/G exists + ncpVpcSG, err := securityHandler.GetSecurity(securityIID) + if err != nil { + createErr := fmt.Errorf("Failed to Find any S/G info. with the SystemId : " + securityIID.SystemId) + cblogger.Error(err.Error()) + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return false, err + } + cblogger.Infof("The S/G Name to Delete : [%s]", ncpVpcSG.IId.NameId) + + // Delete the S/G + sgDelReq := vserver.DeleteAccessControlGroupRequest { + RegionCode: &securityHandler.RegionInfo.Region, + VpcNo: &ncpVpcSG.VpcIID.SystemId, + AccessControlGroupNo: &securityIID.SystemId, + } + + callLogStart := call.Start() + delResult, err := securityHandler.VMClient.V2Api.DeleteAccessControlGroup(&sgDelReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*delResult.ReturnMessage) + LoggingError(callLogInfo, err) + return false, err + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Infof("Succeeded in Deleting the S/G : [%s]", ncpVpcSG.IId.NameId) + + return true, nil +} + +func (securityHandler *NcpVpcSecurityHandler) AddRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (irs.SecurityInfo, error) { + cblogger.Info("NCP VPC cloud driver: called AddRules()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Region, call.SECURITYGROUP, sgIID.SystemId, "AddRules()") + + if sgIID.SystemId == "" { + createErr := fmt.Errorf("Invalid S/G SystemId") + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return irs.SecurityInfo{}, createErr + } + + // Check if the S/G exists + ncpVpcSG, err := securityHandler.GetSecurity(sgIID) + if err != nil { + createErr := fmt.Errorf("Failed to Find any S/G info. with the SystemId : " + sgIID.SystemId) + cblogger.Error(err.Error()) + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return irs.SecurityInfo{}, err + } + + cblogger.Infof("The S/G Name to Add the Requested Rules : [%s]", ncpVpcSG.IId.NameId) + + sgNo := sgIID.SystemId + vpcNo := ncpVpcSG.VpcIID.SystemId + + // Create S/G Rules + for _, curRule := range *securityRules { + if curRule.Direction == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'Direction' Value in the requested rule!!") + } else if curRule.IPProtocol == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'IPProtocol' Value in the requested rule!!") + } else if curRule.FromPort == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'FromPort' Value in the requested rule!!") + } else if curRule.ToPort == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'ToPort' Value in the requested rule!!") + } else if curRule.CIDR == "" { + return irs.SecurityInfo{}, errors.New("Failed to Find 'CIDR' Value in the requested rule!!") + } + + var ruleDirection string + if strings.EqualFold(curRule.Direction, "inbound") { + ruleDirection = "inbound" + } else if strings.EqualFold(curRule.Direction, "outbound") { + ruleDirection = "outbound" + } else { + return irs.SecurityInfo{}, errors.New("Specified Invalid Security Rule Direction!!") + } + + if strings.EqualFold(ruleDirection, "inbound") { + protocolType := strings.ToUpper(curRule.IPProtocol) // Caution : Valid values : [TCP, UDP, ICMP] + + if strings.EqualFold(protocolType, "ALL") { + if strings.EqualFold(curRule.FromPort, "-1") && strings.EqualFold(curRule.ToPort, "-1") { + allProtocolTypeCode := []string {"TCP", "UDP", "ICMP"} + var allPortRange string + allCIDR := "0.0.0.0/0" + + for _, curProtocolType := range allProtocolTypeCode { + if strings.EqualFold(curProtocolType, "ICMP") { + allPortRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + allPortRange = "1-65535" // All Range + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &allCIDR, + PortRange: &allPortRange, + ProtocolTypeCode: &curProtocolType, + } + + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + inboundReq := vserver.AddAccessControlGroupInboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgInboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupInboundRule(&inboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgInboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgInboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Add New S/G Inbound Rule!!") + } else { + cblogger.Infof("Succeeded in Adding New [%s] Inbound Rule!!", curProtocolType) + + time.Sleep(time.Second * 5) // Caution!! + } + } + } else { + return irs.SecurityInfo{}, errors.New("To Specify 'All Traffic Allow Rule', Specify '-1' as FromPort/ToPort!!") + } + } else { + var portRange string + + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else if strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) // string + } else if !strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) + "-"+ strings.ToLower(curRule.ToPort) // string + } + + if strings.EqualFold(curRule.FromPort, "-1") || strings.EqualFold(curRule.ToPort, "-1") { + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + portRange = "1-65535" // All Range + } + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &curRule.CIDR, + PortRange: &portRange, + ProtocolTypeCode: &protocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + inboundReq := vserver.AddAccessControlGroupInboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgInboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupInboundRule(&inboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgInboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgInboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Add New S/G Inbound Rule!!") + } else { + cblogger.Infof("Succeeded in Adding New [%s] Inbound Rule!!", protocolType) + } + } + } + + if strings.EqualFold(ruleDirection, "outbound") { + protocolType := strings.ToUpper(curRule.IPProtocol) // Caution : Valid values : [TCP, UDP, ICMP] + + if strings.EqualFold(protocolType, "ALL") { + if strings.EqualFold(curRule.FromPort, "-1") && strings.EqualFold(curRule.ToPort, "-1") { + allProtocolTypeCode := []string {"TCP", "UDP", "ICMP"} + var allPortRange string // All Range + allCIDR := "0.0.0.0/0" + + for _, curProtocolType := range allProtocolTypeCode { + if strings.EqualFold(curProtocolType, "ICMP") { + allPortRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + allPortRange = "1-65535" // All Range + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &allCIDR, + PortRange: &allPortRange, + ProtocolTypeCode: &curProtocolType, + } + + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + outboundReq := vserver.AddAccessControlGroupOutboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgOutboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupOutboundRule(&outboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgOutboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgOutboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Add New S/G Outbound Rule!!") + } else { + cblogger.Infof("Succeeded in Adding New [%s] Outbound Rule!!", curProtocolType) + + time.Sleep(time.Second * 5) // Caution!! + } + } + } else { + return irs.SecurityInfo{}, errors.New("To Specify 'All Traffic Allow Rule', Specify '-1' as FromPort/ToPort!!") + } + } else { + var portRange string + + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else if strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) // string + } else if !strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) + "-"+ strings.ToLower(curRule.ToPort) // string + } + + if strings.EqualFold(curRule.FromPort, "-1") || strings.EqualFold(curRule.ToPort, "-1") { + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + portRange = "1-65535" // All Range + } + } + + var ruleParameterList []*vserver.AddAccessControlGroupRuleParameter + ruleParameter := vserver.AddAccessControlGroupRuleParameter { + IpBlock: &curRule.CIDR, + PortRange: &portRange, + ProtocolTypeCode: &protocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + outboundReq := vserver.AddAccessControlGroupOutboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgOutboundRule, err := securityHandler.VMClient.V2Api.AddAccessControlGroupOutboundRule(&outboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgOutboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *sgOutboundRule.TotalRows < 1 { + return irs.SecurityInfo{}, errors.New("Failed to Add New S/G Outbound Rule!!") + } else { + cblogger.Infof("Succeeded in Adding New [%s] Outbound Rule!!", protocolType) + } + } + } + } + + // Return Current S/G Info. + sgInfo, err := securityHandler.GetSecurity(irs.IID{SystemId: sgNo}) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + return irs.SecurityInfo{}, err + } + return sgInfo, nil +} + +func (securityHandler *NcpVpcSecurityHandler) RemoveRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (bool, error) { + cblogger.Info("NCP VPC cloud driver: called RemoveRules()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Region, call.SECURITYGROUP, sgIID.SystemId, "RemoveRules()") + + if sgIID.SystemId == "" { + createErr := fmt.Errorf("Invalid S/G SystemId") + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return false, createErr + } + + // Check if the S/G exists + ncpVpcSG, err := securityHandler.GetSecurity(sgIID) + if err != nil { + createErr := fmt.Errorf("Failed to Find any S/G info. with the SystemId : " + sgIID.SystemId) + cblogger.Error(err.Error()) + cblogger.Error(createErr.Error()) + LoggingError(callLogInfo, createErr) + return false, err + } + + cblogger.Infof("The S/G Name to Remove the Requested Rules : [%s]", ncpVpcSG.IId.NameId) + + sgNo := sgIID.SystemId + vpcNo := ncpVpcSG.VpcIID.SystemId + + // Create S/G Rules + for _, curRule := range *securityRules { + if curRule.Direction == "" { + return false, errors.New("Failed to Find 'Direction' Value in the requested rule!!") + } else if curRule.IPProtocol == "" { + return false, errors.New("Failed to Find 'IPProtocol' Value in the requested rule!!") + } else if curRule.FromPort == "" { + return false, errors.New("Failed to Find 'FromPort' Value in the requested rule!!") + } else if curRule.ToPort == "" { + return false, errors.New("Failed to Find 'ToPort' Value in the requested rule!!") + } else if curRule.CIDR == "" { + return false, errors.New("Failed to Find 'CIDR' Value in the requested rule!!") + } + + var ruleDirection string + if strings.EqualFold(curRule.Direction, "inbound") { + ruleDirection = "inbound" + } else if strings.EqualFold(curRule.Direction, "outbound") { + ruleDirection = "outbound" + } else { + return false, errors.New("Specified Invalid Security Rule Direction!!") + } + + if strings.EqualFold(ruleDirection, "inbound") { + protocolType := strings.ToUpper(curRule.IPProtocol) // Caution : Valid values : [TCP, UDP, ICMP] + + if strings.EqualFold(protocolType, "ALL") { + if strings.EqualFold(curRule.FromPort, "-1") && strings.EqualFold(curRule.ToPort, "-1") { + allProtocolTypeCode := []string {"TCP", "UDP", "ICMP"} + var allPortRange string + allCIDR := "0.0.0.0/0" + + for _, curProtocolType := range allProtocolTypeCode { + if strings.EqualFold(curProtocolType, "ICMP") { + allPortRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + allPortRange = "1-65535" // All Range + } + + var ruleParameterList []*vserver.RemoveAccessControlGroupRuleParameter + ruleParameter := vserver.RemoveAccessControlGroupRuleParameter { + IpBlock: &allCIDR, + PortRange: &allPortRange, + ProtocolTypeCode: &curProtocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + inboundReq := vserver.RemoveAccessControlGroupInboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgInboundRule, err := securityHandler.VMClient.V2Api.RemoveAccessControlGroupInboundRule(&inboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgInboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return false, err + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Infof("Succeeded in Removing the [%s] Inbound Rule!!", curProtocolType) + + time.Sleep(time.Second * 5) // Caution!! + } + } else { + return false, errors.New("To Specify 'All Traffic Allow Rule', Specify '-1' as FromPort/ToPort!!") + } + } else { + var portRange string + + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else if strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) // string + } else if !strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) + "-"+ strings.ToLower(curRule.ToPort) // string + } + + if strings.EqualFold(curRule.FromPort, "-1") || strings.EqualFold(curRule.ToPort, "-1") { + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + portRange = "1-65535" // All Range + } + } + + var ruleParameterList []*vserver.RemoveAccessControlGroupRuleParameter + ruleParameter := vserver.RemoveAccessControlGroupRuleParameter { + IpBlock: &curRule.CIDR, + PortRange: &portRange, + ProtocolTypeCode: &protocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + inboundReq := vserver.RemoveAccessControlGroupInboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgInboundRule, err := securityHandler.VMClient.V2Api.RemoveAccessControlGroupInboundRule(&inboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgInboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return false, err + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Infof("Succeeded in Removing the [%s] Inbound Rule!!", protocolType) + } + } + + if strings.EqualFold(ruleDirection, "outbound") { + protocolType := strings.ToUpper(curRule.IPProtocol) // Caution : Valid values : [TCP, UDP, ICMP] + + if strings.EqualFold(protocolType, "ALL") { + if strings.EqualFold(curRule.FromPort, "-1") && strings.EqualFold(curRule.ToPort, "-1") { + allProtocolTypeCode := []string {"TCP", "UDP", "ICMP"} + var allPortRange string // All Range + allCIDR := "0.0.0.0/0" + + for _, curProtocolType := range allProtocolTypeCode { + if strings.EqualFold(curProtocolType, "ICMP") { + allPortRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + allPortRange = "1-65535" // All Range + } + + var ruleParameterList []*vserver.RemoveAccessControlGroupRuleParameter + ruleParameter := vserver.RemoveAccessControlGroupRuleParameter { + IpBlock: &allCIDR, + PortRange: &allPortRange, + ProtocolTypeCode: &curProtocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + outboundReq := vserver.RemoveAccessControlGroupOutboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgOutboundRule, err := securityHandler.VMClient.V2Api.RemoveAccessControlGroupOutboundRule(&outboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgOutboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return false, err + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Infof("Succeeded in Removing the [%s] Outbound Rule!!", curProtocolType) + + time.Sleep(time.Second * 5) // Caution!! + } + } else { + return false, errors.New("To Specify 'All Traffic Allow Rule', Specify '-1' as FromPort/ToPort!!") + } + } else { + var portRange string + + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else if strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) // string + } else if !strings.EqualFold(curRule.FromPort, curRule.ToPort) { + portRange = strings.ToLower(curRule.FromPort) + "-"+ strings.ToLower(curRule.ToPort) // string + } + + if strings.EqualFold(curRule.FromPort, "-1") || strings.EqualFold(curRule.ToPort, "-1") { + if strings.EqualFold(curRule.IPProtocol, "ICMP") { + portRange = "" // string. In case protocolTypeCode is 'ICMP', Do Not input Value + } else { + portRange = "1-65535" // All Range + } + } + + var ruleParameterList []*vserver.RemoveAccessControlGroupRuleParameter + ruleParameter := vserver.RemoveAccessControlGroupRuleParameter { + IpBlock: &curRule.CIDR, + PortRange: &portRange, + ProtocolTypeCode: &protocolType, + } + ruleParameterList = append(ruleParameterList, &ruleParameter) + + // Create Inbound Security Rule + outboundReq := vserver.RemoveAccessControlGroupOutboundRuleRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: &sgNo, + VpcNo: &vpcNo, + AccessControlGroupRuleList: ruleParameterList, + } + + callLogStart := call.Start() + sgOutboundRule, err := securityHandler.VMClient.V2Api.RemoveAccessControlGroupOutboundRule(&outboundReq) + if err != nil { + cblogger.Error(err) + cblogger.Error(*sgOutboundRule.ReturnMessage) + LoggingError(callLogInfo, err) + return false, err + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Infof("Succeeded in Removing the [%s] Outbound Rule!!", protocolType) + } + } + } + + // Return Current S/G Info. + sgInfo, err := securityHandler.GetSecurity(irs.IID{SystemId: sgNo}) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + return false, err + } + spew.Dump(sgInfo) + + return true, nil +} + +func (securityHandler *NcpVpcSecurityHandler) OpenOutboundAllProtocol(sgIID irs.IID) (error) { + cblogger.Info("NCP VPC cloud driver: called OpenOutboundAllProtocol()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(securityHandler.RegionInfo.Zone, call.SECURITYGROUP, sgIID.SystemId, "OpenOutboundAllProtocol()") + + reqRules := []irs.SecurityRuleInfo { + { + Direction: "outbound", + IPProtocol: "ALL", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }, + } + _, err := securityHandler.AddRules(sgIID, &reqRules) + if err != nil { + newErr := fmt.Errorf("Failed to Add Outbound Protocol Opening Rule. : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return newErr + } + + return nil +} + +func (securityHandler *NcpVpcSecurityHandler) MappingSecurityInfo(ncpVpcSG vserver.AccessControlGroup) (irs.SecurityInfo, error) { + cblogger.Info("NCP VPC cloud driver: called MappingSecurityInfo()!") + + sgRuleList, ruleInfoErr := securityHandler.ExtractSecurityRuleInfo(ncloud.StringValue(ncpVpcSG.AccessControlGroupNo)) + if ruleInfoErr != nil { + cblogger.Error(ruleInfoErr) + return irs.SecurityInfo{}, ruleInfoErr + } + + securityInfo := irs.SecurityInfo{ + IId: irs.IID{NameId: ncloud.StringValue(ncpVpcSG.AccessControlGroupName), SystemId: ncloud.StringValue(ncpVpcSG.AccessControlGroupNo)}, + VpcIID: irs.IID{SystemId: ncloud.StringValue(ncpVpcSG.VpcNo)}, + SecurityRules: &sgRuleList, + + KeyValueList: []irs.KeyValue{ + {Key: "SecurityGroupDescription", Value: ncloud.StringValue(ncpVpcSG.AccessControlGroupDescription)}, + {Key: "SecurityGroupStatus", Value: ncloud.StringValue(ncpVpcSG.AccessControlGroupStatus.CodeName)}, + {Key: "IsDefault", Value: strconv.FormatBool(*ncpVpcSG.IsDefault)}, + }, + } + return securityInfo, nil +} + +// Search NCP VPC SecurityGroup Rule List +func (securityHandler *NcpVpcSecurityHandler) ExtractSecurityRuleInfo(ncpVpcSGId string) ([]irs.SecurityRuleInfo, error) { + var securityRuleList []irs.SecurityRuleInfo + + sgRuleReq := vserver.GetAccessControlGroupRuleListRequest { + RegionCode: &securityHandler.RegionInfo.Region, + AccessControlGroupNo: ncloud.String(ncpVpcSGId), + } + ruleListResult, err := securityHandler.VMClient.V2Api.GetAccessControlGroupRuleList(&sgRuleReq) + if err != nil { + cblogger.Error(*ruleListResult.ReturnMessage) + return nil, err + } + if *ruleListResult.TotalRows < 1 { + cblogger.Infof("$$$ The S/G [%s] contains No Rule!!", ncpVpcSGId) + return nil, nil // Caution!! + } + + for _, curRule := range ruleListResult.AccessControlGroupRuleList { + curRuleInfo := irs.SecurityRuleInfo { + IPProtocol: ncloud.StringValue(curRule.ProtocolType.CodeName), + Direction: strings.ToLower(ncloud.StringValue(curRule.AccessControlGroupRuleType.CodeName)), + CIDR: ncloud.StringValue(curRule.IpBlock), + } + + if strings.EqualFold(curRuleInfo.IPProtocol, "icmp") { + curRuleInfo.FromPort = "-1" // string + curRuleInfo.ToPort = "-1" // string + } else if strings.Contains(ncloud.StringValue(curRule.PortRange), "-") { + portNo := strings.Split(ncloud.StringValue(curRule.PortRange), "-") + + curRuleInfo.FromPort = portNo[0] // string + curRuleInfo.ToPort = portNo[1] // string + } else { + curRuleInfo.FromPort = ncloud.StringValue(curRule.PortRange) + curRuleInfo.ToPort = ncloud.StringValue(curRule.PortRange) + } + + securityRuleList = append(securityRuleList, curRuleInfo) + } + return securityRuleList, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VMHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VMHandler.go new file mode 100644 index 000000000..e925af0cf --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/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 VPC VM Handler +// +// by ETRI, 2020.12. +// by ETRI, 2022.02. updated +//================================================================================================== + +package resources + +import ( + "errors" + "fmt" + // "reflect" + "strings" + "strconv" + "time" + "os" + "io" + // "github.com/davecgh/go-spew/spew" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + + 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" + keycommon "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/common" +) + +type NcpVpcVMHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +const ( + lnxUserName string = "cb-user" + winUserName string = "Administrator" + ubuntuCloudInitFilePath string = "/cloud-driver-libs/.cloud-init-ncpvpc/cloud-init" + centosCloudInitFilePath string = "/cloud-driver-libs/.cloud-init-ncpvpc/cloud-init-centos" + winCloudInitFilePath string = "/cloud-driver-libs/.cloud-init-ncpvpc/cloud-init-windows" + LnxTypeOs string = "LNX" // LNX (LINUX) + WinTypeOS string = "WND" // WND (WINDOWS) +) + +// Already declared in CommonNcpFunc.go +// var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC VMHandler") +} + +func (vmHandler *NcpVpcVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, error) { + cblogger.Info("NCPVPC Cloud driver: called StartVM()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.CredentialInfo.ClientId, call.VM, vmReqInfo.IId.NameId, "StartVM()") + + if strings.EqualFold(vmReqInfo.IId.NameId, "") { + newErr := fmt.Errorf("Invalid VM Name required") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + + // CAUTION!! : Instance Name is Convert to lowercase.(strings.ToLower()) + // NCP VPC에서는 VM instance 이름에 영문 대문자 허용 안되므로 여기서 소문자로 변환하여 반영.(대문자 : Error 발생) + instanceName := strings.ToLower(vmReqInfo.IId.NameId) + instanceType := vmReqInfo.VMSpecName + keyPairId := vmReqInfo.KeyPairIID.SystemId + vpcId := vmReqInfo.VpcIID.SystemId + subnetId := vmReqInfo.SubnetIID.SystemId + minCount := ncloud.Int32(1) + + var publicImageId string + var myImageId string + var initScriptNo *string + + if vmReqInfo.ImageType == irs.PublicImage || vmReqInfo.ImageType == "" || vmReqInfo.ImageType == "default" { + imageHandler := NcpVpcImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + + isPublicImage, err := imageHandler.isPublicImage(vmReqInfo.ImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) + cblogger.Error(newErr.Error()) + 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 := imageHandler.CheckWindowsImage(vmReqInfo.ImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is MS Windows Image : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + if isPublicWindowsImage { + var createErr error + initScriptNo, createErr = vmHandler.CreateWinInitScript(vmReqInfo.VMUserPasswd) + if createErr != nil { + newErr := fmt.Errorf("Failed to Create Cloud-Init Script with the Password : [%v]", createErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + } else { + var createErr error + initScriptNo, createErr = vmHandler.CreateLinuxInitScript(vmReqInfo.ImageIID, keyPairId) + if createErr != nil { + newErr := fmt.Errorf("Failed to Create Cloud-Init Script with the KeyPairId : [%v]", createErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + } + } else { + imageHandler := NcpVpcImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + isPublicImage, err := imageHandler.isPublicImage(vmReqInfo.ImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) + cblogger.Error(newErr.Error()) + 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 + } + + myImageHandler := NcpVpcMyImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + isMyWindowsImage, err := myImageHandler.CheckWindowsImage(vmReqInfo.ImageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether My Image is MS Windows Image : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + if isMyWindowsImage { + var createErr error + initScriptNo, createErr = vmHandler.CreateWinInitScript(vmReqInfo.VMUserPasswd) + if createErr != nil { + newErr := fmt.Errorf("Failed to Create Cloud-Init Script with the Password : [%v]", createErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + } else { + var createErr error + initScriptNo, createErr = vmHandler.CreateLinuxInitScript(vmReqInfo.ImageIID, keyPairId) + if createErr != nil { + newErr := fmt.Errorf("Failed to Create Cloud-Init Script with the KeyPairId : [%v]", createErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + } + } + cblogger.Infof("Init Script No : [%s]", *initScriptNo) + + // Check whether the VM name exists + // Search by instanceName converted to lowercase + vmId, getErr := vmHandler.GetVmIdByName(instanceName) + if getErr != nil { + newErr := fmt.Errorf("Failed to Get VmId with the Name : [%s], [%v]", instanceName, getErr) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if vmId != "" { + newErr := fmt.Errorf("The VM Name [%s] is already In Use.", instanceName) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + + //========================================================= + // Security Group IID(SystemId 기반) 변환 -> []*string 으로 + //========================================================= + cblogger.Info("Convert : Security Group IID -> []*string") + var securityGroupIds []*string + + for _, sgID := range vmReqInfo.SecurityGroupIIDs { + cblogger.Infof("Security Group IID : [%s]", sgID) + securityGroupIds = append(securityGroupIds, ncloud.String(sgID.SystemId)) + } + + type intType struct { + nicOrder *int32 + } + + temp := int32(0) // Convert Int data type to Int32 !! + i32 := intType{ + nicOrder: &temp, + } + fmt.Println(*i32.nicOrder) + + //========================================================= + // VM Creation info. setting + //========================================================= + cblogger.Info("# Start to Create NCP VPC VM Instance!!") + cblogger.Info("Preparation of CreateServerInstancesRequest!!") + + instanceReq := vserver.CreateServerInstancesRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + ServerName: ncloud.String(instanceName), + ServerImageProductCode: ncloud.String(publicImageId), + MemberServerImageInstanceNo: ncloud.String(myImageId), + ServerProductCode: ncloud.String(instanceType), + ServerDescription: ncloud.String(vmReqInfo.ImageIID.SystemId), // Caution!! + LoginKeyName: ncloud.String(keyPairId), + VpcNo: ncloud.String(vpcId), + SubnetNo: ncloud.String(subnetId), + + // ### Caution!! : AccessControlGroup은 NCPVPC console의 VPC > 'Network ACL'이 아닌 Server > 'ACG'에 해당됨. + NetworkInterfaceList: []*vserver.NetworkInterfaceParameter{ + { NetworkInterfaceOrder: i32.nicOrder, AccessControlGroupNoList: securityGroupIds}, + // NetworkInterfaceNo를 입력하지 않으면 NetworkInterface가 자동 생성되어 적용됨. + }, + + IsProtectServerTermination: ncloud.Bool(false), // NOTE Caution!! : 'true'로 설정하면 API로 Terminate(VM 반환) 제어 안됨. + ServerCreateCount: minCount, + InitScriptNo: initScriptNo, + } + // cblogger.Info(instanceReq) + + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.CreateServerInstances(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create VM instance : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + scriptDelResult, err := vmHandler.DeleteInitScript(initScriptNo) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the Cloud-Init Script with the initScriptNo : [%s], [%v]", ncloud.StringValue(initScriptNo), err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + cblogger.Infof("DeleteInitScript Result : [%s]", *scriptDelResult) + return irs.VMInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + newVMIID := irs.IID{SystemId: ncloud.StringValue(runResult.ServerInstanceList[0].ServerInstanceNo)} + + //========================================= + // Wait for VM information to be inquired + //========================================= + cblogger.Infof("# Waitting while Initializing New VM!!") + time.Sleep(time.Second * 15) // Waitting Before Getting New VM Status Info!! + + curStatus, errStatus := vmHandler.WaitToGetInfo(newVMIID) // # Waitting while Creating VM!!") + if errStatus != nil { + cblogger.Error(errStatus.Error()) + LoggingError(callLogInfo, errStatus) + return irs.VMInfo{}, errStatus + } + cblogger.Infof("==> VM [%s] status : [%s]", newVMIID.SystemId, curStatus) + cblogger.Info("VM Creation Processes are Finished !!") + + scriptDelResult, err := vmHandler.DeleteInitScript(initScriptNo) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the Cloud-Init Script with the initScriptNo : [%s], [%v]", ncloud.StringValue(initScriptNo), err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + cblogger.Infof("DeleteInitScript Result : [%s]", *scriptDelResult) + + vmInfo, error := vmHandler.GetVM(newVMIID) + if error != nil { + newErr := fmt.Errorf("Failed to Get the New VM Info with the VM ID : [%s], [%v]", newVMIID.SystemId, error) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + + if vmInfo.Platform == irs.WINDOWS { + vmInfo.VMUserPasswd = vmReqInfo.VMUserPasswd + } + + return vmInfo, nil +} + +func (vmHandler *NcpVpcVMHandler) GetVM(vmIID irs.IID) (irs.VMInfo, error) { + cblogger.Info("NCPVPC Cloud driver: called GetVM()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "GetVM()") + + if strings.EqualFold(vmIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId required") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + instanceNumList := []*string{ncloud.String(vmIID.SystemId),} + + curStatus, statusErr := vmHandler.GetVMStatus(vmIID) + if statusErr != nil { + newErr := fmt.Errorf("Failed to Get the VM Status with the VM ID : [%s], [%v]", vmIID.SystemId, statusErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + + cblogger.Infof("===> VM Status : [%s]", curStatus) + + // Since it's impossible to get VM info. during Creation, ... + switch string(curStatus) { + case "Creating", "Booting": + cblogger.Infof("The VM status is '%s', so wait for the VM creation before inquiring the info.", string(curStatus)) + return irs.VMInfo{}, errors.New("The VM status is 'Creating' or 'Booting', so wait for the VM creation before inquiring the info. : " + vmIID.SystemId) + + default: + cblogger.Infof("===> The VM status is not 'Creating' or 'Booting', you can get the VM info.") + } + + /* + newVMIID := irs.IID{SystemId: systemId} + + curStatus, errStatus := vmHandler.WaitToGetInfo(newVMIID) + if errStatus != nil { + cblogger.Error(errStatus.Error()) + return irs.VMInfo{}, nil + } + */ + + instanceReq := vserver.GetServerInstanceListRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: instanceNumList, + } + + start := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find VM Instance List from NCP VPC!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + LoggingInfo(callLogInfo, start) + + if *result.TotalRows < 1 { + cblogger.Info("### VM instance does Not Exist!!") + } + + vmInfo, err := vmHandler.MappingServerInfo(result.ServerInstanceList[0]) + if err != nil { + newErr := fmt.Errorf("Failed to Map the VM Info!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMInfo{}, newErr + } + return vmInfo, nil +} + +func (vmHandler *NcpVpcVMHandler) SuspendVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCPVPC Cloud driver: called SuspendVM()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "SuspendVM()") + + if strings.EqualFold(vmIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId required") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed"), newErr + } + + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + serverInstanceNo := []*string{ncloud.String(vmIID.SystemId)} + + var resultStatus string + + cblogger.Info("Start to Get VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + cblogger.Errorf("Failed to Get the VM Status of [%s]", vmIID.SystemId) + cblogger.Error(err) + } else { + cblogger.Infof("Succeed 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]) + + req := vserver.StopServerInstancesRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: serverInstanceNo, + } + + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.StopServerInstances(&req) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + return irs.VMStatus("Failed"), err + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + } + return irs.VMStatus("Suspending"), nil +} + +func (vmHandler *NcpVpcVMHandler) ResumeVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCPVPC Cloud driver: called ResumeVM()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "ResumeVM()") + + if strings.EqualFold(vmIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId required") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed"), newErr + } + + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + serverInstanceNo := []*string{ncloud.String(vmIID.SystemId)} + + var resultStatus string + + cblogger.Info("Start to Get the VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + cblogger.Errorf("Failed to Get the VM Status of [%s]", vmIID.SystemId) + cblogger.Error(err) + } else { + cblogger.Infof("Succeed 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]) + + req := vserver.StartServerInstancesRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: serverInstanceNo, + } + + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.StartServerInstances(&req) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + return irs.VMStatus("Failed"), err + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + + return irs.VMStatus("Resuming"), nil + } +} + +func (vmHandler *NcpVpcVMHandler) RebootVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCPVPC Cloud driver: called RebootVM()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "RebootVM()") + + if strings.EqualFold(vmIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId required") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed"), newErr + } + + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + serverInstanceNo := []*string{ncloud.String(vmIID.SystemId)} + + var resultStatus string + + cblogger.Info("Start to Get the VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + cblogger.Errorf("Failed to Get the VM Status of [%s]", vmIID.SystemId) + cblogger.Error(err) + } else { + cblogger.Infof("Succeed in Getting the VM Status of [%s] : [%s]", vmIID.SystemId, 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 { + cblogger.Infof("vmID : [%s]", *serverInstanceNo[0]) + + req := vserver.RebootServerInstancesRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: serverInstanceNo, + } + + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.RebootServerInstances(&req) + if err != nil { + newErr := fmt.Errorf("Failed to Reboot the VM Instance on NCP VPC!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed. "), newErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Info(runResult) + + return irs.VMStatus("Rebooting"), nil + } +} + +func (vmHandler *NcpVpcVMHandler) TerminateVM(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCPVPC Cloud driver: called TerminateVM()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "TerminateVM()") + + if strings.EqualFold(vmIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId required") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed"), newErr + } + + cblogger.Infof("vmID : [%s]", vmIID.SystemId) + serverInstanceNos := []*string{ncloud.String(vmIID.SystemId),} + + cblogger.Info("Start to Get the VM Status...") + vmStatus, err := vmHandler.GetVMStatus(vmIID) + if err != nil { + LoggingError(callLogInfo, err) + cblogger.Errorf("Failed to Get the VM Status of [%s]", vmIID.SystemId) + cblogger.Error(err) + } else { + cblogger.Infof("Succeed in Getting the VM Status of [%s] : [%s]", vmIID.SystemId, vmStatus) + } + + vmInfo, error := vmHandler.GetVM(vmIID) + if error != nil { + LoggingError(callLogInfo, error) + cblogger.Error(error.Error()) + + return irs.VMStatus("Failed to get the VM info"), err + } + + switch string(vmStatus) { + case "Suspended": + cblogger.Infof("VM Status : 'Suspended'. so it Can be Terminated!!") + + req := vserver.TerminateServerInstancesRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: serverInstanceNos, + } + + start := call.Start() + runResult, err := vmHandler.VMClient.V2Api.TerminateServerInstances(&req) + if err != nil { + newErr := fmt.Errorf("Failed to Terminate the VM instance on NCP VPC. : [%v]", err) + cblogger.Error(newErr.Error()) + cblogger.Error(*runResult.ReturnMessage) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed to Terminate!!"), newErr + } + LoggingInfo(callLogInfo, start) + 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 { + cblogger.Error(err) + return vmStatus, err + } + } + + return irs.VMStatus("Terminating"), nil + + case "Running": + cblogger.Infof("VM Status : 'Running'. so it Can be Terminated AFTER SUSPENSION !!") + cblogger.Infof("vmID : [%s]", *serverInstanceNos[0]) + + cblogger.Info("Start Suspend VM !!") + result, err := vmHandler.SuspendVM(vmIID) + if err != nil { + cblogger.Errorf("Failed to Suspend the VM [%s] : [%s]", vmIID.SystemId, result) + cblogger.Error(err) + } else { + cblogger.Infof("Succeed in Suspending the VM [%s] : [%s]", vmIID.SystemId, result) + } + + //=================================== + // 15-second wait for Suspending + //=================================== + curRetryCnt := 0 + maxRetryCnt := 15 + for { + curStatus, errStatus := vmHandler.GetVMStatus(vmIID) + if errStatus != nil { + cblogger.Error(errStatus.Error()) + } + + cblogger.Infof("===> VM Status : [%s]", curStatus) + if curStatus != irs.VMStatus("Suspended") { + curRetryCnt++ + cblogger.Infof("The VM is not 'Suspended' yet, 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") + + req := vserver.TerminateServerInstancesRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: serverInstanceNos, + } + + callLogStart := call.Start() + runResult, err := vmHandler.VMClient.V2Api.TerminateServerInstances(&req) + if err != nil { + newErr := fmt.Errorf("Failed to Terminate the VM instance on NCP VPC. : [%v]", err) + cblogger.Error(newErr.Error()) + cblogger.Error(*runResult.ReturnMessage) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed to Terminate!!"), newErr + } + 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 { + cblogger.Error(err) + return vmStatus, err + } + } + + return irs.VMStatus("Terminating"), nil + + default: + resultStatus := "The VM status is not 'Running' or 'Suspended' yet. so it Can NOT be Terminated!! Run or Suspend the VM before terminating." + + cblogger.Error(resultStatus) + return irs.VMStatus("Failed. " + resultStatus), err + } +} + +/* +# NCP serverInstanceStatusName +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 VPC vmStatus to Convert : [%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("VM Status Conversion Completed : [%s] ==> [%s]", vmStatus, resultStatus) + + return irs.VMStatus(resultStatus), nil +} + +func (vmHandler *NcpVpcVMHandler) GetVMStatus(vmIID irs.IID) (irs.VMStatus, error) { + cblogger.Info("NCPVPC Cloud driver: called GetVMStatus()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, vmIID.NameId, "GetVMStatus()") + + if strings.EqualFold(vmIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VM SystemId required") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed"), newErr + } + + cblogger.Infof("VM SystemId : [%s]", vmIID.SystemId) + systemId := vmIID.SystemId + + // instanceReq := vserver.GetServerInstanceListRequest{ + // ServerInstanceNoList: []*string{nil}, + // } + instanceReq := vserver.GetServerInstanceListRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: []*string{ + ncloud.String(systemId), + }, + } + + callLogStart := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find VM Instance List from NCP VPC!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VMStatus("Failed. "), newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + cblogger.Info("The VM instance does Not Exist!!") + return irs.VMStatus("Not Exist!!"), nil //Caution!! + } else { + cblogger.Info("Succeeded in Getting ServerInstanceList from NCP VPC!!") + } + + for _, vm := range result.ServerInstanceList { + //*vm.ServerInstanceStatusName + vmStatus, errStatus := ConvertVMStatusString(*vm.ServerInstanceStatusName) + cblogger.Infof("VM Status of [%s] : [%s]", systemId, vmStatus) + return vmStatus, errStatus + } + + return irs.VMStatus("Failed."), errors.New("Failed to Get the VM Status info!!") +} + +func (vmHandler *NcpVpcVMHandler) ListVMStatus() ([]*irs.VMStatusInfo, error) { + cblogger.Info("NCPVPC Cloud driver: called ListVMStatus()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, "ListVMStatus()", "ListVMStatus()") + + var vmStatusList []*irs.VMStatusInfo + + instanceReq := vserver.GetServerInstanceListRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: []*string{}, + } + + callLogStart := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find VM Instance List from NCP VPC!! : [%v]", err) + cblogger.Error(newErr.Error()) + cblogger.Error(*result.ReturnMessage) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Info("Succeeded in Getting ServerInstanceList from NCP VPC!!") + + for _, vm := range result.ServerInstanceList { + //*vm.ServerInstanceStatusName + //*vm.ServerName + vmStatus, _ := ConvertVMStatusString(*vm.ServerInstanceStatusName) + + 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, nil +} + +func (vmHandler *NcpVpcVMHandler) ListVM() ([]*irs.VMInfo, error) { + cblogger.Info("NCPVPC Cloud driver: called ListVM()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Zone, call.VM, "ListVMS()", "ListVM()") + + var vmInfoList []*irs.VMInfo + + instanceReq := vserver.GetServerInstanceListRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + ServerInstanceNoList: []*string{}, + // ServerInstanceNoList: []*string{ + // nil, + // }, + } + + callLogStart := call.Start() + result, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get VM Instance List from NCP VPC!! : [%v]", err) + cblogger.Error(newErr.Error()) + cblogger.Error(*result.ReturnMessage) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Info("Succeeded in Getting ServerInstanceList from NCP VPC!!") + + for _, vm := range result.ServerInstanceList { + cblogger.Infof("Inquiry of NCP VM Instance info : [%s]", *vm.ServerInstanceNo) + + curStatus, errStatus := vmHandler.GetVMStatus(irs.IID{SystemId: *vm.ServerInstanceNo}) + if errStatus != nil { + cblogger.Errorf("Failed to Get the VM Status of VM : [%s]", *vm.ServerInstanceNo) + cblogger.Error(errStatus.Error()) + } else { + cblogger.Infof("Succeed in Getting the VM Status of [%s] : [%s]", *vm.ServerInstanceNo, curStatus) + } + + cblogger.Infof("===> VM Status : [%s]", curStatus) + + switch string(curStatus) { + case "Creating", "Booting": + return []*irs.VMInfo{}, 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 []*irs.VMInfo{}, error + } + + vmInfoList = append(vmInfoList, &vmInfo) + } + } + + return vmInfoList, nil +} + +func (vmHandler *NcpVpcVMHandler) MappingServerInfo(NcpInstance *vserver.ServerInstance) (irs.VMInfo, error) { + cblogger.Info("NCPVPC Cloud driver: called MappingServerInfo()!") + + var publicIp *string + var privateIp *string + var publicIpInstanceNo *string + + // cblogger.Infof("# NcpInstance Info :") + // spew.Dump(NcpInstance) + + convertedTime, err := convertTimeFormat(*NcpInstance.CreateDate) + if err != nil { + newErr := fmt.Errorf("Failed to Convert the Time Format!!") + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + + // Create a PublicIp, if the instance doesn't have a 'Public IP' after creation. + if strings.EqualFold(ncloud.StringValue(NcpInstance.PublicIp), "") { + publicIpReq := vserver.CreatePublicIpInstanceRequest{ + ServerInstanceNo: NcpInstance.ServerInstanceNo, + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + } + + // 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 { + newErr := fmt.Errorf("Failed to Create Public IP : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create Any Public IP!!") + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + + publicIp = result.PublicIpInstanceList[0].PublicIp + publicIpInstanceNo = result.PublicIpInstanceList[0].PublicIpInstanceNo + privateIp = result.PublicIpInstanceList[0].PrivateIp + + cblogger.Infof("*** PublicIp : %s ", ncloud.StringValue(publicIp)) + cblogger.Infof("Finished to Create Public IP") + } else { + publicIp = NcpInstance.PublicIp + cblogger.Infof("*** NcpInstance.PublicIp : %s ", ncloud.StringValue(publicIp)) + + instanceReq := vserver.GetPublicIpInstanceListRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + PublicIp: publicIp, + } + + // Search the Public IP list info. to get the PublicIp InstanceNo + result, err := vmHandler.VMClient.V2Api.GetPublicIpInstanceList(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find PublicIp InstanceList from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Find Any PublicIpInstance!!") + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + + publicIpInstanceNo = result.PublicIpInstanceList[0].PublicIpInstanceNo + privateIp = result.PublicIpInstanceList[0].PrivateIp + + cblogger.Infof("Finished to Get PublicIP InstanceNo") + } + + netInterfaceName, err := vmHandler.GetNetworkInterfaceName(NcpInstance.NetworkInterfaceNoList[0]) + if err != nil { + newErr := fmt.Errorf("Failed to Find NetworkInterface Name : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + + // 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. Ex) Region: "KR", Zone: "KR-2" + Region: irs.RegionInfo{ + Region: *NcpInstance.RegionCode, + Zone: *NcpInstance.ZoneCode, + }, + + VMSpecName: ncloud.StringValue(NcpInstance.ServerProductCode), //Server Spec code + + VpcIID: irs.IID{NameId: "N/A", SystemId: *NcpInstance.VpcNo}, + SubnetIID: irs.IID{NameId: "N/A", SystemId: *NcpInstance.SubnetNo}, + + SecurityGroupIIds: []irs.IID{ + {NameId: "N/A", SystemId: "N/A"}, + }, + + KeyPairIId: irs.IID{NameId: *NcpInstance.LoginKeyName, SystemId: *NcpInstance.LoginKeyName}, + NetworkInterface: *netInterfaceName, + PublicIP: *publicIp, + PrivateIP: *privateIp, + 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: "PlatformType", Value: *NcpInstance.PlatformType.CodeName}, + {Key: "PublicIpID", Value: *publicIpInstanceNo}, + }, + } + + imageHandler := NcpVpcImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + + // Set the VM Image Info + 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 := imageHandler.isPublicImage(irs.IID{SystemId: *NcpInstance.ServerDescription}) // Caution!! : Not '*NcpInstance.ServerImageProductCode' + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) + 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 { + newErr := fmt.Errorf("Failed to Find BlockStorage Info : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if !strings.EqualFold(*storageSize, "") { + vmInfo.RootDiskSize = *storageSize + } + if !strings.EqualFold(*deviceName, "") { + vmInfo.RootDeviceName = *deviceName + } + + dataDiskList, err := vmHandler.GetVmDataDiskList(NcpInstance.ServerInstanceNo) + if err != nil { + newErr := fmt.Errorf("Failed to Get Data Disk List : [%v]", err) + cblogger.Error(newErr.Error()) + return irs.VMInfo{}, newErr + } + if len(dataDiskList) > 0 { + vmInfo.DataDiskIIDs = dataDiskList + } + + // 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 *NcpVpcVMHandler) CreateLinuxInitScript(imageIID irs.IID, keyPairId string) (*string, error) { + cblogger.Info("NCPVPC Cloud driver: called CreateLinuxInitScript()!!") + + var originImagePlatform string + + imageHandler := NcpVpcImageHandler{ + RegionInfo: vmHandler.RegionInfo, + VMClient: vmHandler.VMClient, + } + isPublicImage, err := imageHandler.isPublicImage(imageIID) + if err != nil { + newErr := fmt.Errorf("Failed to Check Whether the Image is Public Image : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if isPublicImage { + if strings.Contains(strings.ToUpper(imageIID.SystemId), "UBNTU") { + originImagePlatform = "UBUNTU" + } else if strings.Contains(strings.ToUpper(imageIID.SystemId), "CNTOS") { + originImagePlatform = "CENTOS" + } else if strings.Contains(strings.ToUpper(imageIID.SystemId), "ROCKY") { + originImagePlatform = "ROCKY" + } else if strings.Contains(strings.ToUpper(imageIID.SystemId), "WND") { + originImagePlatform = "WINDOWS" + } else { + newErr := fmt.Errorf("Failed to Get OriginImageOSPlatform of the Public Image!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + } else { + myImageHandler := NcpVpcMyImageHandler{ + 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 My 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 + case "ROCKY" : + 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("NCPVPC", 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 cloud-init script + cmdString = strings.ReplaceAll(cmdString, "{{username}}", lnxUserName) + cmdString = strings.ReplaceAll(cmdString, "{{public_key}}", keyValue.Value) + // cblogger.Info("cmdString : ", cmdString) + + // Create Cloud-Init Script + // LnxTypeOs string = "LNX" // LNX (LINUX) + // WinTypeOS string = "WND" // WND (WINDOWS) + createInitReq := vserver.CreateInitScriptRequest { + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + InitScriptContent: ncloud.String(cmdString), + OsTypeCode: ncloud.String(LnxTypeOs), + } + + result, err := vmHandler.VMClient.V2Api.CreateInitScript(&createInitReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create Linux type Cloud-Init Script : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create any Linux type Cloud-Init Script!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Creating Linux type Cloud-Init Script!!") + } + return result.InitScriptList[0].InitScriptNo, nil +} + +func (vmHandler *NcpVpcVMHandler) CreateWinInitScript(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 cloud-init script + cmdString = strings.ReplaceAll(cmdString, "{{PASSWORD}}", passWord) + // cblogger.Info("cmdString : ", cmdString) + + // Create Cloud-Init Script + // LnxTypeOs string = "LNX" // LNX (LINUX) + // WinTypeOS string = "WND" // WND (WINDOWS) + createInitReq := vserver.CreateInitScriptRequest { + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + InitScriptContent: ncloud.String(cmdString), + OsTypeCode: ncloud.String(WinTypeOS), + } + + result, err := vmHandler.VMClient.V2Api.CreateInitScript(&createInitReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create Windows Cloud-Init Script : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create any Windows Cloud-Init Script!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Creating Windows Cloud-Init Script!!") + } + return result.InitScriptList[0].InitScriptNo, nil +} + +func (vmHandler *NcpVpcVMHandler) DeleteInitScript(initScriptNum *string) (*string, error) { + cblogger.Info("NCPVPC Cloud driver: called DeleteInitScript()!!") + + InitScriptNums := []*string{initScriptNum,} + + // Delete Cloud-Init Script + deleteInitReq := vserver.DeleteInitScriptsRequest { + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + InitScriptNoList: InitScriptNums, + } + + result, err := vmHandler.VMClient.V2Api.DeleteInitScripts(&deleteInitReq) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the Cloud-Init Script : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Delete any Cloud-Init Script!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Deleting the Cloud-Init Script!!") + } + return result.ReturnMessage, nil +} + +// Waiting for up to 500 seconds until VM info. can be Get +func (vmHandler *NcpVpcVMHandler) 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, errStatus := vmHandler.GetVMStatus(vmIID) + if errStatus != nil { + cblogger.Errorf("Failed to Get the VM Status of [%s]", vmIID.SystemId) + cblogger.Error(errStatus.Error()) + } else { + cblogger.Infof("Succeeded in Getting the Status of VM [%s] : [%s]", vmIID.SystemId, curStatus) + } + + cblogger.Infof("===> VM Status : [%s]", curStatus) + + switch string(curStatus) { + case "Creating", "Booting": + + curRetryCnt++ + cblogger.Infof("The VM is '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 status not 'Creating', stopping the waiting.") + return irs.VMStatus(curStatus), nil + } + } +} + +// Waiting for up to 600 seconds until Public IP can be Deleted. +func (vmHandler *NcpVpcVMHandler) 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.SystemId) + 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]", vmIID.SystemId) + } + + cblogger.Infof("===> VM Status [%s] : ", 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 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 Termination is finished, so stopping the waiting.") + return irs.VMStatus(curStatus), nil + } + } +} + +// Whenever a VM is terminated, Delete the public IP that the VM has +func (vmHandler *NcpVpcVMHandler) DeletePublicIP(vmInfo irs.VMInfo) (irs.VMStatus, error) { + cblogger.Info("NCPVPC Cloud driver: called DeletePublicIP()!") + + var publicIPId string + + for _, keyInfo := range vmInfo.KeyValueList { + if keyInfo.Key == "PublicIpID" { + publicIPId = keyInfo.Value + break + } + } + + cblogger.Infof("vmInfo.PublicIP : [%s]", vmInfo.PublicIP) + cblogger.Infof("publicIPId : [%s]", 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 := vserver.DeletePublicIpInstanceRequest{ + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), // $$$ Caution!! + PublicIpInstanceNo: ncloud.String(publicIPId), + } + + cblogger.Infof("DeletePublicIPReq Ready!!") + + result, err := vmHandler.VMClient.V2Api.DeletePublicIpInstance(&deleteReq) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the Public IP of the VM instance. : [%v]", err) + cblogger.Error(newErr.Error()) + cblogger.Error(*result.ReturnMessage) + return irs.VMStatus("Failed. "), newErr + } + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Delete any Public IP of the VM instance.") + cblogger.Error(newErr.Error()) + return irs.VMStatus("Failed. "), newErr + } else { + cblogger.Infof("Succeed in Deleting the PublicIP of the instance. : [%s]", vmInfo.PublicIP) + } + + return irs.VMStatus("Terminating"), nil +} + +func (vmHandler *NcpVpcVMHandler) 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 := vserver.GetBlockStorageInstanceListRequest { + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + 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 *NcpVpcVMHandler) GetVmDataDiskList(vmId *string) ([]irs.IID, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetVmDataDiskList()") + + if strings.EqualFold(*vmId, "") { + newErr := fmt.Errorf("Invalid VM Instance ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + storageReq := vserver.GetBlockStorageInstanceListRequest { + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + 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 *storageResult.TotalRows < 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 *NcpVpcVMHandler) GetNetworkInterfaceName(netInterfaceNo *string) (*string, error) { + cblogger.Info("NCPVPC Cloud driver: called GetNetworkInterfaceName()!!") + + if strings.EqualFold(*netInterfaceNo, "") { + newErr := fmt.Errorf("Invalid Net Interface ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + netReq := vserver.GetNetworkInterfaceDetailRequest { + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + NetworkInterfaceNo: netInterfaceNo, + } + netResult, err := vmHandler.VMClient.V2Api.GetNetworkInterfaceDetail(&netReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get NetworkInterface Info!! : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + if *netResult.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Get any NetworkInterface Info with the Network Interface ID!! : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting NetworkInterface Info!!") + } + + return netResult.NetworkInterfaceList[0].DeviceName, nil +} + +func (vmHandler *NcpVpcVMHandler) GetVmIdByName(vmNameId string) (string, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetVmIdByName()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Region, call.VM, vmNameId, "GetVmIdByName()") + + if strings.EqualFold(vmNameId, "") { + newErr := fmt.Errorf("Invalid VM Instance ID!!") + cblogger.Error(newErr.Error()) + return "", newErr + } + + instanceListReq := vserver.GetServerInstanceListRequest{ + RegionCode: &vmHandler.RegionInfo.Region, + } + + callLogStart := call.Start() + instanceResult, err := vmHandler.VMClient.V2Api.GetServerInstanceList(&instanceListReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get VM Instance List from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return "", newErr + } + LoggingInfo(callLogInfo, callLogStart) + + // Search by Name in the VM list + var vmId string + if *instanceResult.TotalRows < 1 { + cblogger.Info("### VM Instance does Not Exist on NCP VPC!!") + } else { + cblogger.Info("Succeeded in Getting VM Instance List from NCP VPC.") + for _, vm := range instanceResult.ServerInstanceList { + if strings.EqualFold(*vm.ServerName, vmNameId) { + vmId = *vm.ServerInstanceNo + break + } + } + + if strings.EqualFold(vmId, "") { + cblogger.Info("### VM Instance does Not Exist with the Name!!") + } + } + return vmId, nil +} + +func (vmHandler *NcpVpcVMHandler) GetNcpVMInfo(instanceId string) (*vserver.ServerInstance, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNcpVMInfo()") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vmHandler.RegionInfo.Region, call.VM, instanceId, "GetNcpVMInfo()") + + if strings.EqualFold(instanceId, "") { + newErr := fmt.Errorf("Invalid VM Instance ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + instanceReq := vserver.GetServerInstanceDetailRequest{ + RegionCode: &vmHandler.RegionInfo.Region, + ServerInstanceNo: &instanceId, // *** Required (Not Optional) + } + + callLogStart := call.Start() + instanceResult, err := vmHandler.VMClient.V2Api.GetServerInstanceDetail(&instanceReq) + if err != nil { + newErr := fmt.Errorf("Failed to Find the VM Instance Info from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *instanceResult.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Find Any NCP VPC VM Instance Info!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Info("Succeeded in Getting NCP VPC VM Instance Info.") + } + + return instanceResult.ServerInstanceList[0], nil +} + +func (vmHandler *NcpVpcVMHandler) GetRootPassword(vmId *string, privateKey *string) (*string, error) { + cblogger.Info("NCPVPC Cloud driver: called GetRootPassword()!!") + + if strings.EqualFold(*vmId, "") { + newErr := fmt.Errorf("Invalid VM Instance ID!!") + cblogger.Error(newErr.Error()) + return nil, newErr + } + + pwdReq := vserver.GetRootPasswordRequest { + RegionCode: ncloud.String(vmHandler.RegionInfo.Region), + ServerInstanceNo: vmId, + PrivateKey: privateKey, + } + result, err := vmHandler.VMClient.V2Api.GetRootPassword(&pwdReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get the Root Password of the VM!! : [%v]", err) + cblogger.Error(newErr.Error()) + return nil, newErr + } + return result.RootPassword, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VMSpecHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VMSpecHandler.go new file mode 100644 index 000000000..0edd8a201 --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VMSpecHandler.go @@ -0,0 +1,246 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VPC VMSpec Handler +// +// by ETRI, 2020.12. + +package resources + +import ( + "errors" + "strconv" + // "github.com/davecgh/go-spew/spew" + + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vserver" + 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 NcpVpcVMSpecHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VMClient *vserver.APIClient +} + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPC VMSpecHandler") +} + +func (vmSpecHandler *NcpVpcVMSpecHandler) ListVMSpec() ([]*irs.VMSpecInfo, error) { + cblogger.Info("NCP VPC Cloud driver: called ListVMSpec()!") + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, "ListVMSpec()", "ListVMSpec()") + + imageHandler := NcpVpcImageHandler{ + RegionInfo: vmSpecHandler.RegionInfo, //CAUTION!! + VMClient: vmSpecHandler.VMClient, + } + imgListResult, err := imageHandler.ListImage() + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Image Info list : : ", err) + return nil, rtnErr + } else { + cblogger.Infof("Image list Count of the Region : [%d]", len(imgListResult)) + } + + var vmSpecInfoList []*irs.VMSpecInfo + for _, image := range imgListResult { + cblogger.Infof("\n### 기준 NCP VPC Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + vmSpecReq := vserver.GetServerProductListRequest{ + RegionCode: &vmSpecHandler.RegionInfo.Region, + ServerImageProductCode: ncloud.String(image.IId.SystemId), // ***** Caution : ImageProductCode is mandatory. ***** + } + callLogStart := call.Start() + result, err := vmSpecHandler.VMClient.V2Api.GetServerProductList(&vmSpecReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get VMSpec list from NCP VPC Cloud : ", err) + return nil, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + // spew.Dump(result) + if len(result.ProductList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "# VMSpec info corresponding to the Image ID does Not Exist!!", "") + return nil, rtnErr + } else { + for _, NcpVMSpec := range result.ProductList { + vmSpecInfo := vmSpecHandler.MappingVMSpecInfo(image.IId.SystemId, NcpVMSpec) + vmSpecInfoList = append(vmSpecInfoList, &vmSpecInfo) + } + } + } + return vmSpecInfoList, nil +} + +func (vmSpecHandler *NcpVpcVMSpecHandler) GetVMSpec(specName string) (irs.VMSpecInfo, error) { + cblogger.Info("NCP VPC Cloud driver: called GetVMSpec()!") + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, specName, "GetVMSpec()") + + imageId, ncpVpcVMspec, err := vmSpecHandler.getNcpVpcVMSpec(specName, "GetVMSpec()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get VMSpec from NCP VPC Cloud : ", err) + return irs.VMSpecInfo{}, rtnErr + } + specInfo := vmSpecHandler.MappingVMSpecInfo(imageId, ncpVpcVMspec) + return specInfo, nil +} + +func (vmSpecHandler *NcpVpcVMSpecHandler) ListOrgVMSpec() (string, error) { + cblogger.Info("NCP VPC Cloud driver: called ListOrgVMSpec()!") + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, "ListOrgVMSpec()", "ListOrgVMSpec()") + + ncpVpcVMSpecList, err := vmSpecHandler.getNcpVpcVMSpecList("ListOrgVMSpec()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get VMSpec from NCP VPC Cloud : ", err) + return "", rtnErr + } + jsonString, cvtErr := ConvertJsonString(ncpVpcVMSpecList) + if cvtErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Convert JSON to String : ", cvtErr) + return "", rtnErr + } + return jsonString, nil +} + +func (vmSpecHandler *NcpVpcVMSpecHandler) GetOrgVMSpec(specName string) (string, error) { + cblogger.Info("NCP VPC Cloud driver: called GetOrgVMSpec()!") + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, specName, "GetOrgVMSpec()") + + _, ncpVpcVMSpec, err := vmSpecHandler.getNcpVpcVMSpec(specName, "GetOrgVMSpec()") + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get VMSpec from NCP VPC Cloud : ", err) + return "", rtnErr + } + jsonString, cvtErr := ConvertJsonString(ncpVpcVMSpec) + if cvtErr != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Convert JSON to String : ", cvtErr) + return "", rtnErr + } + return jsonString, nil +} + +func (vmSpecHandler *NcpVpcVMSpecHandler) MappingVMSpecInfo(ImageId string, NcpVMSpec *vserver.Product) irs.VMSpecInfo { + cblogger.Info("NCP VPC Cloud driver: called MappingVMSpecInfo()!") + // spew.Dump(NcpVMSpec) + + vmSpecInfo := irs.VMSpecInfo{ + Region: vmSpecHandler.RegionInfo.Region, + Name: *NcpVMSpec.ProductCode, + // int32 to string 변환 : String(), int64 to string 변환 : strconv.Itoa() + VCpu: irs.VCpuInfo{Count: String(*NcpVMSpec.CpuCount), Clock: "N/A"}, + + // vserver.Product에 GPU 정보는 없음. + Gpu: []irs.GpuInfo{{Count: "N/A", Mfr: "N/A", Model: "N/A", Mem: "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.Code}, // ### 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: "Region", Value: vmSpecHandler.RegionInfo.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 +} + +func (vmSpecHandler *NcpVpcVMSpecHandler) getNcpVpcVMSpecList(callLogfunc string) ([]*vserver.Product, error) { + cblogger.Info("NCP VPC Cloud driver: called getNcpVpcVMSpecList()!") + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, callLogfunc, callLogfunc) + + imgHandler := NcpVpcImageHandler{ + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + imgListResult, err := imgHandler.ListImage() + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Image Info list : : ", err) + return nil, rtnErr + } else { + cblogger.Infof("Image list Count of the Region : [%d]", len(imgListResult)) + } + + for _, image := range imgListResult { + cblogger.Infof("\n### 기준 NCP VPC Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + specReq := vserver.GetServerProductListRequest{ + RegionCode: &vmSpecHandler.RegionInfo.Region, + ServerImageProductCode: ncloud.String(image.IId.SystemId), // *** Caution : ImageProductCode is mandatory. *** + } + callLogStart := call.Start() + result, err := vmSpecHandler.VMClient.V2Api.GetServerProductList(&specReq) + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get VMSpec list from NCP VPC : ", err) + return nil, rtnErr + } + LoggingInfo(callLogInfo, callLogStart) + + // spew.Dump(result) + if len(result.ProductList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "# VMSpec info corresponding to the Image ID does Not Exist!!", "") + return nil, rtnErr + } else { + return result.ProductList, nil + } + } + return nil, errors.New("Failed to Get NCP VPC VMSpec List!!") +} + +func (vmSpecHandler *NcpVpcVMSpecHandler) getNcpVpcVMSpec(specName string, callLogfunc string) (string, *vserver.Product, error) { + cblogger.Info("NCP VPC Cloud driver: called GetNcpVpcVMSpec()!") + InitLog() + callLogInfo := GetCallLogScheme(vmSpecHandler.RegionInfo.Zone, call.VMSPEC, specName, callLogfunc) + + imgHandler := NcpVpcImageHandler{ + RegionInfo: vmSpecHandler.RegionInfo, + VMClient: vmSpecHandler.VMClient, + } + imgListResult, err := imgHandler.ListImage() + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get Image Info list : ", err) + return "", nil, rtnErr + } else { + cblogger.Infof("Image list count of the region : [%d]", len(imgListResult)) + } + + for _, image := range imgListResult { + cblogger.Infof("\n### 기준 NCP VPC Image ID(ImageProductCode) : [%s]", image.IId.SystemId) + specReq := vserver.GetServerProductListRequest{ + RegionCode: &vmSpecHandler.RegionInfo.Region, + ProductCode: &specName, + ServerImageProductCode: ncloud.String(image.IId.SystemId), // *** Caution : ImageProductCode is mandatory. *** + } + + callLogStart := call.Start() + result, err := vmSpecHandler.VMClient.V2Api.GetServerProductList(&specReq) + if err != nil { + if err != nil { + rtnErr := logAndReturnError(callLogInfo, "Failed to Get VMSpec list from NCP VPC : ", err) + return "", nil, rtnErr + } + } + LoggingInfo(callLogInfo, callLogStart) + + // spew.Dump(result) + if len(result.ProductList) < 1 { + rtnErr := logAndReturnError(callLogInfo, "# VMSpec info corresponding to the VMSpec Name and Image ID does Not Exist!!", "") + return "", nil, rtnErr + } else { + return image.IId.SystemId, result.ProductList[0], nil + } + } + return "", nil, errors.New("Failed to Get the NCP VPC VMSpec!!") +} diff --git a/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VPCHandler.go b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VPCHandler.go new file mode 100644 index 000000000..2c3d209cf --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/ncpvpc/resources/VPCHandler.go @@ -0,0 +1,913 @@ +// Proof of Concepts for the Cloud-Barista Multi-Cloud Project. +// * Cloud-Barista: https://github.com/cloud-barista +// +// NCP VPC Handler +// +// by ETRI, 2020.10. +// by ETRI, 2022.03. updated + +package resources + +import ( + "fmt" + // "errors" + "time" + "strings" + + // "github.com/davecgh/go-spew/spew" + "github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/vpc" + + 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" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" +) + +type NcpVpcVPCHandler struct { + CredentialInfo idrv.CredentialInfo + RegionInfo idrv.RegionInfo + VPCClient *vpc.APIClient +} + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("NCP VPCHandler") +} + +func (vpcHandler *NcpVpcVPCHandler) CreateVPC(vpcReqInfo irs.VPCReqInfo) (irs.VPCInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateVPC()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, vpcReqInfo.IId.NameId, "CreateVPC()") + + if strings.EqualFold(vpcReqInfo.IId.NameId, "") { + newErr := fmt.Errorf("Invalid VPC Name!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + + // Check if the VPC Exists + vpcInfoList, err := vpcHandler.ListVPC() + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + // return irs.VPCInfo{}, err // Caution!! + } + + for _, vpcInfo := range vpcInfoList { + if strings.EqualFold(vpcInfo.IId.NameId, vpcReqInfo.IId.NameId) { + newErr := fmt.Errorf("VPC with the name [%s] exists already!!", vpcReqInfo.IId.NameId) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + } + + // Create New VPC + var vpcInfo irs.VPCInfo + vpcReqName := strings.ToLower(vpcReqInfo.IId.NameId) + + createVpcReq := vpc.CreateVpcRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + Ipv4CidrBlock: &vpcReqInfo.IPv4_CIDR, + VpcName: &vpcReqName, // Allows only lowercase letters, numbers or special character "-". Start with an alphabet character. + } + + callLogStart := call.Start() + vpcResult, err := vpcHandler.VPCClient.V2Api.CreateVpc(&createVpcReq) + if err != nil { + newErr := fmt.Errorf("Failed to Create requested VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + if *vpcResult.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create any VPC. Neww VPC does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } else { + cblogger.Infof("Succeeded in Creating the VPC!! : [%s]", vpcReqInfo.IId.NameId) + } + + // $$$ Uses Default NetworkACL of the Created VPC $$$ + /* + // Create NetworkACL + netAclReqName := vpcReqName // vpcReqName : length of 30 from CB-Spider Server + // Caution!! + // # Only lower case letter(No upper case). + // # Length constraints: Minimum length of 3. Maximum length of 30. + + createNetAclReq := vpc.CreateNetworkAclRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + NetworkAclName: &netAclReqName, // Allows only lowercase letters, numbers or special character "-". Start with an alphabet character. + VpcNo: vpcResult.VpcList[0].VpcNo, + } + + netAclResult, err := vpcHandler.VPCClient.V2Api.CreateNetworkAcl(&createNetAclReq) + if err != nil { + cblogger.Errorf("Failed to Create the NetworkACL : [%v]", err) + LoggingError(callLogInfo, err) + return irs.VPCInfo{}, err + } + + if *netAclResult.TotalRows < 1 { + cblogger.Error("Failed to Create any NetworkACL!!") + return irs.VPCInfo{}, errors.New("Failed to Create any NetworkACL!!") + } else { + cblogger.Infof("Succeeded in Creating the NetworkACL!! : [%s]", netAclReqName) + } + + // Create Subnet + for _, subnetInfo := range vpcReqInfo.SubnetInfoList { + _, err := vpcHandler.CreateSubnet(vpcResult.VpcList[0].VpcNo, netAclResult.NetworkAclList[0].NetworkAclNo, subnetInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Create New Subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + } + */ + + newVpcIID := irs.IID{SystemId: *vpcResult.VpcList[0].VpcNo} + + cblogger.Infof("# Waitting while Creating New VPC and Default NetworkACL!!") + vpcStatus, err := vpcHandler.WaitForCreateVPC(newVpcIID) + if err != nil { + newErr := fmt.Errorf("Failed to Wait for VPC Creation : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + cblogger.Infof("===> # Status of New VPC [%s] : [%s]", newVpcIID.SystemId, vpcStatus) + + // Add Requested Subnets + for _, subnetReqInfo := range vpcReqInfo.SubnetInfoList { + _, err := vpcHandler.AddSubnet(newVpcIID, subnetReqInfo) // Waitting time Included + if err != nil { + newErr := fmt.Errorf("Failed to Create New Subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + } + + vpcInfo, getErr := vpcHandler.GetVPC(newVpcIID) + if getErr != nil { + newErr := fmt.Errorf("Failed to Get VPC Info : [%v]", getErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + return vpcInfo, nil +} + +func (vpcHandler *NcpVpcVPCHandler) ListVPC() ([]*irs.VPCInfo, error) { + cblogger.Info("NCP VPC cloud driver: called ListVPC()!!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, "ListVPC()", "ListVPC()") + + vpcListReq := vpc.GetVpcListRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + } + + // cblogger.Infof("vpcListReq Ready!!") + // spew.Dump(vpcListReq) + callLogStart := call.Start() + result, err := vpcHandler.VPCClient.V2Api.GetVpcList(&vpcListReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get VPC List from NCP VPC : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var vpcInfoList []*irs.VPCInfo + if *result.TotalRows < 1 { + cblogger.Info("### VPC does Not Exist!!") + } else { + for _, vpc := range result.VpcList { + vpcInfo, err := vpcHandler.MappingVpcInfo(vpc) + if err != nil { + newErr := fmt.Errorf("Failed to Map the VPC Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + vpcInfoList = append(vpcInfoList, vpcInfo) + } + } + return vpcInfoList, nil +} + +func (vpcHandler *NcpVpcVPCHandler) GetVPC(vpcIID irs.IID) (irs.VPCInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetVPC()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, vpcIID.SystemId, "GetVPC()") + + if strings.EqualFold(vpcIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VPC SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + + // Get VPC Info from NCP VPC + ncpVpcInfo, err := vpcHandler.GetNcpVpcInfo(&vpcIID.SystemId) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP VPC Info with the SystemId : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + + vpcInfo, err := vpcHandler.MappingVpcInfo(ncpVpcInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Map the VPC Info : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + return *vpcInfo, nil +} + +func (vpcHandler *NcpVpcVPCHandler) GetNcpVpcInfo(vpcId *string) (*vpc.Vpc, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNcpVpcInfo()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, *vpcId, "GetNcpVpcInfo()") + + if strings.EqualFold(*vpcId, "") { + newErr := fmt.Errorf("Invalid VPC SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + vpcInfoReq := vpc.GetVpcDetailRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + VpcNo: vpcId, + } + + callLogStart := call.Start() + result, err := vpcHandler.VPCClient.V2Api.GetVpcDetail(&vpcInfoReq) + if err != nil { + cblogger.Errorf("Failed to Find the VPC Info from NCP VPC : [%v]", err) + LoggingError(callLogInfo, err) + return nil, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Find Any VPC Info with the ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Infof("Succeeded in Getting the VPC Info from NCP VPC!!") + } + return result.VpcList[0], nil +} + +func (vpcHandler *NcpVpcVPCHandler) GetSubnet(sunbnetIID irs.IID) (irs.SubnetInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetSubnet()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, sunbnetIID.SystemId, "GetSubnet()") + + if strings.EqualFold(sunbnetIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Subnet SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SubnetInfo{}, newErr + } + + // Get Subnet Info from NCP VPC + ncpSubnetInfo, err := vpcHandler.GetNcpSubnetInfo(&sunbnetIID.SystemId) + if err != nil { + newErr := fmt.Errorf("Failed to Get NCP Subnet Info with the SystemId : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.SubnetInfo{}, newErr + } + + subnetInfo := vpcHandler.MappingSubnetInfo(ncpSubnetInfo) + return *subnetInfo, nil +} + +func (vpcHandler *NcpVpcVPCHandler) DeleteVPC(vpcIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called DeleteVPC()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, vpcIID.SystemId, "DeleteVPC()") + + if strings.EqualFold(vpcIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VPC SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + // Check if the VPC exists + vpcInfo, err := vpcHandler.GetVPC(vpcIID) + if err != nil { + newErr := fmt.Errorf("Failed to Find any VPC info. with the SystemId : [%s] : [%v]", vpcIID.SystemId, err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + cblogger.Infof("VPC NameId to Delete [%s]", vpcInfo.IId.NameId) + + // Get SubnetList to Delete + subnetInfoList, err := vpcHandler.ListSubnet(&vpcIID.SystemId) + if err != nil { + newErr := fmt.Errorf("Failed to Get SubnetList with the SystemId : [%s] : [%v]", vpcIID.SystemId, err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + var lastSubnetNo string + + // Remove All Subnets belonging to the VPC + for _, subnet := range subnetInfoList { + // Remove the Subnet + delReq := vpc.DeleteSubnetRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + SubnetNo: &subnet.IId.SystemId, + } + + callLogStart := call.Start() + delResult, err := vpcHandler.VPCClient.V2Api.DeleteSubnet(&delReq) + if err != nil { + newErr := fmt.Errorf("Failed to Remove the Subnet with the SystemId : [%s] : [%v]", subnet.IId.SystemId, err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Infof("Removed Subnet Name : [%s]", *delResult.SubnetList[0].SubnetName) + + lastSubnetNo = subnet.IId.SystemId + } + + lastSubentIID := irs.IID{SystemId: lastSubnetNo} + + cblogger.Infof("# Waitting while Deleting All Subnets belonging to the VPC!!") + subnetStatus, err := vpcHandler.WaitForDeleteSubnet(vpcIID.SystemId, lastSubentIID) + if err != nil { + newErr := fmt.Errorf("Failed to Wait for Subnet Deletion : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + // return false, newErr + } + + cblogger.Infof("===> # Status of Subnet [%s] : [%s]", lastSubentIID.SystemId, subnetStatus) + + // Delete the VPC + delReq := vpc.DeleteVpcRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + VpcNo: &vpcIID.SystemId, + } + + callLogStart := call.Start() + delResult, err := vpcHandler.VPCClient.V2Api.DeleteVpc(&delReq) + if err != nil { + newErr := fmt.Errorf("Failed to Delete the VPC with the SystemId : [%s] : [%v]", vpcIID.SystemId, err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + cblogger.Infof("Succeeded in Deleting the VPC!! : [%s]", *delResult.VpcList[0].VpcName) + return true, nil +} + +// Only When any Subnet exists already(because of NetworkACLNo) +func (vpcHandler *NcpVpcVPCHandler) AddSubnet(vpcIID irs.IID, subnetReqInfo irs.SubnetInfo) (irs.VPCInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called AddSubnet()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, subnetReqInfo.IId.NameId, "AddSubnet()") + + if strings.EqualFold(vpcIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VPC SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + + // Check if the VPC exists + vpcInfo, err := vpcHandler.GetVPC(vpcIID) + if err != nil { + newErr := fmt.Errorf("Failed to Find any VPC info. with the SystemId : [%s]", vpcIID.SystemId) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + + cblogger.Infof("VPC NameId to Add the Subnet : [%s]", vpcInfo.IId.NameId) + + // Check if the SubnetName Exists + subnetInfoList, err := vpcHandler.ListSubnet(&vpcIID.SystemId) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + // return irs.VPCInfo{}, err // Caution!! + } + + for _, subnet := range subnetInfoList { + if strings.EqualFold(subnet.IId.NameId, subnetReqInfo.IId.NameId) { + newErr := fmt.Errorf("Subnet with the name [%s] exists already!!", subnetReqInfo.IId.NameId) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + } + + // Get the Default NetworkACL No. of the VPC + netAclNo, getNoErr := vpcHandler.GetDefaultNetworkAclNo(vpcIID) + if getNoErr != nil { + newErr := fmt.Errorf("Failed to Get Network ACL No of the VPC : [%v]", getNoErr) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + + // Note : subnetUsageType : 'GEN' (general) | 'LOADB' (Load balancer only) | 'BM' (Bare metal only) + subnetUsageType := "GEN" + ncpSubnetInfo, err := vpcHandler.CreateSubnet(vpcIID, netAclNo, &subnetUsageType, subnetReqInfo) + if err != nil { + newErr := fmt.Errorf("Failed to Create the Subnet for General Purpose : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + cblogger.Infof("New Subnet SubnetNo : [%s]", *ncpSubnetInfo.SubnetNo) + + subnetStatus, err := vpcHandler.WaitForCreateSubnet(ncpSubnetInfo.SubnetNo) + if err != nil { + newErr := fmt.Errorf("Failed to Wait for Creating the subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return irs.VPCInfo{}, newErr + } + cblogger.Infof("# Subnet Status : [%s]", subnetStatus) + + vpcInfo, getErr := vpcHandler.GetVPC(irs.IID{SystemId: vpcIID.SystemId}) + if getErr != nil { + cblogger.Error(getErr.Error()) + LoggingError(callLogInfo, getErr) + return irs.VPCInfo{}, getErr + } + return vpcInfo, nil +} + +func (vpcHandler *NcpVpcVPCHandler) RemoveSubnet(vpcIID irs.IID, subnetIID irs.IID) (bool, error) { + cblogger.Info("NCP VPC Cloud Driver: called RemoveSubnet()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, subnetIID.SystemId, "RemoveSubnet()") + + if strings.EqualFold(subnetIID.SystemId, "") { + newErr := fmt.Errorf("Invalid Subnet SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + + // Check if the Subnet Exists + subnetInfoList, err := vpcHandler.ListSubnet(&vpcIID.SystemId) + if err != nil { + cblogger.Error(err.Error()) + LoggingError(callLogInfo, err) + return false, err + } + + var subnetName string + + for _, subnetInfo := range subnetInfoList { + if strings.EqualFold(subnetInfo.IId.SystemId, subnetIID.SystemId) { + subnetName = subnetInfo.IId.NameId + break + } + } + + if strings.EqualFold(subnetName, "") { + return false, fmt.Errorf("Failed to Find the Subnet!! : [%s]", subnetIID.SystemId) + } + + // Remove the Subnet + delReq := vpc.DeleteSubnetRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + SubnetNo: &subnetIID.SystemId, + } + + callLogStart := call.Start() + delResult, err := vpcHandler.VPCClient.V2Api.DeleteSubnet(&delReq) + if err != nil { + newErr := fmt.Errorf("Failed to Remove the Requested Subnet : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return false, newErr + } + LoggingInfo(callLogInfo, callLogStart) + cblogger.Infof("Removed Subnet Name : [%s]", *delResult.SubnetList[0].SubnetName) + return true, nil +} + +func (vpcHandler *NcpVpcVPCHandler) CreateSubnet(vpcIID irs.IID, netAclNo *string, subnetUsageType *string, subnetReqInfo irs.SubnetInfo) (*vpc.Subnet, error) { + cblogger.Info("NCP VPC Cloud Driver: called CreateSubnet()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, subnetReqInfo.IId.NameId, "CreateSubnet()") + + if strings.EqualFold(vpcIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VPC SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + if strings.EqualFold(subnetReqInfo.IId.NameId, "") { + newErr := fmt.Errorf("Invalid Requested Subnet NameId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + // vpcInfo, err := vpcHandler.GetVPC(vpcIID) // Don't Need to Check if the VPC exists + + subnetReqName := strings.ToLower(subnetReqInfo.IId.NameId) + subnetTypeCode := "PUBLIC" // 'PUBLIC' (for Internet Gateway) | 'PRIVATE' + // subnetUsageType : 'GEN' (general) | 'LOADB' (Load balancer only) | 'BM' (Bare metal only) + createSubnetReq := vpc.CreateSubnetRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + SubnetTypeCode: &subnetTypeCode, + UsageTypeCode: subnetUsageType, + NetworkAclNo: netAclNo, + Subnet: &subnetReqInfo.IPv4_CIDR, + SubnetName: &subnetReqName, // Allows only lowercase letters, numbers or special character "-". Start with an alphabet character. + VpcNo: &vpcIID.SystemId, + ZoneCode: &vpcHandler.RegionInfo.Zone, + } + + callLogStart := call.Start() + subnet, err := vpcHandler.VPCClient.V2Api.CreateSubnet(&createSubnetReq) + if err != nil { + cblogger.Errorf("Failed to Create the Subnet : [%v]", err) + LoggingError(callLogInfo, err) + return nil, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *subnet.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Create the Subnet. New Subnet does Not Exist!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Infof("Succeeded in Creating the Subnet!! : [%s]", *subnet.SubnetList[0].SubnetName) + } + return subnet.SubnetList[0], nil +} + +func (vpcHandler *NcpVpcVPCHandler) GetNcpSubnetInfo(sunbnetId *string) (*vpc.Subnet, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetNcpSubnetInfo()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, *sunbnetId, "GetNcpSubnetInfo()") + + if strings.EqualFold(*sunbnetId, "") { + newErr := fmt.Errorf("Invalid Subnet ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + subnetInfoReq := vpc.GetSubnetDetailRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + SubnetNo: sunbnetId, + } + + callLogStart := call.Start() + result, err := vpcHandler.VPCClient.V2Api.GetSubnetDetail(&subnetInfoReq) + if err != nil { + cblogger.Errorf("Failed to Get the Subnet Info from NCP VPC : [%v]", err) + LoggingError(callLogInfo, err) + return nil, err + } + LoggingInfo(callLogInfo, callLogStart) + + if *result.TotalRows < 1 { + newErr := fmt.Errorf("Failed to Get any Subnet Info with the ID!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } else { + cblogger.Infof("Succeeded in Getting the Subnet Info from NCP VPC!!") + } + return result.SubnetList[0], nil +} + +func (vpcHandler *NcpVpcVPCHandler) ListSubnet(vpcNo *string) ([]*irs.SubnetInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called ListSubnet()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, "ListSubnet()", "ListSubnet()") + + subnetListReq := vpc.GetSubnetListRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + VpcNo: vpcNo, + } + + cblogger.Infof("subnetListReq Ready!!") + // spew.Dump(subnetListReq) + + result, err := vpcHandler.VPCClient.V2Api.GetSubnetList(&subnetListReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get subnetList : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + var subnetInfoList []*irs.SubnetInfo + if *result.TotalRows < 1 { + cblogger.Infof("### The VPC has No Subnet!!") + } else { + cblogger.Infof("Succeeded in Getting SubnetList!! : ") + for _, subnet := range result.SubnetList { // To Get Subnet info list + subnetInfo := vpcHandler.MappingSubnetInfo(subnet) + subnetInfoList = append(subnetInfoList, subnetInfo) + } + } + return subnetInfoList, nil +} + +func (vpcHandler *NcpVpcVPCHandler) GetDefaultNetworkAclNo(vpcIID irs.IID) (*string, error) { + cblogger.Info("NCP VPC Cloud Driver: called GetDefaultNetworkAclNo()!") + + InitLog() // Caution!! + callLogInfo := GetCallLogScheme(vpcHandler.RegionInfo.Zone, call.VPCSUBNET, vpcIID.SystemId, "GetDefaultNetworkAclNo()") + + if strings.EqualFold(vpcIID.SystemId, "") { + newErr := fmt.Errorf("Invalid VPC SystemId!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + + // # Caution!! : Infinite Loop + // vpcInfo, err := vpcHandler.GetVPC(vpcIID) // Check if the VPC exists + + // Get the Default NetworkACL of the VPC + getReq := vpc.GetNetworkAclListRequest { + RegionCode: &vpcHandler.RegionInfo.Region, + VpcNo: &vpcIID.SystemId, + } + + callLogStart := call.Start() + netAclResult, err := vpcHandler.VPCClient.V2Api.GetNetworkAclList(&getReq) + if err != nil { + newErr := fmt.Errorf("Failed to Get NetworkACL List!! : [%v]", err) + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + LoggingInfo(callLogInfo, callLogStart) + + var netACLNo *string + if *netAclResult.TotalRows < 1 { + cblogger.Info("# NetworkACL does Not Exist!!") + } else { + for _, netACL := range netAclResult.NetworkAclList { + if strings.Contains(*netACL.NetworkAclName, "default-network-acl") { // When Contains "default-network-acl" in NetworkAclName + netACLNo = netACL.NetworkAclNo + break + } + } + } + + if strings.EqualFold(*netACLNo, "") { + newErr := fmt.Errorf("Failed to Get the Default NetworkACL No of the VPC!!") + cblogger.Error(newErr.Error()) + LoggingError(callLogInfo, newErr) + return nil, newErr + } + return netACLNo, nil +} + +func (vpcHandler *NcpVpcVPCHandler) MappingVpcInfo(vpc *vpc.Vpc) (*irs.VPCInfo, error) { + cblogger.Info("NCP VPC Cloud Driver: called MappingVpcInfo()!") + + // VPC info mapping + vpcInfo := irs.VPCInfo{ + IId: irs.IID{ + NameId: *vpc.VpcName, + SystemId: *vpc.VpcNo, + }, + IPv4_CIDR: *vpc.Ipv4CidrBlock, + } + + keyValueList := []irs.KeyValue{ + {Key: "RegionCode", Value: *vpc.RegionCode}, + {Key: "VpcStatus", Value: *vpc.VpcStatus.Code}, + {Key: "CreateDate", Value: *vpc.CreateDate}, + } + vpcInfo.KeyValueList = keyValueList + + subnetList, err := vpcHandler.ListSubnet(vpc.VpcNo) + if err != nil { + cblogger.Errorf("Failed to Get subnet List : [%v]", err) // Caution!! + // return nil // Caution!! + } + + var subnetInfoList []irs.SubnetInfo + + if len(subnetList) > 0 { + for _, subnetInfo := range subnetList { // Ref) var subnetList []*irs.SubnetInfo + cblogger.Infof("# Subnet NameId : [%s]", subnetInfo.IId.NameId) + subnetInfoList = append(subnetInfoList, *subnetInfo) + } + vpcInfo.SubnetInfoList = subnetInfoList + } + + // cblogger.Infof("vpcInfo.SubnetInfoList : ") + // spew.Dump(vpcInfo.SubnetInfoList) + + /* + // Get the Default NetworkACL of the VPC + netAclNo, getNoErr := vpcHandler.GetDefaultNetworkAclNo(irs.IID{SystemId: *vpc.VpcNo}) + if getNoErr != nil { + newErr := fmt.Errorf("Failed to Get Network ACL No of the VPC : [%v]", getNoErr) + cblogger.Error(newErr.Error()) + return nil, newErr + } + + keyValue := irs.KeyValue{Key: "DefaultNetworkACLNo", Value: *netAclNo} + vpcInfo.KeyValueList = append(vpcInfo.KeyValueList, keyValue) + */ + + return &vpcInfo, nil +} + +func (vpcHandler *NcpVpcVPCHandler) MappingSubnetInfo(subnet *vpc.Subnet) *irs.SubnetInfo { + cblogger.Info("NCP VPC Cloud Driver: called MappingSubnetInfo()!") + // spew.Dump(*subnet) + + // Subnet info mapping + subnetInfo := irs.SubnetInfo { + IId: irs.IID{ + NameId: *subnet.SubnetName, + SystemId: *subnet.SubnetNo, + }, + IPv4_CIDR: *subnet.Subnet, + } + + keyValueList := []irs.KeyValue{ + {Key: "ZoneCode", Value: *subnet.ZoneCode}, + {Key: "SubnetStatus", Value: *subnet.SubnetStatus.Code}, + {Key: "SubnetType", Value: *subnet.SubnetType.Code}, + {Key: "UsageType", Value: *subnet.UsageType.Code}, + {Key: "NetworkACLNo", Value: *subnet.NetworkAclNo}, + {Key: "CreateDate", Value: *subnet.CreateDate}, + } + subnetInfo.KeyValueList = keyValueList + return &subnetInfo +} + +// Waiting for up to 600 seconds until VPC and Network ACL Creation processes are Finished. +func (vpcHandler *NcpVpcVPCHandler) WaitForCreateVPC(vpcIID irs.IID) (string, error) { + cblogger.Info("======> As Subnet cannot be Created Immediately after VPC Creation Call, it waits until VPC and Network ACL Creation processes are Finished.") + + curRetryCnt := 0 + maxRetryCnt := 600 + + for { + ncpVpcInfo, getErr := vpcHandler.GetNcpVpcInfo(&vpcIID.SystemId) + if getErr != nil { + newErr := fmt.Errorf("Failed to Get VPC Info : [%v]", getErr) + cblogger.Error(newErr.Error()) + return "", newErr + } else { + cblogger.Infof("Succeeded in Getting the VPC Info of [%s]", vpcIID.SystemId) + } + + vpcStatus := *ncpVpcInfo.VpcStatus.Code + cblogger.Infof("\n### VPC Status [%s] : ", vpcStatus) + + if strings.EqualFold(vpcStatus, "CREATING") { + curRetryCnt++ + cblogger.Infof("The VPC and Network ACL are still [%s], so wait for a second more before Creating Subnet.", vpcStatus) + time.Sleep(time.Second * 3) + if curRetryCnt > maxRetryCnt { + newErr := fmt.Errorf("Despite waiting for a long time(%d sec), the VPC status is '%s', so it is forcibly finishied.", maxRetryCnt, vpcStatus) + return "", newErr + } + } else { + cblogger.Infof("The VPC and Network ACL Creation processes are Finished.") + + // Wait More + time.Sleep(time.Second * 5) + return vpcStatus, nil + } + } +} + +// Waiting for up to 600 seconds until VPC and Network ACL Creation processes are Finished. +func (vpcHandler *NcpVpcVPCHandler) WaitForDeleteSubnet(vpcNo string, subnetIID irs.IID) (string, error) { + cblogger.Info("======> As VPC cannot be Deleted Immediately after Subnet Deletion Call, it waits until Subnet Deletion processes are Finished.") + + curRetryCnt := 0 + maxRetryCnt := 600 + + subnetList, err := vpcHandler.ListSubnet(&vpcNo) + if err != nil { + cblogger.Errorf("Failed to Get subnet List : [%v]", err) // Caution!! + // return nil // Caution!! + } + + if len(subnetList) > 0 { + for { + ncpSubnetInfo, getErr := vpcHandler.GetNcpSubnetInfo(&subnetIID.SystemId) + if getErr != nil { + newErr := fmt.Errorf("Failed to Get the Subnet Info : [%v]", getErr) + cblogger.Error(newErr.Error()) + return "", newErr + } else { + cblogger.Infof("Succeeded in Getting the Subnet Info of [%s]", subnetIID.SystemId) + } + + subnetStatus := *ncpSubnetInfo.SubnetStatus.Code + cblogger.Infof("\n### Subnet Status [%s] : ", subnetStatus) + + if strings.EqualFold(subnetStatus, "TERMTING") || strings.EqualFold(subnetStatus, "CREATING"){ + curRetryCnt++ + cblogger.Infof("The Suntnet is still [%s], so wait for a second more before Deleting VPC.", subnetStatus) + time.Sleep(time.Second * 3) + if curRetryCnt > maxRetryCnt { + newErr := fmt.Errorf("Despite waiting for a long time(%d sec), the Subnet status is '%s', so it is forcibly finishied.", maxRetryCnt, subnetStatus) + return "", newErr + } + } else { + cblogger.Infof("The Subnet Deletion processes are Finished.") + + // Wait More + time.Sleep(time.Second * 5) + + return subnetStatus, nil + } + } + } else { + return "This VPC has No Subnet!!", nil + } +} + +// Waiting for up to 600 seconds until Subnet Creation processes are Finished. +func (vpcHandler *NcpVpcVPCHandler) WaitForCreateSubnet(subnetId *string) (string, error) { + cblogger.Info("======> As Subnet cannot be Created Immediately after VPC Creation Call, it waits until VPC and Network ACL Creation processes are Finished.") + + curRetryCnt := 0 + maxRetryCnt := 600 + + for { + ncpSubnetInfo, getErr := vpcHandler.GetNcpSubnetInfo(subnetId) + if getErr != nil { + newErr := fmt.Errorf("Failed to Get the Subnet Info : [%v]", getErr) + cblogger.Error(newErr.Error()) + return "", newErr + } else { + cblogger.Infof("Succeeded in Getting the Subnet Info of [%s]", *subnetId) + } + + subnetStatus := *ncpSubnetInfo.SubnetStatus.Code + cblogger.Infof("\n### Subnet Status [%s] : ", subnetStatus) + + if strings.EqualFold(subnetStatus, "CREATING") { + curRetryCnt++ + cblogger.Infof("The Subnet is still [%s], so wait for a second more before Getting VPC Info.", subnetStatus) + time.Sleep(time.Second * 3) + if curRetryCnt > maxRetryCnt { + newErr := fmt.Errorf("Despite waiting for a long time(%d sec), the Subnet status is '%s', so it is forcibly finishied.", maxRetryCnt, subnetStatus) + return "", newErr + } + } else { + cblogger.Infof("The Subnet Creation processes are Finished.") + + // Wait More + time.Sleep(time.Second * 3) + return subnetStatus, nil + } + } +}