diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go index 05e4e1cb6..1230b0e62 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go @@ -1,2036 +1,2172 @@ -package main - -import ( - "bufio" - "errors" - "fmt" - "io/ioutil" - "os" - "strconv" - "strings" - - cblog "github.com/cloud-barista/cb-log" - ibm "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc" - idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" - irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" - "github.com/davecgh/go-spew/spew" - "github.com/sirupsen/logrus" - "gopkg.in/yaml.v3" -) - -type Config struct { - IbmVPC struct { - ApiKey string `yaml:"apiKey"` - Region string `yaml:"region"` - Zone string `yaml:"zone"` - Resources struct { - Image struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"image"` - Security struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - VpcIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"VpcIID"` - Rules []struct { - FromPort string `yaml:"FromPort"` - ToPort string `yaml:"ToPort"` - IPProtocol string `yaml:"IPProtocol"` - CIDR string `yaml:"CIDR"` - Direction string `yaml:"Direction"` - } `yaml:"rules"` - AddRules []struct { - FromPort string `yaml:"FromPort"` - ToPort string `yaml:"ToPort"` - IPProtocol string `yaml:"IPProtocol"` - CIDR string `yaml:"CIDR"` - Direction string `yaml:"Direction"` - } `yaml:"addRules"` - RemoveRules []struct { - FromPort string `yaml:"FromPort"` - ToPort string `yaml:"ToPort"` - IPProtocol string `yaml:"IPProtocol"` - CIDR string `yaml:"CIDR"` - Direction string `yaml:"Direction"` - } `yaml:"removeRules"` - } `yaml:"security"` - KeyPair struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"keyPair"` - VmSpec struct { - NameId string `yaml:"nameId"` - } `yaml:"vmSpec"` - VPC struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - IPv4CIDR string `yaml:"ipv4CIDR"` - Subnets []struct { - NameId string `yaml:"nameId"` - IPv4CIDR string `yaml:"ipv4CIDR"` - } `yaml:"subnets"` - AddSubnet struct { - NameId string `yaml:"nameId"` - IPv4CIDR string `yaml:"ipv4CIDR"` - } `yaml:"addSubnet"` - } `yaml:"vpc"` - Vm struct { - IID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"IID"` - ImageIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"ImageIID"` - VmSpecName string `yaml:"VmSpecName"` - KeyPairIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"KeyPairIID"` - VpcIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"VpcIID"` - SubnetIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"SubnetIID"` - SecurityGroupIIDs []struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"SecurityGroupIIDs"` - DataDiskIIDs []struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"DataDiskIIDs"` - VMUserID string `yaml:"VMUserID"` - VMUserPassword string `yaml:"VMUserPassword"` - } `yaml:"vm"` - VmFromMyImage struct { - IID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"IID"` - ImageIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"ImageIID"` - VmSpecName string `yaml:"VmSpecName"` - KeyPairIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"KeyPairIID"` - VpcIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"VpcIID"` - SubnetIID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"SubnetIID"` - SecurityGroupIIDs []struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"SecurityGroupIIDs"` - VMUserID string `yaml:"VMUserID"` - VMUserPassword string `yaml:"VMUserPassword"` - } `yaml:"VmFromMyImage"` - DISK struct { - IID struct { - NameId string `yaml:"nameId"` - SystemId string `yaml:"systemId"` - } `yaml:"IID"` - DiskSize string `yaml:"DiskSize"` - DiskType string `yaml:"DiskType"` - } `yaml:"disk"` - MYIMAGE struct { - IID struct { - NameId string `yaml:"nameId"` - } `yaml:"IID"` - SourceVMIID struct { - NameId string `yaml:"nameId"` - } `yaml:"SourceVMIID"` - } `yaml:"myimage"` - CLUSTER struct { - IID struct { - NameId string `yaml:"nameId"` - } `yaml:"IID"` - Version string `yaml:"version"` - Network struct { - VpcIID struct { - NameId string `yaml:"nameId"` - } `yaml:"vpcIID"` - SubnetIIDs []struct { - NameId string `yaml:"nameId"` - } `yaml:"subnetIIDs"` - SecurityGroupIIDs []struct { - NameId string `yaml:"nameId"` - } `yaml:"securityGroupIIDs"` - } `yaml:"network"` - NodeGroupList []struct { - IID struct { - NameId string `yaml:"nameId"` - } `yaml:"IID"` - VMSpecName string `yaml:"vmSpecName"` - RootDiskType string `yaml:"rootDiskType"` - RootDiskSize string `yaml:"rootDiskSize"` - KeyPairIID struct { - NameId string `yaml:"nameId"` - } `yaml:"keyPairIID"` - OnAutoScaling bool `yaml:"onAutoScaling"` - DesireNodeSize int `yaml:"desireNodeSize"` - MinNodeSize int `yaml:"minNodeSize"` - MaxNodeSize int `yaml:"maxNodeSize"` - } `yaml:"nodeGroupList"` - AdditionalNodeGroup struct { - IID struct { - NameId string `yaml:"nameId"` - } `yaml:"IID"` - VMSpecName string `yaml:"vmSpecName"` - RootDiskType string `yaml:"rootDiskType"` - RootDiskSize string `yaml:"rootDiskSize"` - KeyPairIID struct { - NameId string `yaml:"nameId"` - } `yaml:"keyPairIID"` - OnAutoScaling bool `yaml:"onAutoScaling"` - DesireNodeSize int `yaml:"desireNodeSize"` - MinNodeSize int `yaml:"minNodeSize"` - MaxNodeSize int `yaml:"maxNodeSize"` - } `yaml:"additionalNodeGroup"` - ClusterUpdateInfos struct { - TargetNodeGroupIID struct { - NameId string `yaml:"nameId"` - } `yaml:"targetNodeGroupIID"` - OnNodeGroupAutoScaling bool `yaml:"onNodeGroupAutoScaling"` - ChangeNodeGroupScaling struct { - DesiredNodeSize int `yaml:"desiredNodeSize"` - MinNodeSize int `yaml:"minNodeSize"` - MaxNodeSize int `yaml:"maxNodeSize"` - } `yaml:"changeNodeGroupScaling"` - UpgradeVersion string `yaml:"upgradeVersion"` - } `yaml:"clusterUpdateInfos"` - } `yaml:"cluster"` - } `yaml:"resources"` - } `yaml:"ibmvpc"` -} - -var cblogger *logrus.Logger - -func init() { - // cblog is a global variable. - cblogger = cblog.GetLogger("CB-SPIDER") -} - -func readConfigFile() Config { - // Set Environment Value of Project Root Path - rootPath := os.Getenv("CBSPIDER_ROOT") - data, err := ioutil.ReadFile(rootPath + "/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/conf/config.yaml") - if err != nil { - cblogger.Error(err) - } - - var config Config - err = yaml.Unmarshal(data, &config) - if err != nil { - cblogger.Error(err) - } - - return config -} - -func showTestHandlerInfo() { - cblogger.Info("==========================================================") - cblogger.Info("[Test ResourceHandler]") - cblogger.Info("1. ImageHandler") - cblogger.Info("2. SecurityHandler") - cblogger.Info("3. VPCHandler") - cblogger.Info("4. KeyPairHandler") - cblogger.Info("5. VmSpecHandler") - cblogger.Info("6. VmHandler") - cblogger.Info("7. NLBHandler") - cblogger.Info("8. DiskHandler") - cblogger.Info("9. MyImageHandler") - cblogger.Info("10. RegionZoneHandler") - cblogger.Info("11. PriceInfoHandler") - cblogger.Info("12. ClusterHandler") - cblogger.Info("13. TagHandler") - cblogger.Info("14. Exit") - cblogger.Info("==========================================================") -} - -func getResourceHandler(resourceType string, config Config) (interface{}, error) { - ibmCloudConnectionIfo := idrv.ConnectionInfo{ - CredentialInfo: idrv.CredentialInfo{ - ApiKey: config.IbmVPC.ApiKey, - }, - RegionInfo: idrv.RegionInfo{ - Region: config.IbmVPC.Region, - Zone: config.IbmVPC.Zone, - }, - } - - var cloudDriver idrv.CloudDriver - cloudDriver = new(ibm.IbmCloudDriver) - - ibmCon, err := cloudDriver.ConnectCloud(ibmCloudConnectionIfo) - if err != nil { - return nil, err - } - var resourceHandler interface{} - - switch resourceType { - case "image": - resourceHandler, err = ibmCon.CreateImageHandler() - case "security": - resourceHandler, err = ibmCon.CreateSecurityHandler() - case "vpc": - resourceHandler, err = ibmCon.CreateVPCHandler() - case "keypair": - resourceHandler, err = ibmCon.CreateKeyPairHandler() - case "vmspec": - resourceHandler, err = ibmCon.CreateVMSpecHandler() - case "vm": - resourceHandler, err = ibmCon.CreateVMHandler() - // TODO interface Change - case "nlb": - //return nil, errors.New("not support") - resourceHandler, err = ibmCon.CreateNLBHandler() - case "disk": - resourceHandler, err = ibmCon.CreateDiskHandler() - case "myimage": - resourceHandler, err = ibmCon.CreateMyImageHandler() - case "regionzone": - resourceHandler, err = ibmCon.CreateRegionZoneHandler() - case "price": - resourceHandler, err = ibmCon.CreatePriceInfoHandler() - case "cluster": - resourceHandler, err = ibmCon.CreateClusterHandler() - case "tag": - resourceHandler, err = ibmCon.CreateTagHandler() - } - - return resourceHandler, nil -} -func testImageHandlerListPrint() { - cblogger.Info("Test ImageHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListImage()") - cblogger.Info("2. GetImage()") - cblogger.Info("3. CreateImage()") - cblogger.Info("4. DeleteImage()") - cblogger.Info("5. Exit") -} - -func testImageHandler(config Config) { - resourceHandler, err := getResourceHandler("image", config) - if err != nil { - cblogger.Error(err) - return - } - - imageHandler := resourceHandler.(irs.ImageHandler) - - testImageHandlerListPrint() - - imageIID := irs.IID{NameId: config.IbmVPC.Resources.Image.NameId} - -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testImageHandlerListPrint() - case 1: - cblogger.Info("Start ListImage() ...") - if list, err := imageHandler.ListImage(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListImage()") - case 2: - cblogger.Info("Start GetImage() ...") - if imageInfo, err := imageHandler.GetImage(imageIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(imageInfo) - } - cblogger.Info("Finish GetImage()") - case 3: - cblogger.Info("Start CreateImage() ...") - cblogger.Info("Finish CreateImage()") - case 4: - cblogger.Info("Start DeleteImage() ...") - cblogger.Info("Finish DeleteImage()") - case 5: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testSecurityHandlerListPrint() { - cblogger.Info("Test securityHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListSecurity()") - cblogger.Info("2. GetSecurity()") - cblogger.Info("3. CreateSecurity()") - cblogger.Info("4. DeleteSecurity()") - cblogger.Info("5. AddRules()") - cblogger.Info("6. RemoveRules()") - cblogger.Info("7. Exit") -} - -// SecurityGroup -func testSecurityHandler(config Config) { - resourceHandler, err := getResourceHandler("security", config) - if err != nil { - cblogger.Error(err) - return - } - - securityHandler := resourceHandler.(irs.SecurityHandler) - - testSecurityHandlerListPrint() - - securityIId := irs.IID{NameId: config.IbmVPC.Resources.Security.NameId} - securityRules := config.IbmVPC.Resources.Security.Rules - var securityRulesInfos []irs.SecurityRuleInfo - for _, securityRule := range securityRules { - infos := irs.SecurityRuleInfo{ - FromPort: securityRule.FromPort, - ToPort: securityRule.ToPort, - IPProtocol: securityRule.IPProtocol, - Direction: securityRule.Direction, - CIDR: securityRule.CIDR, - } - securityRulesInfos = append(securityRulesInfos, infos) - } - targetVPCIId := irs.IID{ - NameId: config.IbmVPC.Resources.Security.VpcIID.NameId, - } - securityAddRules := config.IbmVPC.Resources.Security.AddRules - var securityAddRulesInfos []irs.SecurityRuleInfo - for _, securityRule := range securityAddRules { - infos := irs.SecurityRuleInfo{ - FromPort: securityRule.FromPort, - ToPort: securityRule.ToPort, - IPProtocol: securityRule.IPProtocol, - Direction: securityRule.Direction, - CIDR: securityRule.CIDR, - } - securityAddRulesInfos = append(securityAddRulesInfos, infos) - } - securityRemoveRules := config.IbmVPC.Resources.Security.RemoveRules - var securityRemoveRulesInfos []irs.SecurityRuleInfo - for _, securityRule := range securityRemoveRules { - infos := irs.SecurityRuleInfo{ - FromPort: securityRule.FromPort, - ToPort: securityRule.ToPort, - IPProtocol: securityRule.IPProtocol, - Direction: securityRule.Direction, - CIDR: securityRule.CIDR, - } - securityRemoveRulesInfos = append(securityRemoveRulesInfos, infos) - } -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - fmt.Println(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testSecurityHandlerListPrint() - case 1: - fmt.Println("Start ListSecurity() ...") - if securityList, err := securityHandler.ListSecurity(); err != nil { - fmt.Println(err) - } else { - spew.Dump(securityList) - } - fmt.Println("Finish ListSecurity()") - case 2: - fmt.Println("Start GetSecurity() ...") - if secGroupInfo, err := securityHandler.GetSecurity(securityIId); err != nil { - fmt.Println(err) - } else { - spew.Dump(secGroupInfo) - } - fmt.Println("Finish GetSecurity()") - case 3: - fmt.Println("Start CreateSecurity() ...") - reqInfo := irs.SecurityReqInfo{ - IId: securityIId, - SecurityRules: &securityRulesInfos, - VpcIID: targetVPCIId, - } - security, err := securityHandler.CreateSecurity(reqInfo) - if err != nil { - fmt.Println(err) - } else { - spew.Dump(security) - } - //securityGroupId = security.IId - fmt.Println("Finish CreateSecurity()") - case 4: - fmt.Println("Start DeleteSecurity() ...") - if ok, err := securityHandler.DeleteSecurity(securityIId); !ok { - fmt.Println(err) - } - fmt.Println("Finish DeleteSecurity()") - case 5: - fmt.Println("Start AddRules() ...") - security, err := securityHandler.AddRules(securityIId, &securityAddRulesInfos) - if err != nil { - fmt.Println(err) - } else { - spew.Dump(security) - } - fmt.Println("Finish AddRules()") - case 6: - fmt.Println("Start RemoveRules() ...") - if ok, err := securityHandler.RemoveRules(securityIId, &securityRemoveRulesInfos); !ok { - fmt.Println(err) - } - fmt.Println("Finish RemoveRules()") - case 7: - fmt.Println("Exit") - break Loop - } - } - } -} -func testKeyPairHandlerListPrint() { - cblogger.Info("Test KeyPairHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListKey()") - cblogger.Info("2. GetKey()") - cblogger.Info("3. CreateKey()") - cblogger.Info("4. DeleteKey()") - cblogger.Info("5. Exit") -} -func testKeyPairHandler(config Config) { - resourceHandler, err := getResourceHandler("keypair", config) - if err != nil { - cblogger.Error(err) - return - } - - keyPairHandler := resourceHandler.(irs.KeyPairHandler) - - testKeyPairHandlerListPrint() - - keypairIId := irs.IID{ - NameId: config.IbmVPC.Resources.KeyPair.NameId, - } - -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testKeyPairHandlerListPrint() - case 1: - cblogger.Info("Start ListKey() ...") - if keyPairList, err := keyPairHandler.ListKey(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(keyPairList) - } - cblogger.Info("Finish ListKey()") - case 2: - cblogger.Info("Start GetKey() ...") - if keyPairInfo, err := keyPairHandler.GetKey(keypairIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(keyPairInfo) - } - cblogger.Info("Finish GetKey()") - case 3: - cblogger.Info("Start CreateKey() ...") - reqInfo := irs.KeyPairReqInfo{ - IId: keypairIId, - } - if keyInfo, err := keyPairHandler.CreateKey(reqInfo); err != nil { - cblogger.Error(err) - } else { - keypairIId = keyInfo.IId - spew.Dump(keyInfo) - } - cblogger.Info("Finish CreateKey()") - case 4: - cblogger.Info("Start DeleteKey() ...") - if ok, err := keyPairHandler.DeleteKey(keypairIId); !ok { - cblogger.Error(err) - } - cblogger.Info("Finish DeleteKey()") - case 5: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testVMSpecHandlerListPrint() { - cblogger.Info("Test VMSpecHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListVMSpec()") - cblogger.Info("2. GetVMSpec()") - cblogger.Info("3. ListOrgVMSpec()") - cblogger.Info("4. GetOrgVMSpec()") - cblogger.Info("5. Exit") -} - -func testVMSpecHandler(config Config) { - resourceHandler, err := getResourceHandler("vmspec", config) - if err != nil { - cblogger.Error(err) - return - } - - vmSpecHandler := resourceHandler.(irs.VMSpecHandler) - - testVMSpecHandlerListPrint() - -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testVMSpecHandlerListPrint() - case 1: - cblogger.Info("Start ListVMSpec() ...") - if list, err := vmSpecHandler.ListVMSpec(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListVMSpec()") - case 2: - cblogger.Info("Start GetVMSpec() ...") - if vmSpecInfo, err := vmSpecHandler.GetVMSpec(config.IbmVPC.Resources.VmSpec.NameId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmSpecInfo) - } - cblogger.Info("Finish GetVMSpec()") - case 3: - cblogger.Info("Start ListOrgVMSpec() ...") - if listStr, err := vmSpecHandler.ListOrgVMSpec(); err != nil { - cblogger.Error(err) - } else { - fmt.Println(listStr) - } - cblogger.Info("Finish ListOrgVMSpec()") - case 4: - cblogger.Info("Start GetOrgVMSpec() ...") - if vmSpecStr, err := vmSpecHandler.GetOrgVMSpec(config.IbmVPC.Resources.VmSpec.NameId); err != nil { - cblogger.Error(err) - } else { - fmt.Println(vmSpecStr) - } - cblogger.Info("Finish GetOrgVMSpec()") - case 5: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testVPCHandlerListPrint() { - cblogger.Info("Test VPCHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListVPC()") - cblogger.Info("2. GetVPC()") - cblogger.Info("3. CreateVPC()") - cblogger.Info("4. DeleteVPC()") - cblogger.Info("5. AddSubnet()") - cblogger.Info("6. RemoveSubnet()") - cblogger.Info("7. Exit") -} - -func testVPCHandler(config Config) { - resourceHandler, err := getResourceHandler("vpc", config) - if err != nil { - cblogger.Error(err) - return - } - - vpcHandler := resourceHandler.(irs.VPCHandler) - - testVPCHandlerListPrint() - - vpcIID := irs.IID{NameId: config.IbmVPC.Resources.VPC.NameId} - - subnetLists := config.IbmVPC.Resources.VPC.Subnets - var subnetInfoList []irs.SubnetInfo - for _, sb := range subnetLists { - info := irs.SubnetInfo{ - IId: irs.IID{ - NameId: sb.NameId, - }, - IPv4_CIDR: sb.IPv4CIDR, - } - subnetInfoList = append(subnetInfoList, info) - } - - VPCReqInfo := irs.VPCReqInfo{ - IId: vpcIID, - IPv4_CIDR: config.IbmVPC.Resources.VPC.IPv4CIDR, - SubnetInfoList: subnetInfoList, - } - addSubnet := config.IbmVPC.Resources.VPC.AddSubnet - addSubnetInfo := irs.SubnetInfo{ - IId: irs.IID{ - NameId: addSubnet.NameId, - }, - IPv4_CIDR: addSubnet.IPv4CIDR, - } - //deleteVpcid := irs.IID{ - // NameId: "bcr02a.tok02.774", - //} -Loop: - - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testVPCHandlerListPrint() - case 1: - cblogger.Info("Start ListVPC() ...") - if list, err := vpcHandler.ListVPC(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListVPC()") - case 2: - cblogger.Info("Start GetVPC() ...") - if vpcInfo, err := vpcHandler.GetVPC(vpcIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vpcInfo) - } - cblogger.Info("Finish GetVPC()") - case 3: - cblogger.Info("Start CreateVPC() ...") - if vpcInfo, err := vpcHandler.CreateVPC(VPCReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vpcInfo) - } - cblogger.Info("Finish CreateVPC()") - case 4: - cblogger.Info("Start DeleteVPC() ...") - if result, err := vpcHandler.DeleteVPC(vpcIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(result) - } - cblogger.Info("Finish DeleteVPC()") - case 5: - cblogger.Info("Start AddSubnet() ...") - if vpcInfo, err := vpcHandler.AddSubnet(vpcIID, addSubnetInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vpcInfo) - } - cblogger.Info("Finish AddSubnet()") - case 6: - cblogger.Info("Start RemoveSubnet() ...") - vpcInfo, err := vpcHandler.GetVPC(vpcIID) - if err != nil { - cblogger.Error(err) - } - if vpcInfo.SubnetInfoList != nil && len(vpcInfo.SubnetInfoList) > 0 { - firstSubnet := vpcInfo.SubnetInfoList[0] - cblogger.Info(fmt.Sprintf("RemoveSubnet : %s %s", firstSubnet.IId.NameId, firstSubnet.IPv4_CIDR)) - result, err := vpcHandler.RemoveSubnet(vpcIID, firstSubnet.IId) - if err != nil { - cblogger.Error(err) - } else { - spew.Dump(result) - } - } else { - err = errors.New("not exist subnet") - cblogger.Error(err) - } - cblogger.Info("Finish RemoveSubnet()") - case 7: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testVMHandlerListPrint() { - cblogger.Info("Test VMSpecHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListVM()") - cblogger.Info("2. GetVM()") - cblogger.Info("3. ListVMStatus()") - cblogger.Info("4. GetVMStatus()") - cblogger.Info("5. StartVM()") - cblogger.Info("6. RebootVM()") - cblogger.Info("7. SuspendVM()") - cblogger.Info("8. ResumeVM()") - cblogger.Info("9. TerminateVM()") - cblogger.Info("10. StartVM() - from MyImage") - cblogger.Info("11. Exit") -} - -func testVMHandler(config Config) { - resourceHandler, err := getResourceHandler("vm", config) - if err != nil { - cblogger.Error(err) - return - } - - vmHandler := resourceHandler.(irs.VMHandler) - - testVMHandlerListPrint() - - configsgIIDs := config.IbmVPC.Resources.Vm.SecurityGroupIIDs - var SecurityGroupIIDs []irs.IID - for _, sg := range configsgIIDs { - SecurityGroupIIDs = append(SecurityGroupIIDs, irs.IID{NameId: sg.NameId}) - } - var vmDataDiskIIDs []irs.IID - for _, dataDisk := range config.IbmVPC.Resources.Vm.DataDiskIIDs { - vmDataDiskIIDs = append(vmDataDiskIIDs, irs.IID{NameId: dataDisk.NameId}) - } - vmIID := irs.IID{ - NameId: config.IbmVPC.Resources.Vm.IID.NameId, - } - vmReqInfo := irs.VMReqInfo{ - IId: irs.IID{ - NameId: config.IbmVPC.Resources.Vm.IID.NameId, - }, - ImageIID: irs.IID{ - NameId: config.IbmVPC.Resources.Vm.ImageIID.NameId, - }, - VpcIID: irs.IID{ - NameId: config.IbmVPC.Resources.Vm.VpcIID.NameId, - }, - SubnetIID: irs.IID{ - NameId: config.IbmVPC.Resources.Vm.SubnetIID.NameId, - }, - VMSpecName: config.IbmVPC.Resources.Vm.VmSpecName, - KeyPairIID: irs.IID{ - NameId: config.IbmVPC.Resources.KeyPair.NameId, - }, - SecurityGroupIIDs: SecurityGroupIIDs, - RootDiskSize: "", - RootDiskType: "", - DataDiskIIDs: vmDataDiskIIDs, - VMUserId: config.IbmVPC.Resources.Vm.VMUserID, - VMUserPasswd: config.IbmVPC.Resources.Vm.VMUserPassword, - } - vmFromSnapshotReqInfo := irs.VMReqInfo{ - IId: irs.IID{ - NameId: config.IbmVPC.Resources.VmFromMyImage.IID.NameId, - }, - ImageIID: irs.IID{ - NameId: config.IbmVPC.Resources.VmFromMyImage.ImageIID.NameId, - }, - VpcIID: irs.IID{ - NameId: config.IbmVPC.Resources.VmFromMyImage.VpcIID.NameId, - }, - SubnetIID: irs.IID{ - NameId: config.IbmVPC.Resources.VmFromMyImage.SubnetIID.NameId, - }, - VMSpecName: config.IbmVPC.Resources.VmFromMyImage.VmSpecName, - KeyPairIID: irs.IID{ - NameId: config.IbmVPC.Resources.KeyPair.NameId, - }, - SecurityGroupIIDs: SecurityGroupIIDs, - RootDiskSize: "", - RootDiskType: "", - VMUserId: config.IbmVPC.Resources.VmFromMyImage.VMUserID, - VMUserPasswd: config.IbmVPC.Resources.VmFromMyImage.VMUserPassword, - } - -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testVMHandlerListPrint() - case 1: - cblogger.Info("Start ListVM() ...") - if list, err := vmHandler.ListVM(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListVM()") - case 2: - cblogger.Info("Start GetVM() ...") - if vm, err := vmHandler.GetVM(vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vm) - } - cblogger.Info("Finish GetVM()") - case 3: - cblogger.Info("Start ListVMStatus() ...") - if statusList, err := vmHandler.ListVMStatus(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(statusList) - } - cblogger.Info("Finish ListVMStatus()") - case 4: - cblogger.Info("Start GetVMStatus() ...") - if vmStatus, err := vmHandler.GetVMStatus(vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish GetVMStatus()") - case 5: - cblogger.Info("Start StartVM() ...") - vmReqInfo.ImageType = irs.PublicImage - if vm, err := vmHandler.StartVM(vmReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vm) - } - cblogger.Info("Finish StartVM()") - case 6: - cblogger.Info("Start RebootVM() ...") - if vmStatus, err := vmHandler.RebootVM(vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish RebootVM()") - case 7: - cblogger.Info("Start SuspendVM() ...") - if vmStatus, err := vmHandler.SuspendVM(vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish SuspendVM()") - case 8: - cblogger.Info("Start ResumeVM() ...") - if vmStatus, err := vmHandler.ResumeVM(vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish ResumeVM()") - case 9: - cblogger.Info("Start TerminateVM() ...") - if vmStatus, err := vmHandler.TerminateVM(vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish TerminateVM()") - case 10: - cblogger.Info("Start StartVM() - from MyImage ...") - vmFromSnapshotReqInfo.ImageType = irs.MyImage - if vmStatus, err := vmHandler.StartVM(vmFromSnapshotReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish StartVM() - from MyImage") - case 11: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testNLBHandlerListPrint() { - cblogger.Info("Test NLBHandler") - cblogger.Info("0. Print Menu") - 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") -} - -func testNLBHandler(config Config) { - resourceHandler, err := getResourceHandler("nlb", config) - if err != nil { - cblogger.Error(err) - return - } - - nlbHandler := resourceHandler.(irs.NLBHandler) - - testNLBHandlerListPrint() - - nlbIId := irs.IID{ - NameId: "test-nlb-01", - } - nlbCreateReqInfo := irs.NLBInfo{ - IId: irs.IID{ - NameId: "test-nlb-01", - }, - VpcIID: irs.IID{ - NameId: "nlb-tester-vpc", - }, - Listener: irs.ListenerInfo{ - Protocol: "TCP", - Port: "8080", - }, - VMGroup: irs.VMGroupInfo{ - Port: "8080", - Protocol: "TCP", - VMs: &[]irs.IID{ - {NameId: "nlb-tester-vm-02"}, - }, - }, - HealthChecker: irs.HealthCheckerInfo{ - Protocol: "TCP", - Port: "8080", - Interval: 10, - Timeout: 5, - Threshold: 10, - }, - } - updateListener := irs.ListenerInfo{ - Protocol: "TCP", - Port: "8087", - } - updateVMGroups := irs.VMGroupInfo{ - Protocol: "TCP", - Port: "8087", - } - addVMs := []irs.IID{ - {NameId: "nlb-tester-vm-02"}, - } - removeVMs := []irs.IID{ - {NameId: "nlb-tester-vm-03"}, - } - - updateHealthCheckerInfo := irs.HealthCheckerInfo{ - Protocol: "HTTP", - Port: "8087", - Interval: 11, - Threshold: 4, - Timeout: 5, - } -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testNLBHandlerListPrint() - case 1: - cblogger.Info("Start ListNLB() ...") - if list, err := nlbHandler.ListNLB(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListNLB()") - case 2: - cblogger.Info("Start GetNLB() ...") - if vm, err := nlbHandler.GetNLB(nlbIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vm) - } - cblogger.Info("Finish GetNLB()") - case 3: - cblogger.Info("Start CreateNLB() ...") - if createInfo, err := nlbHandler.CreateNLB(nlbCreateReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(createInfo) - } - cblogger.Info("Finish CreateNLB()") - case 4: - cblogger.Info("Start DeleteNLB() ...") - if vmStatus, err := nlbHandler.DeleteNLB(nlbIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - 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 result, err := nlbHandler.GetVMGroupHealthInfo(nlbIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(result) - } - 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") - break Loop - } - } - } -} - -func testDiskHandlerListPrint() { - cblogger.Info("Test DiskHandler") - cblogger.Info("0. Print Menu") - 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("8. Exit") -} - -func testDiskHandler(config Config) { - resourceHandler, err := getResourceHandler("disk", config) - if err != nil { - cblogger.Error(err) - return - } - diskHandler := resourceHandler.(irs.DiskHandler) - - testDiskHandlerListPrint() - configdisk := config.IbmVPC.Resources.DISK - - diskCreateReqInfo := irs.DiskInfo{ - IId: irs.IID{ - NameId: configdisk.IID.NameId, - }, - DiskSize: configdisk.DiskSize, - DiskType: configdisk.DiskType, - } - diskIId := irs.IID{ - NameId: configdisk.IID.NameId, - } - vmIID := irs.IID{ - NameId: config.IbmVPC.Resources.Vm.IID.NameId, - } -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testDiskHandlerListPrint() - case 1: - cblogger.Info("Start ListDisk() ...") - if list, err := diskHandler.ListDisk(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListDisk()") - case 2: - cblogger.Info("Start GetDisk() ...") - if vm, err := diskHandler.GetDisk(diskIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vm) - } - cblogger.Info("Finish GetDisk()") - case 3: - cblogger.Info("Start CreateDisk() ...") - if createInfo, err := diskHandler.CreateDisk(diskCreateReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(createInfo) - } - cblogger.Info("Finish CreateDisk()") - case 4: - cblogger.Info("Start DeleteDisk() ...") - if vmStatus, err := diskHandler.DeleteDisk(diskIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish DeleteDisk()") - case 5: - cblogger.Info("Start ChangeDiskSize() [+ 10G] ...") - - // set new size - intSize, _ := strconv.Atoi(configdisk.DiskSize) - intSize += 10 - - if nlbInfo, err := diskHandler.ChangeDiskSize(diskIId, strconv.Itoa(intSize)); err != nil { - cblogger.Error(err) - } else { - spew.Dump(nlbInfo) - } - cblogger.Info("Finish ChangeDiskSize() [+ 10G]") - case 6: - cblogger.Info("Start AttachDisk() ...") - - if info, err := diskHandler.AttachDisk(diskIId, vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(info) - } - cblogger.Info("Finish AttachDisk()") - case 7: - cblogger.Info("Start DetachDisk() ...") - if info, err := diskHandler.DetachDisk(diskIId, vmIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(info) - } - cblogger.Info("Finish DetachDisk()") - case 8: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testMyImageHandlerListPrint() { - cblogger.Info("Test MyImageHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListMyImage()") - cblogger.Info("2. GetMyImage()") - cblogger.Info("3. CreateMyImage()") - cblogger.Info("4. DeleteMyImage()") - cblogger.Info("5. Exit") -} - -func testMyImageHandler(config Config) { - resourceHandler, err := getResourceHandler("myimage", config) - if err != nil { - cblogger.Error(err) - return - } - - myImageHandler := resourceHandler.(irs.MyImageHandler) - - testMyImageHandlerListPrint() - configmyimage := config.IbmVPC.Resources.MYIMAGE - - snapshotCreateReqInfo := irs.MyImageInfo{ - IId: irs.IID{ - NameId: configmyimage.IID.NameId, - }, - SourceVM: irs.IID{ - NameId: configmyimage.SourceVMIID.NameId, - }, - } - myImageIId := irs.IID{ - NameId: configmyimage.IID.NameId, - } -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testMyImageHandlerListPrint() - case 1: - cblogger.Info("Start ListMyImage() ...") - if list, err := myImageHandler.ListMyImage(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListMyImage()") - case 2: - cblogger.Info("Start GetMyImage() ...") - if vm, err := myImageHandler.GetMyImage(myImageIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vm) - } - cblogger.Info("Finish GetMyImage()") - case 3: - cblogger.Info("Start CreateMyImage() ...") - if createInfo, err := myImageHandler.SnapshotVM(snapshotCreateReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(createInfo) - } - cblogger.Info("Finish CreateMyImage()") - case 4: - cblogger.Info("Start DeleteMyImage() ...") - if vmStatus, err := myImageHandler.DeleteMyImage(myImageIId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(vmStatus) - } - cblogger.Info("Finish DeleteMyImage()") - case 5: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testRegionZoneHandlerListPrint() { - cblogger.Info("Test RegionZoneHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListRegionZone()") - cblogger.Info("2. GetRegionZone()") - cblogger.Info("3. ListOrgRegion()") - cblogger.Info("4. ListOrgZone()") - cblogger.Info("5. Exit") -} - -func testRegionZoneHandler(config Config) { - resourceHandler, err := getResourceHandler("regionzone", config) - if err != nil { - cblogger.Error(err) - return - } - regionzoneHandler := resourceHandler.(irs.RegionZoneHandler) - - testRegionZoneHandlerListPrint() -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testRegionZoneHandlerListPrint() - case 1: - cblogger.Info("Start ListRegionZone() ...") - if listRegionZone, err := regionzoneHandler.ListRegionZone(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(listRegionZone) - } - cblogger.Info("Finish ListRegionZone()") - case 2: - cblogger.Info("Start GetRegionZone() ...") - var region string - fmt.Print("Enter Region Name: ") - if _, err := fmt.Scanln(®ion); err != nil { - cblogger.Error(err) - } - if listRegionZone, err := regionzoneHandler.GetRegionZone(region); err != nil { - cblogger.Error(err) - } else { - spew.Dump(listRegionZone) - } - cblogger.Info("Finish GetRegionZone()") - case 3: - cblogger.Info("Start ListOrgRegion() ...") - if listOrgRegion, err := regionzoneHandler.ListOrgRegion(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(listOrgRegion) - } - cblogger.Info("Finish ListOrgRegion()") - case 4: - cblogger.Info("Start ListOrgZone() ...") - if listOrgZone, err := regionzoneHandler.ListOrgZone(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(listOrgZone) - } - cblogger.Info("Finish ListOrgZone()") - case 5: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testPriceInfoHandlerListPrint() { - cblogger.Info("Test PriceInfoHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListProductFamily()") - cblogger.Info("2. GetPriceInfo()") - cblogger.Info("3. Exit") -} - -func testPriceInfoHandler(config Config) { - resourceHandler, err := getResourceHandler("price", config) - if err != nil { - cblogger.Error(err) - return - } - priceInfoHandler := resourceHandler.(irs.PriceInfoHandler) - - testPriceInfoHandlerListPrint() -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testPriceInfoHandlerListPrint() - case 1: - cblogger.Info("Start ListProductFamily() ...") - var region string - fmt.Print("Enter Region Name: ") - if _, err := fmt.Scanln(®ion); err != nil { - cblogger.Error(err) - } - if listProductFamily, err := priceInfoHandler.ListProductFamily(region); err != nil { - cblogger.Error(err) - } else { - spew.Dump(listProductFamily) - } - cblogger.Info("Finish ListProductFamily()") - case 2: - cblogger.Info("Start GetPriceInfo() ...") - fmt.Println("=== Enter Product Familiy ===") - in := bufio.NewReader(os.Stdin) - productFamiliy, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - - productFamiliy = strings.TrimSpace(productFamiliy) - var region string - fmt.Print("Enter Region Name: ") - if _, err := fmt.Scanln(®ion); err != nil { - cblogger.Error(err) - } - - var addFilterList string - var filterList []irs.KeyValue - for { - fmt.Print("Add filter list? (y/N): ") - _, err := fmt.Scanln(&addFilterList) - if err != nil || strings.ToLower(addFilterList) == "n" { - break - } - - fmt.Println("=== Enter key to filter ===") - in = bufio.NewReader(os.Stdin) - key, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - key = strings.TrimSpace(key) - - fmt.Println("=== Enter value to filter ===") - in = bufio.NewReader(os.Stdin) - value, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - value = strings.TrimSpace(value) - - filterList = append(filterList, irs.KeyValue{ - Key: key, - Value: value, - }) - } - - if priceInfo, err := priceInfoHandler.GetPriceInfo(productFamiliy, region, []irs.KeyValue{} /*filterList*/); err != nil { - cblogger.Error(err) - } else { - spew.Dump(priceInfo) - } - cblogger.Info("Finish GetPriceInfo()") - case 3: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testClusterHandlerListPrint() { - cblogger.Info("Test ClusterHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. ListCluster()") - cblogger.Info("2. GetCluster()") - cblogger.Info("3. CreateCluster()") - cblogger.Info("4. DeleteCluster()") //AddNodeGroup - cblogger.Info("5. AddNodeGroup()") - cblogger.Info("6. RemoveNodeGroup()") - cblogger.Info("7. SetNodeGroupAutoScaling()") - cblogger.Info("8. ChangeNodeGroupScaling()") - cblogger.Info("9. UpgradeCluster()") - cblogger.Info("10. Exit") -} - -func testClusterHandler(config Config) { - resourceHandler, err := getResourceHandler("cluster", config) - if err != nil { - cblogger.Error(err) - return - } - - clusterHandler := resourceHandler.(irs.ClusterHandler) - - testClusterHandlerListPrint() - configCluster := config.IbmVPC.Resources.CLUSTER - - clusterIID := irs.IID{NameId: configCluster.IID.NameId} - - var subnetIIDs []irs.IID - for _, configSubnetIID := range configCluster.Network.SubnetIIDs { - subnetIIDs = append(subnetIIDs, irs.IID{NameId: configSubnetIID.NameId}) - } - var securityGroupIID []irs.IID - for _, configSecurityGroupIID := range configCluster.Network.SecurityGroupIIDs { - securityGroupIID = append(securityGroupIID, irs.IID{NameId: configSecurityGroupIID.NameId}) - } - var nodeGroupList []irs.NodeGroupInfo - for _, configNodeGroup := range configCluster.NodeGroupList { - nodeGroupList = append(nodeGroupList, irs.NodeGroupInfo{ - IId: irs.IID{NameId: configNodeGroup.IID.NameId}, - VMSpecName: configNodeGroup.VMSpecName, - RootDiskType: configNodeGroup.RootDiskType, - RootDiskSize: configNodeGroup.RootDiskSize, - KeyPairIID: irs.IID{NameId: configNodeGroup.KeyPairIID.NameId}, - OnAutoScaling: configNodeGroup.OnAutoScaling, - DesiredNodeSize: configNodeGroup.DesireNodeSize, - MinNodeSize: configNodeGroup.MinNodeSize, - MaxNodeSize: configNodeGroup.MaxNodeSize, - }) - } - clusterCreateReqInfo := irs.ClusterInfo{ - IId: irs.IID{NameId: configCluster.IID.NameId}, - Version: configCluster.Version, - Network: irs.NetworkInfo{ - VpcIID: irs.IID{NameId: configCluster.Network.VpcIID.NameId}, - SubnetIIDs: subnetIIDs, - SecurityGroupIIDs: securityGroupIID, - }, - NodeGroupList: nodeGroupList, - } - nodeGroupReqInfo := irs.NodeGroupInfo{ - IId: irs.IID{NameId: configCluster.AdditionalNodeGroup.IID.NameId}, - VMSpecName: configCluster.AdditionalNodeGroup.VMSpecName, - OnAutoScaling: configCluster.AdditionalNodeGroup.OnAutoScaling, - DesiredNodeSize: configCluster.AdditionalNodeGroup.DesireNodeSize, - MinNodeSize: configCluster.AdditionalNodeGroup.MinNodeSize, - MaxNodeSize: configCluster.AdditionalNodeGroup.MaxNodeSize, - } - -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testClusterHandlerListPrint() - case 1: - cblogger.Info("Start ListCluster() ...") - if list, err := clusterHandler.ListCluster(); err != nil { - cblogger.Error(err) - } else { - spew.Dump(list) - } - cblogger.Info("Finish ListCluster()") - case 2: - cblogger.Info("Start GetCluster() ...") - if cluster, err := clusterHandler.GetCluster(clusterIID); err != nil { - cblogger.Error(err) - } else { - spew.Dump(cluster) - } - cblogger.Info("Finish GetCluster()") - case 3: - cblogger.Info("Start CreateCluster() ...") - if createInfo, err := clusterHandler.CreateCluster(clusterCreateReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(createInfo) - } - cblogger.Info("Finish CreateCluster()") - case 4: - cblogger.Info("Start DeleteCluster() ...") - if deleteClusterResult, err := clusterHandler.DeleteCluster(clusterCreateReqInfo.IId); err != nil { - cblogger.Error(err) - } else { - spew.Dump(deleteClusterResult) - } - cblogger.Info("Finish DeleteCluster()") - case 5: - cblogger.Info("Start AddNodeGroup() ...") - if addNodeGroupInfo, err := clusterHandler.AddNodeGroup(clusterCreateReqInfo.IId, nodeGroupReqInfo); err != nil { - cblogger.Error(err) - } else { - spew.Dump(addNodeGroupInfo) - } - cblogger.Info("Finish AddNodeGroup()") - case 6: - cblogger.Info("Start RemoveNodeGroup() ...") - if removeNodeGroupResult, err := clusterHandler.RemoveNodeGroup(clusterCreateReqInfo.IId, - irs.IID{NameId: configCluster.AdditionalNodeGroup.IID.NameId}); err != nil { - cblogger.Error(err) - } else { - spew.Dump(removeNodeGroupResult) - } - cblogger.Info("Finish RemoveNodeGroup()") - case 7: - cblogger.Info("Start SetNodeGroupAutoScaling() ...") - if setNodeGroupAutoScalingResult, err := clusterHandler.SetNodeGroupAutoScaling( - clusterCreateReqInfo.IId, - irs.IID{NameId: configCluster.ClusterUpdateInfos.TargetNodeGroupIID.NameId}, - configCluster.ClusterUpdateInfos.OnNodeGroupAutoScaling); err != nil { - cblogger.Error(err) - } else { - spew.Dump(setNodeGroupAutoScalingResult) - } - cblogger.Info("Finish SetNodeGroupAutoScaling()") - case 8: - cblogger.Info("Start ChangeNodeGroupScaling() ...") - if changeNodeGroupScalingResult, err := clusterHandler.ChangeNodeGroupScaling( - clusterCreateReqInfo.IId, - irs.IID{NameId: configCluster.ClusterUpdateInfos.TargetNodeGroupIID.NameId}, - configCluster.ClusterUpdateInfos.ChangeNodeGroupScaling.DesiredNodeSize, - configCluster.ClusterUpdateInfos.ChangeNodeGroupScaling.MinNodeSize, - configCluster.ClusterUpdateInfos.ChangeNodeGroupScaling.MaxNodeSize); err != nil { - cblogger.Error(err) - } else { - spew.Dump(changeNodeGroupScalingResult) - } - cblogger.Info("Finish ChangeNodeGroupScaling()") - case 9: - cblogger.Info("Start UpgradeCluster() ...") - if upgradeResult, err := clusterHandler.UpgradeCluster(clusterCreateReqInfo.IId, configCluster.ClusterUpdateInfos.UpgradeVersion); err != nil { - cblogger.Error(err) - } else { - spew.Dump(upgradeResult) - } - cblogger.Info("Finish UpgradeCluster()") - case 10: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func testTagHandlerListPrint() { - cblogger.Info("Test TagHandler") - cblogger.Info("0. Print Menu") - cblogger.Info("1. AddTag()") - cblogger.Info("2. ListTag()") - cblogger.Info("3. GetTag()") - cblogger.Info("4. RemoveTag()") - cblogger.Info("5. FindTag()") - cblogger.Info("6. Exit") -} - -func inputToRSType(input string) irs.RSType { - switch input { - case "all": - return irs.ALL - case "image": - return irs.IMAGE - case "vpc": - return irs.VPC - case "subnet": - return irs.SUBNET - case "sg": - return irs.SG - case "keypair": - return irs.KEY - case "vm": - return irs.VM - case "nlb": - return irs.NLB - case "disk": - return irs.DISK - case "myimage": - return irs.MYIMAGE - case "cluster": - return irs.CLUSTER - case "nodegroup": - return irs.NODEGROUP - default: - return "" - } -} - -func testTagHandler(config Config) { - resourceHandler, err := getResourceHandler("tag", config) - if err != nil { - cblogger.Error(err) - return - } - tagHandler := resourceHandler.(irs.TagHandler) - - testTagHandlerListPrint() -Loop: - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 0: - testTagHandlerListPrint() - case 1: - cblogger.Info("Start AddTag() ...") - fmt.Println("=== Enter resource type ===") - in := bufio.NewReader(os.Stdin) - resTypeStr, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resTypeStr = strings.TrimSpace(resTypeStr) - result := irs.RSTypeString(irs.RSType(resTypeStr)) - if strings.Contains(result, "not supported") { - cblogger.Error(result) - break Loop - } - resType := inputToRSType(resTypeStr) - - fmt.Println("=== Enter name of the resource ===") - in = bufio.NewReader(os.Stdin) - resName, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resName = strings.TrimSpace(resName) - - fmt.Println("=== Enter tag's key ===") - in = bufio.NewReader(os.Stdin) - tagKey, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - tagKey = strings.TrimSpace(tagKey) - - fmt.Println("=== Enter tag's value ===") - in = bufio.NewReader(os.Stdin) - tagValue, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - tagValue = strings.TrimSpace(tagValue) - - if tagKeyValue, err := tagHandler.AddTag(resType, irs.IID{NameId: resName}, irs.KeyValue{Key: tagKey, Value: tagValue}); err != nil { - cblogger.Error(err) - } else { - spew.Dump(tagKeyValue) - } - cblogger.Info("Finish AddTag()") - case 2: - cblogger.Info("Start ListTag() ...") - fmt.Println("=== Enter resource type ===") - in := bufio.NewReader(os.Stdin) - resTypeStr, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resTypeStr = strings.TrimSpace(resTypeStr) - result := irs.RSTypeString(irs.RSType(resTypeStr)) - if strings.Contains(result, "not supported") { - cblogger.Error(result) - break Loop - } - resType := inputToRSType(resTypeStr) - - fmt.Println("=== Enter name of the resource ===") - in = bufio.NewReader(os.Stdin) - resName, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resName = strings.TrimSpace(resName) - - if tagList, err := tagHandler.ListTag(resType, irs.IID{NameId: resName}); err != nil { - cblogger.Error(err) - } else { - spew.Dump(tagList) - } - cblogger.Info("Finish ListTag()") - case 3: - cblogger.Info("Start GetTag() ...") - fmt.Println("=== Enter resource type ===") - in := bufio.NewReader(os.Stdin) - resTypeStr, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resTypeStr = strings.TrimSpace(resTypeStr) - result := irs.RSTypeString(irs.RSType(resTypeStr)) - if strings.Contains(result, "not supported") { - cblogger.Error(result) - break Loop - } - resType := inputToRSType(resTypeStr) - - fmt.Println("=== Enter name of the resource ===") - in = bufio.NewReader(os.Stdin) - resName, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resName = strings.TrimSpace(resName) - - fmt.Println("=== Enter tag's key ===") - in = bufio.NewReader(os.Stdin) - tagKey, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - tagKey = strings.TrimSpace(tagKey) - - if tagKeyValue, err := tagHandler.GetTag(resType, irs.IID{NameId: resName}, tagKey); err != nil { - cblogger.Error(err) - } else { - spew.Dump(tagKeyValue) - } - cblogger.Info("Finish GetTag()") - case 4: - cblogger.Info("Start RemoveTag() ...") - fmt.Println("=== Enter resource type ===") - in := bufio.NewReader(os.Stdin) - resTypeStr, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resTypeStr = strings.TrimSpace(resTypeStr) - result := irs.RSTypeString(irs.RSType(resTypeStr)) - if strings.Contains(result, "not supported") { - cblogger.Error(result) - break Loop - } - resType := inputToRSType(resTypeStr) - - fmt.Println("=== Enter name of the resource ===") - in = bufio.NewReader(os.Stdin) - resName, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resName = strings.TrimSpace(resName) - - fmt.Println("=== Enter tag's key ===") - in = bufio.NewReader(os.Stdin) - tagKey, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - tagKey = strings.TrimSpace(tagKey) - - if tagKeyValue, err := tagHandler.RemoveTag(resType, irs.IID{NameId: resName}, tagKey); err != nil { - cblogger.Error(err) - } else { - spew.Dump(tagKeyValue) - } - cblogger.Info("Finish RemoveTag()") - case 5: - cblogger.Info("Start FindTag() ...") - fmt.Println("=== Enter resource type ===") - in := bufio.NewReader(os.Stdin) - resTypeStr, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - resTypeStr = strings.TrimSpace(resTypeStr) - result := irs.RSTypeString(irs.RSType(resTypeStr)) - if strings.Contains(result, "not supported") { - cblogger.Error(result) - break Loop - } - resType := inputToRSType(resTypeStr) - - fmt.Println("=== Enter keyword ===") - in = bufio.NewReader(os.Stdin) - keyword, err := in.ReadString('\n') - if err != nil { - cblogger.Error(err) - } - keyword = strings.TrimSpace(keyword) - - if tagKeyValue, err := tagHandler.FindTag(resType, keyword); err != nil { - cblogger.Error(err) - } else { - spew.Dump(tagKeyValue) - } - cblogger.Info("Finish FindTag()") - case 6: - cblogger.Info("Exit") - break Loop - } - } - } -} - -func main() { - showTestHandlerInfo() - config := readConfigFile() - -Loop: - - for { - var commandNum int - inputCnt, err := fmt.Scan(&commandNum) - if err != nil { - cblogger.Error(err) - } - - if inputCnt == 1 { - switch commandNum { - case 1: - testImageHandler(config) - showTestHandlerInfo() - case 2: - testSecurityHandler(config) - showTestHandlerInfo() - case 3: - testVPCHandler(config) - showTestHandlerInfo() - case 4: - testKeyPairHandler(config) - showTestHandlerInfo() - case 5: - testVMSpecHandler(config) - showTestHandlerInfo() - case 6: - testVMHandler(config) - showTestHandlerInfo() - case 7: - testNLBHandler(config) - showTestHandlerInfo() - case 8: - testDiskHandler(config) - showTestHandlerInfo() - case 9: - testMyImageHandler(config) - showTestHandlerInfo() - case 10: - testRegionZoneHandler(config) - showTestHandlerInfo() - case 11: - testPriceInfoHandler(config) - showTestHandlerInfo() - case 12: - testClusterHandler(config) - showTestHandlerInfo() - case 13: - testTagHandler(config) - showTestHandlerInfo() - case 14: - cblogger.Info("Exit Test ResourceHandler Program") - break Loop - } - } - } -} +package main + +import ( + "bufio" + "errors" + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + + cblog "github.com/cloud-barista/cb-log" + ibm "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc" + idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" + irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" + "github.com/davecgh/go-spew/spew" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" +) + +type Config struct { + IbmVPC struct { + ApiKey string `yaml:"apiKey"` + Region string `yaml:"region"` + Zone string `yaml:"zone"` + Resources struct { + Image struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"image"` + Security struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + VpcIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"VpcIID"` + Rules []struct { + FromPort string `yaml:"FromPort"` + ToPort string `yaml:"ToPort"` + IPProtocol string `yaml:"IPProtocol"` + CIDR string `yaml:"CIDR"` + Direction string `yaml:"Direction"` + } `yaml:"rules"` + AddRules []struct { + FromPort string `yaml:"FromPort"` + ToPort string `yaml:"ToPort"` + IPProtocol string `yaml:"IPProtocol"` + CIDR string `yaml:"CIDR"` + Direction string `yaml:"Direction"` + } `yaml:"addRules"` + RemoveRules []struct { + FromPort string `yaml:"FromPort"` + ToPort string `yaml:"ToPort"` + IPProtocol string `yaml:"IPProtocol"` + CIDR string `yaml:"CIDR"` + Direction string `yaml:"Direction"` + } `yaml:"removeRules"` + } `yaml:"security"` + KeyPair struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"keyPair"` + VmSpec struct { + NameId string `yaml:"nameId"` + } `yaml:"vmSpec"` + VPC struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + IPv4CIDR string `yaml:"ipv4CIDR"` + Subnets []struct { + NameId string `yaml:"nameId"` + IPv4CIDR string `yaml:"ipv4CIDR"` + } `yaml:"subnets"` + AddSubnet struct { + NameId string `yaml:"nameId"` + IPv4CIDR string `yaml:"ipv4CIDR"` + } `yaml:"addSubnet"` + } `yaml:"vpc"` + Vm struct { + IID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"IID"` + ImageIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"ImageIID"` + VmSpecName string `yaml:"VmSpecName"` + KeyPairIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"KeyPairIID"` + VpcIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"VpcIID"` + SubnetIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"SubnetIID"` + SecurityGroupIIDs []struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"SecurityGroupIIDs"` + DataDiskIIDs []struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"DataDiskIIDs"` + VMUserID string `yaml:"VMUserID"` + VMUserPassword string `yaml:"VMUserPassword"` + } `yaml:"vm"` + VmFromMyImage struct { + IID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"IID"` + ImageIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"ImageIID"` + VmSpecName string `yaml:"VmSpecName"` + KeyPairIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"KeyPairIID"` + VpcIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"VpcIID"` + SubnetIID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"SubnetIID"` + SecurityGroupIIDs []struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"SecurityGroupIIDs"` + VMUserID string `yaml:"VMUserID"` + VMUserPassword string `yaml:"VMUserPassword"` + } `yaml:"VmFromMyImage"` + DISK struct { + IID struct { + NameId string `yaml:"nameId"` + SystemId string `yaml:"systemId"` + } `yaml:"IID"` + DiskSize string `yaml:"DiskSize"` + DiskType string `yaml:"DiskType"` + } `yaml:"disk"` + MYIMAGE struct { + IID struct { + NameId string `yaml:"nameId"` + } `yaml:"IID"` + SourceVMIID struct { + NameId string `yaml:"nameId"` + } `yaml:"SourceVMIID"` + } `yaml:"myimage"` + CLUSTER struct { + IID struct { + NameId string `yaml:"nameId"` + } `yaml:"IID"` + Version string `yaml:"version"` + Network struct { + VpcIID struct { + NameId string `yaml:"nameId"` + } `yaml:"vpcIID"` + SubnetIIDs []struct { + NameId string `yaml:"nameId"` + } `yaml:"subnetIIDs"` + SecurityGroupIIDs []struct { + NameId string `yaml:"nameId"` + } `yaml:"securityGroupIIDs"` + } `yaml:"network"` + NodeGroupList []struct { + IID struct { + NameId string `yaml:"nameId"` + } `yaml:"IID"` + VMSpecName string `yaml:"vmSpecName"` + RootDiskType string `yaml:"rootDiskType"` + RootDiskSize string `yaml:"rootDiskSize"` + KeyPairIID struct { + NameId string `yaml:"nameId"` + } `yaml:"keyPairIID"` + OnAutoScaling bool `yaml:"onAutoScaling"` + DesireNodeSize int `yaml:"desireNodeSize"` + MinNodeSize int `yaml:"minNodeSize"` + MaxNodeSize int `yaml:"maxNodeSize"` + } `yaml:"nodeGroupList"` + AdditionalNodeGroup struct { + IID struct { + NameId string `yaml:"nameId"` + } `yaml:"IID"` + VMSpecName string `yaml:"vmSpecName"` + RootDiskType string `yaml:"rootDiskType"` + RootDiskSize string `yaml:"rootDiskSize"` + KeyPairIID struct { + NameId string `yaml:"nameId"` + } `yaml:"keyPairIID"` + OnAutoScaling bool `yaml:"onAutoScaling"` + DesireNodeSize int `yaml:"desireNodeSize"` + MinNodeSize int `yaml:"minNodeSize"` + MaxNodeSize int `yaml:"maxNodeSize"` + } `yaml:"additionalNodeGroup"` + ClusterUpdateInfos struct { + TargetNodeGroupIID struct { + NameId string `yaml:"nameId"` + } `yaml:"targetNodeGroupIID"` + OnNodeGroupAutoScaling bool `yaml:"onNodeGroupAutoScaling"` + ChangeNodeGroupScaling struct { + DesiredNodeSize int `yaml:"desiredNodeSize"` + MinNodeSize int `yaml:"minNodeSize"` + MaxNodeSize int `yaml:"maxNodeSize"` + } `yaml:"changeNodeGroupScaling"` + UpgradeVersion string `yaml:"upgradeVersion"` + } `yaml:"clusterUpdateInfos"` + } `yaml:"cluster"` + } `yaml:"resources"` + } `yaml:"ibmvpc"` +} + +var cblogger *logrus.Logger + +func init() { + // cblog is a global variable. + cblogger = cblog.GetLogger("CB-SPIDER") +} + +func readConfigFile() Config { + // Set Environment Value of Project Root Path + rootPath := os.Getenv("CBSPIDER_ROOT") + data, err := ioutil.ReadFile(rootPath + "/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/conf/config.yaml") + if err != nil { + cblogger.Error(err) + } + + var config Config + err = yaml.Unmarshal(data, &config) + if err != nil { + cblogger.Error(err) + } + + return config +} + +func showTestHandlerInfo() { + cblogger.Info("==========================================================") + cblogger.Info("[Test ResourceHandler]") + cblogger.Info("1. ImageHandler") + cblogger.Info("2. SecurityHandler") + cblogger.Info("3. VPCHandler") + cblogger.Info("4. KeyPairHandler") + cblogger.Info("5. VmSpecHandler") + cblogger.Info("6. VmHandler") + cblogger.Info("7. NLBHandler") + cblogger.Info("8. DiskHandler") + cblogger.Info("9. MyImageHandler") + cblogger.Info("10. RegionZoneHandler") + cblogger.Info("11. PriceInfoHandler") + cblogger.Info("12. ClusterHandler") + cblogger.Info("13. TagHandler") + cblogger.Info("14. Exit") + cblogger.Info("==========================================================") +} + +func getResourceHandler(resourceType string, config Config) (interface{}, error) { + ibmCloudConnectionIfo := idrv.ConnectionInfo{ + CredentialInfo: idrv.CredentialInfo{ + ApiKey: config.IbmVPC.ApiKey, + }, + RegionInfo: idrv.RegionInfo{ + Region: config.IbmVPC.Region, + Zone: config.IbmVPC.Zone, + }, + } + + var cloudDriver idrv.CloudDriver + cloudDriver = new(ibm.IbmCloudDriver) + + ibmCon, err := cloudDriver.ConnectCloud(ibmCloudConnectionIfo) + if err != nil { + return nil, err + } + var resourceHandler interface{} + + switch resourceType { + case "image": + resourceHandler, err = ibmCon.CreateImageHandler() + case "security": + resourceHandler, err = ibmCon.CreateSecurityHandler() + case "vpc": + resourceHandler, err = ibmCon.CreateVPCHandler() + case "keypair": + resourceHandler, err = ibmCon.CreateKeyPairHandler() + case "vmspec": + resourceHandler, err = ibmCon.CreateVMSpecHandler() + case "vm": + resourceHandler, err = ibmCon.CreateVMHandler() + // TODO interface Change + case "nlb": + //return nil, errors.New("not support") + resourceHandler, err = ibmCon.CreateNLBHandler() + case "disk": + resourceHandler, err = ibmCon.CreateDiskHandler() + case "myimage": + resourceHandler, err = ibmCon.CreateMyImageHandler() + case "regionzone": + resourceHandler, err = ibmCon.CreateRegionZoneHandler() + case "price": + resourceHandler, err = ibmCon.CreatePriceInfoHandler() + case "cluster": + resourceHandler, err = ibmCon.CreateClusterHandler() + case "tag": + resourceHandler, err = ibmCon.CreateTagHandler() + } + + return resourceHandler, nil +} +func testImageHandlerListPrint() { + cblogger.Info("Test ImageHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListImage()") + cblogger.Info("2. GetImage()") + cblogger.Info("3. CreateImage()") + cblogger.Info("4. DeleteImage()") + cblogger.Info("5. Exit") +} + +func testImageHandler(config Config) { + resourceHandler, err := getResourceHandler("image", config) + if err != nil { + cblogger.Error(err) + return + } + + imageHandler := resourceHandler.(irs.ImageHandler) + + testImageHandlerListPrint() + + imageIID := irs.IID{NameId: config.IbmVPC.Resources.Image.NameId} + +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testImageHandlerListPrint() + case 1: + cblogger.Info("Start ListImage() ...") + if list, err := imageHandler.ListImage(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListImage()") + case 2: + cblogger.Info("Start GetImage() ...") + if imageInfo, err := imageHandler.GetImage(imageIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(imageInfo) + } + cblogger.Info("Finish GetImage()") + case 3: + cblogger.Info("Start CreateImage() ...") + cblogger.Info("Finish CreateImage()") + case 4: + cblogger.Info("Start DeleteImage() ...") + cblogger.Info("Finish DeleteImage()") + case 5: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testSecurityHandlerListPrint() { + cblogger.Info("Test securityHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListSecurity()") + cblogger.Info("2. GetSecurity()") + cblogger.Info("3. CreateSecurity()") + cblogger.Info("4. DeleteSecurity()") + cblogger.Info("5. AddRules()") + cblogger.Info("6. RemoveRules()") + cblogger.Info("7. Exit") +} + +// SecurityGroup +func testSecurityHandler(config Config) { + resourceHandler, err := getResourceHandler("security", config) + if err != nil { + cblogger.Error(err) + return + } + + securityHandler := resourceHandler.(irs.SecurityHandler) + + testSecurityHandlerListPrint() + + securityIId := irs.IID{NameId: config.IbmVPC.Resources.Security.NameId} + securityRules := config.IbmVPC.Resources.Security.Rules + var securityRulesInfos []irs.SecurityRuleInfo + for _, securityRule := range securityRules { + infos := irs.SecurityRuleInfo{ + FromPort: securityRule.FromPort, + ToPort: securityRule.ToPort, + IPProtocol: securityRule.IPProtocol, + Direction: securityRule.Direction, + CIDR: securityRule.CIDR, + } + securityRulesInfos = append(securityRulesInfos, infos) + } + targetVPCIId := irs.IID{ + NameId: config.IbmVPC.Resources.Security.VpcIID.NameId, + } + securityAddRules := config.IbmVPC.Resources.Security.AddRules + var securityAddRulesInfos []irs.SecurityRuleInfo + for _, securityRule := range securityAddRules { + infos := irs.SecurityRuleInfo{ + FromPort: securityRule.FromPort, + ToPort: securityRule.ToPort, + IPProtocol: securityRule.IPProtocol, + Direction: securityRule.Direction, + CIDR: securityRule.CIDR, + } + securityAddRulesInfos = append(securityAddRulesInfos, infos) + } + securityRemoveRules := config.IbmVPC.Resources.Security.RemoveRules + var securityRemoveRulesInfos []irs.SecurityRuleInfo + for _, securityRule := range securityRemoveRules { + infos := irs.SecurityRuleInfo{ + FromPort: securityRule.FromPort, + ToPort: securityRule.ToPort, + IPProtocol: securityRule.IPProtocol, + Direction: securityRule.Direction, + CIDR: securityRule.CIDR, + } + securityRemoveRulesInfos = append(securityRemoveRulesInfos, infos) + } +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + fmt.Println(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testSecurityHandlerListPrint() + case 1: + fmt.Println("Start ListSecurity() ...") + if securityList, err := securityHandler.ListSecurity(); err != nil { + fmt.Println(err) + } else { + spew.Dump(securityList) + } + fmt.Println("Finish ListSecurity()") + case 2: + fmt.Println("Start GetSecurity() ...") + if secGroupInfo, err := securityHandler.GetSecurity(securityIId); err != nil { + fmt.Println(err) + } else { + spew.Dump(secGroupInfo) + } + fmt.Println("Finish GetSecurity()") + case 3: + fmt.Println("Start CreateSecurity() ...") + reqInfo := irs.SecurityReqInfo{ + IId: securityIId, + SecurityRules: &securityRulesInfos, + VpcIID: targetVPCIId, + } + + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + reqInfo.TagList = tagList + + security, err := securityHandler.CreateSecurity(reqInfo) + if err != nil { + fmt.Println(err) + } else { + spew.Dump(security) + } + //securityGroupId = security.IId + fmt.Println("Finish CreateSecurity()") + case 4: + fmt.Println("Start DeleteSecurity() ...") + if ok, err := securityHandler.DeleteSecurity(securityIId); !ok { + fmt.Println(err) + } + fmt.Println("Finish DeleteSecurity()") + case 5: + fmt.Println("Start AddRules() ...") + security, err := securityHandler.AddRules(securityIId, &securityAddRulesInfos) + if err != nil { + fmt.Println(err) + } else { + spew.Dump(security) + } + fmt.Println("Finish AddRules()") + case 6: + fmt.Println("Start RemoveRules() ...") + if ok, err := securityHandler.RemoveRules(securityIId, &securityRemoveRulesInfos); !ok { + fmt.Println(err) + } + fmt.Println("Finish RemoveRules()") + case 7: + fmt.Println("Exit") + break Loop + } + } + } +} +func testKeyPairHandlerListPrint() { + cblogger.Info("Test KeyPairHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListKey()") + cblogger.Info("2. GetKey()") + cblogger.Info("3. CreateKey()") + cblogger.Info("4. DeleteKey()") + cblogger.Info("5. Exit") +} +func testKeyPairHandler(config Config) { + resourceHandler, err := getResourceHandler("keypair", config) + if err != nil { + cblogger.Error(err) + return + } + + keyPairHandler := resourceHandler.(irs.KeyPairHandler) + + testKeyPairHandlerListPrint() + + keypairIId := irs.IID{ + NameId: config.IbmVPC.Resources.KeyPair.NameId, + } + +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testKeyPairHandlerListPrint() + case 1: + cblogger.Info("Start ListKey() ...") + if keyPairList, err := keyPairHandler.ListKey(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(keyPairList) + } + cblogger.Info("Finish ListKey()") + case 2: + cblogger.Info("Start GetKey() ...") + if keyPairInfo, err := keyPairHandler.GetKey(keypairIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(keyPairInfo) + } + cblogger.Info("Finish GetKey()") + case 3: + cblogger.Info("Start CreateKey() ...") + reqInfo := irs.KeyPairReqInfo{ + IId: keypairIId, + } + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + reqInfo.TagList = tagList + + if keyInfo, err := keyPairHandler.CreateKey(reqInfo); err != nil { + cblogger.Error(err) + } else { + keypairIId = keyInfo.IId + spew.Dump(keyInfo) + } + cblogger.Info("Finish CreateKey()") + case 4: + cblogger.Info("Start DeleteKey() ...") + if ok, err := keyPairHandler.DeleteKey(keypairIId); !ok { + cblogger.Error(err) + } + cblogger.Info("Finish DeleteKey()") + case 5: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testVMSpecHandlerListPrint() { + cblogger.Info("Test VMSpecHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListVMSpec()") + cblogger.Info("2. GetVMSpec()") + cblogger.Info("3. ListOrgVMSpec()") + cblogger.Info("4. GetOrgVMSpec()") + cblogger.Info("5. Exit") +} + +func testVMSpecHandler(config Config) { + resourceHandler, err := getResourceHandler("vmspec", config) + if err != nil { + cblogger.Error(err) + return + } + + vmSpecHandler := resourceHandler.(irs.VMSpecHandler) + + testVMSpecHandlerListPrint() + +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testVMSpecHandlerListPrint() + case 1: + cblogger.Info("Start ListVMSpec() ...") + if list, err := vmSpecHandler.ListVMSpec(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListVMSpec()") + case 2: + cblogger.Info("Start GetVMSpec() ...") + if vmSpecInfo, err := vmSpecHandler.GetVMSpec(config.IbmVPC.Resources.VmSpec.NameId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmSpecInfo) + } + cblogger.Info("Finish GetVMSpec()") + case 3: + cblogger.Info("Start ListOrgVMSpec() ...") + if listStr, err := vmSpecHandler.ListOrgVMSpec(); err != nil { + cblogger.Error(err) + } else { + fmt.Println(listStr) + } + cblogger.Info("Finish ListOrgVMSpec()") + case 4: + cblogger.Info("Start GetOrgVMSpec() ...") + if vmSpecStr, err := vmSpecHandler.GetOrgVMSpec(config.IbmVPC.Resources.VmSpec.NameId); err != nil { + cblogger.Error(err) + } else { + fmt.Println(vmSpecStr) + } + cblogger.Info("Finish GetOrgVMSpec()") + case 5: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testVPCHandlerListPrint() { + cblogger.Info("Test VPCHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListVPC()") + cblogger.Info("2. GetVPC()") + cblogger.Info("3. CreateVPC()") + cblogger.Info("4. DeleteVPC()") + cblogger.Info("5. AddSubnet()") + cblogger.Info("6. RemoveSubnet()") + cblogger.Info("7. Exit") +} + +func testVPCHandler(config Config) { + resourceHandler, err := getResourceHandler("vpc", config) + if err != nil { + cblogger.Error(err) + return + } + + vpcHandler := resourceHandler.(irs.VPCHandler) + + testVPCHandlerListPrint() + + vpcIID := irs.IID{NameId: config.IbmVPC.Resources.VPC.NameId} + + subnetLists := config.IbmVPC.Resources.VPC.Subnets + var subnetInfoList []irs.SubnetInfo + for _, sb := range subnetLists { + info := irs.SubnetInfo{ + IId: irs.IID{ + NameId: sb.NameId, + }, + IPv4_CIDR: sb.IPv4CIDR, + } + subnetInfoList = append(subnetInfoList, info) + } + + VPCReqInfo := irs.VPCReqInfo{ + IId: vpcIID, + IPv4_CIDR: config.IbmVPC.Resources.VPC.IPv4CIDR, + SubnetInfoList: subnetInfoList, + } + addSubnet := config.IbmVPC.Resources.VPC.AddSubnet + addSubnetInfo := irs.SubnetInfo{ + IId: irs.IID{ + NameId: addSubnet.NameId, + }, + IPv4_CIDR: addSubnet.IPv4CIDR, + } + //deleteVpcid := irs.IID{ + // NameId: "bcr02a.tok02.774", + //} +Loop: + + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testVPCHandlerListPrint() + case 1: + cblogger.Info("Start ListVPC() ...") + if list, err := vpcHandler.ListVPC(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListVPC()") + case 2: + cblogger.Info("Start GetVPC() ...") + if vpcInfo, err := vpcHandler.GetVPC(vpcIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vpcInfo) + } + cblogger.Info("Finish GetVPC()") + case 3: + cblogger.Info("Start CreateVPC() ...") + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + VPCReqInfo.TagList = tagList + + if vpcInfo, err := vpcHandler.CreateVPC(VPCReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vpcInfo) + } + cblogger.Info("Finish CreateVPC()") + case 4: + cblogger.Info("Start DeleteVPC() ...") + if result, err := vpcHandler.DeleteVPC(vpcIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(result) + } + cblogger.Info("Finish DeleteVPC()") + case 5: + cblogger.Info("Start AddSubnet() ...") + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + addSubnetInfo.TagList = tagList + + if vpcInfo, err := vpcHandler.AddSubnet(vpcIID, addSubnetInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vpcInfo) + } + cblogger.Info("Finish AddSubnet()") + case 6: + cblogger.Info("Start RemoveSubnet() ...") + vpcInfo, err := vpcHandler.GetVPC(vpcIID) + if err != nil { + cblogger.Error(err) + } + if vpcInfo.SubnetInfoList != nil && len(vpcInfo.SubnetInfoList) > 0 { + firstSubnet := vpcInfo.SubnetInfoList[0] + cblogger.Info(fmt.Sprintf("RemoveSubnet : %s %s", firstSubnet.IId.NameId, firstSubnet.IPv4_CIDR)) + result, err := vpcHandler.RemoveSubnet(vpcIID, firstSubnet.IId) + if err != nil { + cblogger.Error(err) + } else { + spew.Dump(result) + } + } else { + err = errors.New("not exist subnet") + cblogger.Error(err) + } + cblogger.Info("Finish RemoveSubnet()") + case 7: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testVMHandlerListPrint() { + cblogger.Info("Test VMSpecHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListVM()") + cblogger.Info("2. GetVM()") + cblogger.Info("3. ListVMStatus()") + cblogger.Info("4. GetVMStatus()") + cblogger.Info("5. StartVM()") + cblogger.Info("6. RebootVM()") + cblogger.Info("7. SuspendVM()") + cblogger.Info("8. ResumeVM()") + cblogger.Info("9. TerminateVM()") + cblogger.Info("10. StartVM() - from MyImage") + cblogger.Info("11. Exit") +} + +func testVMHandler(config Config) { + resourceHandler, err := getResourceHandler("vm", config) + if err != nil { + cblogger.Error(err) + return + } + + vmHandler := resourceHandler.(irs.VMHandler) + + testVMHandlerListPrint() + + configsgIIDs := config.IbmVPC.Resources.Vm.SecurityGroupIIDs + var SecurityGroupIIDs []irs.IID + for _, sg := range configsgIIDs { + SecurityGroupIIDs = append(SecurityGroupIIDs, irs.IID{NameId: sg.NameId}) + } + var vmDataDiskIIDs []irs.IID + for _, dataDisk := range config.IbmVPC.Resources.Vm.DataDiskIIDs { + vmDataDiskIIDs = append(vmDataDiskIIDs, irs.IID{NameId: dataDisk.NameId}) + } + vmIID := irs.IID{ + NameId: config.IbmVPC.Resources.Vm.IID.NameId, + } + vmReqInfo := irs.VMReqInfo{ + IId: irs.IID{ + NameId: config.IbmVPC.Resources.Vm.IID.NameId, + }, + ImageIID: irs.IID{ + NameId: config.IbmVPC.Resources.Vm.ImageIID.NameId, + }, + VpcIID: irs.IID{ + NameId: config.IbmVPC.Resources.Vm.VpcIID.NameId, + }, + SubnetIID: irs.IID{ + NameId: config.IbmVPC.Resources.Vm.SubnetIID.NameId, + }, + VMSpecName: config.IbmVPC.Resources.Vm.VmSpecName, + KeyPairIID: irs.IID{ + NameId: config.IbmVPC.Resources.KeyPair.NameId, + }, + SecurityGroupIIDs: SecurityGroupIIDs, + RootDiskSize: "", + RootDiskType: "", + DataDiskIIDs: vmDataDiskIIDs, + VMUserId: config.IbmVPC.Resources.Vm.VMUserID, + VMUserPasswd: config.IbmVPC.Resources.Vm.VMUserPassword, + } + vmFromSnapshotReqInfo := irs.VMReqInfo{ + IId: irs.IID{ + NameId: config.IbmVPC.Resources.VmFromMyImage.IID.NameId, + }, + ImageIID: irs.IID{ + NameId: config.IbmVPC.Resources.VmFromMyImage.ImageIID.NameId, + }, + VpcIID: irs.IID{ + NameId: config.IbmVPC.Resources.VmFromMyImage.VpcIID.NameId, + }, + SubnetIID: irs.IID{ + NameId: config.IbmVPC.Resources.VmFromMyImage.SubnetIID.NameId, + }, + VMSpecName: config.IbmVPC.Resources.VmFromMyImage.VmSpecName, + KeyPairIID: irs.IID{ + NameId: config.IbmVPC.Resources.KeyPair.NameId, + }, + SecurityGroupIIDs: SecurityGroupIIDs, + RootDiskSize: "", + RootDiskType: "", + VMUserId: config.IbmVPC.Resources.VmFromMyImage.VMUserID, + VMUserPasswd: config.IbmVPC.Resources.VmFromMyImage.VMUserPassword, + } + +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testVMHandlerListPrint() + case 1: + cblogger.Info("Start ListVM() ...") + if list, err := vmHandler.ListVM(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListVM()") + case 2: + cblogger.Info("Start GetVM() ...") + if vm, err := vmHandler.GetVM(vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vm) + } + cblogger.Info("Finish GetVM()") + case 3: + cblogger.Info("Start ListVMStatus() ...") + if statusList, err := vmHandler.ListVMStatus(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(statusList) + } + cblogger.Info("Finish ListVMStatus()") + case 4: + cblogger.Info("Start GetVMStatus() ...") + if vmStatus, err := vmHandler.GetVMStatus(vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish GetVMStatus()") + case 5: + cblogger.Info("Start StartVM() ...") + vmReqInfo.ImageType = irs.PublicImage + + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + vmReqInfo.TagList = tagList + + if vm, err := vmHandler.StartVM(vmReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vm) + } + cblogger.Info("Finish StartVM()") + case 6: + cblogger.Info("Start RebootVM() ...") + if vmStatus, err := vmHandler.RebootVM(vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish RebootVM()") + case 7: + cblogger.Info("Start SuspendVM() ...") + if vmStatus, err := vmHandler.SuspendVM(vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish SuspendVM()") + case 8: + cblogger.Info("Start ResumeVM() ...") + if vmStatus, err := vmHandler.ResumeVM(vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish ResumeVM()") + case 9: + cblogger.Info("Start TerminateVM() ...") + if vmStatus, err := vmHandler.TerminateVM(vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish TerminateVM()") + case 10: + cblogger.Info("Start StartVM() - from MyImage ...") + vmFromSnapshotReqInfo.ImageType = irs.MyImage + if vmStatus, err := vmHandler.StartVM(vmFromSnapshotReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish StartVM() - from MyImage") + case 11: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testNLBHandlerListPrint() { + cblogger.Info("Test NLBHandler") + cblogger.Info("0. Print Menu") + 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") +} + +func testNLBHandler(config Config) { + resourceHandler, err := getResourceHandler("nlb", config) + if err != nil { + cblogger.Error(err) + return + } + + nlbHandler := resourceHandler.(irs.NLBHandler) + + testNLBHandlerListPrint() + + nlbIId := irs.IID{ + NameId: "test-nlb-01", + } + nlbCreateReqInfo := irs.NLBInfo{ + IId: irs.IID{ + NameId: "test-nlb-01", + }, + VpcIID: irs.IID{ + NameId: "nlb-tester-vpc", + }, + Listener: irs.ListenerInfo{ + Protocol: "TCP", + Port: "8080", + }, + VMGroup: irs.VMGroupInfo{ + Port: "8080", + Protocol: "TCP", + VMs: &[]irs.IID{ + {NameId: "nlb-tester-vm-02"}, + }, + }, + HealthChecker: irs.HealthCheckerInfo{ + Protocol: "TCP", + Port: "8080", + Interval: 10, + Timeout: 5, + Threshold: 10, + }, + } + updateListener := irs.ListenerInfo{ + Protocol: "TCP", + Port: "8087", + } + updateVMGroups := irs.VMGroupInfo{ + Protocol: "TCP", + Port: "8087", + } + addVMs := []irs.IID{ + {NameId: "nlb-tester-vm-02"}, + } + removeVMs := []irs.IID{ + {NameId: "nlb-tester-vm-03"}, + } + + updateHealthCheckerInfo := irs.HealthCheckerInfo{ + Protocol: "HTTP", + Port: "8087", + Interval: 11, + Threshold: 4, + Timeout: 5, + } +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testNLBHandlerListPrint() + case 1: + cblogger.Info("Start ListNLB() ...") + if list, err := nlbHandler.ListNLB(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListNLB()") + case 2: + cblogger.Info("Start GetNLB() ...") + if vm, err := nlbHandler.GetNLB(nlbIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vm) + } + cblogger.Info("Finish GetNLB()") + case 3: + cblogger.Info("Start CreateNLB() ...") + + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + nlbCreateReqInfo.TagList = tagList + + if createInfo, err := nlbHandler.CreateNLB(nlbCreateReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(createInfo) + } + cblogger.Info("Finish CreateNLB()") + case 4: + cblogger.Info("Start DeleteNLB() ...") + if vmStatus, err := nlbHandler.DeleteNLB(nlbIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + 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 result, err := nlbHandler.GetVMGroupHealthInfo(nlbIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(result) + } + 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") + break Loop + } + } + } +} + +func testDiskHandlerListPrint() { + cblogger.Info("Test DiskHandler") + cblogger.Info("0. Print Menu") + 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("8. Exit") +} + +func testDiskHandler(config Config) { + resourceHandler, err := getResourceHandler("disk", config) + if err != nil { + cblogger.Error(err) + return + } + diskHandler := resourceHandler.(irs.DiskHandler) + + testDiskHandlerListPrint() + configdisk := config.IbmVPC.Resources.DISK + + diskCreateReqInfo := irs.DiskInfo{ + IId: irs.IID{ + NameId: configdisk.IID.NameId, + }, + DiskSize: configdisk.DiskSize, + DiskType: configdisk.DiskType, + } + diskIId := irs.IID{ + NameId: configdisk.IID.NameId, + } + vmIID := irs.IID{ + NameId: config.IbmVPC.Resources.Vm.IID.NameId, + } +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testDiskHandlerListPrint() + case 1: + cblogger.Info("Start ListDisk() ...") + if list, err := diskHandler.ListDisk(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListDisk()") + case 2: + cblogger.Info("Start GetDisk() ...") + if vm, err := diskHandler.GetDisk(diskIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vm) + } + cblogger.Info("Finish GetDisk()") + case 3: + cblogger.Info("Start CreateDisk() ...") + + + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + diskCreateReqInfo.TagList = tagList + + if createInfo, err := diskHandler.CreateDisk(diskCreateReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(createInfo) + } + cblogger.Info("Finish CreateDisk()") + case 4: + cblogger.Info("Start DeleteDisk() ...") + if vmStatus, err := diskHandler.DeleteDisk(diskIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish DeleteDisk()") + case 5: + cblogger.Info("Start ChangeDiskSize() [+ 10G] ...") + + // set new size + intSize, _ := strconv.Atoi(configdisk.DiskSize) + intSize += 10 + + if nlbInfo, err := diskHandler.ChangeDiskSize(diskIId, strconv.Itoa(intSize)); err != nil { + cblogger.Error(err) + } else { + spew.Dump(nlbInfo) + } + cblogger.Info("Finish ChangeDiskSize() [+ 10G]") + case 6: + cblogger.Info("Start AttachDisk() ...") + + if info, err := diskHandler.AttachDisk(diskIId, vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(info) + } + cblogger.Info("Finish AttachDisk()") + case 7: + cblogger.Info("Start DetachDisk() ...") + if info, err := diskHandler.DetachDisk(diskIId, vmIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(info) + } + cblogger.Info("Finish DetachDisk()") + case 8: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testMyImageHandlerListPrint() { + cblogger.Info("Test MyImageHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListMyImage()") + cblogger.Info("2. GetMyImage()") + cblogger.Info("3. CreateMyImage()") + cblogger.Info("4. DeleteMyImage()") + cblogger.Info("5. Exit") +} + +func testMyImageHandler(config Config) { + resourceHandler, err := getResourceHandler("myimage", config) + if err != nil { + cblogger.Error(err) + return + } + + myImageHandler := resourceHandler.(irs.MyImageHandler) + + testMyImageHandlerListPrint() + configmyimage := config.IbmVPC.Resources.MYIMAGE + + snapshotCreateReqInfo := irs.MyImageInfo{ + IId: irs.IID{ + NameId: configmyimage.IID.NameId, + }, + SourceVM: irs.IID{ + NameId: configmyimage.SourceVMIID.NameId, + }, + } + myImageIId := irs.IID{ + NameId: configmyimage.IID.NameId, + } +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testMyImageHandlerListPrint() + case 1: + cblogger.Info("Start ListMyImage() ...") + if list, err := myImageHandler.ListMyImage(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListMyImage()") + case 2: + cblogger.Info("Start GetMyImage() ...") + if vm, err := myImageHandler.GetMyImage(myImageIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vm) + } + cblogger.Info("Finish GetMyImage()") + case 3: + cblogger.Info("Start CreateMyImage() ...") + + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + snapshotCreateReqInfo.TagList = tagList + + if createInfo, err := myImageHandler.SnapshotVM(snapshotCreateReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(createInfo) + } + cblogger.Info("Finish CreateMyImage()") + case 4: + cblogger.Info("Start DeleteMyImage() ...") + if vmStatus, err := myImageHandler.DeleteMyImage(myImageIId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(vmStatus) + } + cblogger.Info("Finish DeleteMyImage()") + case 5: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testRegionZoneHandlerListPrint() { + cblogger.Info("Test RegionZoneHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListRegionZone()") + cblogger.Info("2. GetRegionZone()") + cblogger.Info("3. ListOrgRegion()") + cblogger.Info("4. ListOrgZone()") + cblogger.Info("5. Exit") +} + +func testRegionZoneHandler(config Config) { + resourceHandler, err := getResourceHandler("regionzone", config) + if err != nil { + cblogger.Error(err) + return + } + regionzoneHandler := resourceHandler.(irs.RegionZoneHandler) + + testRegionZoneHandlerListPrint() +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testRegionZoneHandlerListPrint() + case 1: + cblogger.Info("Start ListRegionZone() ...") + if listRegionZone, err := regionzoneHandler.ListRegionZone(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(listRegionZone) + } + cblogger.Info("Finish ListRegionZone()") + case 2: + cblogger.Info("Start GetRegionZone() ...") + var region string + fmt.Print("Enter Region Name: ") + if _, err := fmt.Scanln(®ion); err != nil { + cblogger.Error(err) + } + if listRegionZone, err := regionzoneHandler.GetRegionZone(region); err != nil { + cblogger.Error(err) + } else { + spew.Dump(listRegionZone) + } + cblogger.Info("Finish GetRegionZone()") + case 3: + cblogger.Info("Start ListOrgRegion() ...") + if listOrgRegion, err := regionzoneHandler.ListOrgRegion(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(listOrgRegion) + } + cblogger.Info("Finish ListOrgRegion()") + case 4: + cblogger.Info("Start ListOrgZone() ...") + if listOrgZone, err := regionzoneHandler.ListOrgZone(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(listOrgZone) + } + cblogger.Info("Finish ListOrgZone()") + case 5: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testPriceInfoHandlerListPrint() { + cblogger.Info("Test PriceInfoHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListProductFamily()") + cblogger.Info("2. GetPriceInfo()") + cblogger.Info("3. Exit") +} + +func testPriceInfoHandler(config Config) { + resourceHandler, err := getResourceHandler("price", config) + if err != nil { + cblogger.Error(err) + return + } + priceInfoHandler := resourceHandler.(irs.PriceInfoHandler) + + testPriceInfoHandlerListPrint() +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testPriceInfoHandlerListPrint() + case 1: + cblogger.Info("Start ListProductFamily() ...") + var region string + fmt.Print("Enter Region Name: ") + if _, err := fmt.Scanln(®ion); err != nil { + cblogger.Error(err) + } + if listProductFamily, err := priceInfoHandler.ListProductFamily(region); err != nil { + cblogger.Error(err) + } else { + spew.Dump(listProductFamily) + } + cblogger.Info("Finish ListProductFamily()") + case 2: + cblogger.Info("Start GetPriceInfo() ...") + fmt.Println("=== Enter Product Familiy ===") + in := bufio.NewReader(os.Stdin) + productFamiliy, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + + productFamiliy = strings.TrimSpace(productFamiliy) + var region string + fmt.Print("Enter Region Name: ") + if _, err := fmt.Scanln(®ion); err != nil { + cblogger.Error(err) + } + + var addFilterList string + var filterList []irs.KeyValue + for { + fmt.Print("Add filter list? (y/N): ") + _, err := fmt.Scanln(&addFilterList) + if err != nil || strings.ToLower(addFilterList) == "n" { + break + } + + fmt.Println("=== Enter key to filter ===") + in = bufio.NewReader(os.Stdin) + key, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + key = strings.TrimSpace(key) + + fmt.Println("=== Enter value to filter ===") + in = bufio.NewReader(os.Stdin) + value, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + value = strings.TrimSpace(value) + + filterList = append(filterList, irs.KeyValue{ + Key: key, + Value: value, + }) + } + + if priceInfo, err := priceInfoHandler.GetPriceInfo(productFamiliy, region, []irs.KeyValue{} /*filterList*/); err != nil { + cblogger.Error(err) + } else { + spew.Dump(priceInfo) + } + cblogger.Info("Finish GetPriceInfo()") + case 3: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testClusterHandlerListPrint() { + cblogger.Info("Test ClusterHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. ListCluster()") + cblogger.Info("2. GetCluster()") + cblogger.Info("3. CreateCluster()") + cblogger.Info("4. DeleteCluster()") //AddNodeGroup + cblogger.Info("5. AddNodeGroup()") + cblogger.Info("6. RemoveNodeGroup()") + cblogger.Info("7. SetNodeGroupAutoScaling()") + cblogger.Info("8. ChangeNodeGroupScaling()") + cblogger.Info("9. UpgradeCluster()") + cblogger.Info("10. Exit") +} + +func testClusterHandler(config Config) { + resourceHandler, err := getResourceHandler("cluster", config) + if err != nil { + cblogger.Error(err) + return + } + + clusterHandler := resourceHandler.(irs.ClusterHandler) + + testClusterHandlerListPrint() + configCluster := config.IbmVPC.Resources.CLUSTER + + clusterIID := irs.IID{NameId: configCluster.IID.NameId} + + var subnetIIDs []irs.IID + for _, configSubnetIID := range configCluster.Network.SubnetIIDs { + subnetIIDs = append(subnetIIDs, irs.IID{NameId: configSubnetIID.NameId}) + } + var securityGroupIID []irs.IID + for _, configSecurityGroupIID := range configCluster.Network.SecurityGroupIIDs { + securityGroupIID = append(securityGroupIID, irs.IID{NameId: configSecurityGroupIID.NameId}) + } + var nodeGroupList []irs.NodeGroupInfo + for _, configNodeGroup := range configCluster.NodeGroupList { + nodeGroupList = append(nodeGroupList, irs.NodeGroupInfo{ + IId: irs.IID{NameId: configNodeGroup.IID.NameId}, + VMSpecName: configNodeGroup.VMSpecName, + RootDiskType: configNodeGroup.RootDiskType, + RootDiskSize: configNodeGroup.RootDiskSize, + KeyPairIID: irs.IID{NameId: configNodeGroup.KeyPairIID.NameId}, + OnAutoScaling: configNodeGroup.OnAutoScaling, + DesiredNodeSize: configNodeGroup.DesireNodeSize, + MinNodeSize: configNodeGroup.MinNodeSize, + MaxNodeSize: configNodeGroup.MaxNodeSize, + }) + } + clusterCreateReqInfo := irs.ClusterInfo{ + IId: irs.IID{NameId: configCluster.IID.NameId}, + Version: configCluster.Version, + Network: irs.NetworkInfo{ + VpcIID: irs.IID{NameId: configCluster.Network.VpcIID.NameId}, + SubnetIIDs: subnetIIDs, + SecurityGroupIIDs: securityGroupIID, + }, + NodeGroupList: nodeGroupList, + } + nodeGroupReqInfo := irs.NodeGroupInfo{ + IId: irs.IID{NameId: configCluster.AdditionalNodeGroup.IID.NameId}, + VMSpecName: configCluster.AdditionalNodeGroup.VMSpecName, + OnAutoScaling: configCluster.AdditionalNodeGroup.OnAutoScaling, + DesiredNodeSize: configCluster.AdditionalNodeGroup.DesireNodeSize, + MinNodeSize: configCluster.AdditionalNodeGroup.MinNodeSize, + MaxNodeSize: configCluster.AdditionalNodeGroup.MaxNodeSize, + } + +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testClusterHandlerListPrint() + case 1: + cblogger.Info("Start ListCluster() ...") + if list, err := clusterHandler.ListCluster(); err != nil { + cblogger.Error(err) + } else { + spew.Dump(list) + } + cblogger.Info("Finish ListCluster()") + case 2: + cblogger.Info("Start GetCluster() ...") + if cluster, err := clusterHandler.GetCluster(clusterIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(cluster) + } + cblogger.Info("Finish GetCluster()") + case 3: + cblogger.Info("Start CreateCluster() ...") + // Add TagList + var tagList []irs.KeyValue + tagList, err = SetResourceTagList() + if err != nil { + cblogger.Error(err) + } + + clusterCreateReqInfo.TagList = tagList + + if createInfo, err := clusterHandler.CreateCluster(clusterCreateReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(createInfo) + } + cblogger.Info("Finish CreateCluster()") + case 4: + cblogger.Info("Start DeleteCluster() ...") + if deleteClusterResult, err := clusterHandler.DeleteCluster(clusterCreateReqInfo.IId); err != nil { + cblogger.Error(err) + } else { + spew.Dump(deleteClusterResult) + } + cblogger.Info("Finish DeleteCluster()") + case 5: + cblogger.Info("Start AddNodeGroup() ...") + if addNodeGroupInfo, err := clusterHandler.AddNodeGroup(clusterCreateReqInfo.IId, nodeGroupReqInfo); err != nil { + cblogger.Error(err) + } else { + spew.Dump(addNodeGroupInfo) + } + cblogger.Info("Finish AddNodeGroup()") + case 6: + cblogger.Info("Start RemoveNodeGroup() ...") + if removeNodeGroupResult, err := clusterHandler.RemoveNodeGroup(clusterCreateReqInfo.IId, + irs.IID{NameId: configCluster.AdditionalNodeGroup.IID.NameId}); err != nil { + cblogger.Error(err) + } else { + spew.Dump(removeNodeGroupResult) + } + cblogger.Info("Finish RemoveNodeGroup()") + case 7: + cblogger.Info("Start SetNodeGroupAutoScaling() ...") + if setNodeGroupAutoScalingResult, err := clusterHandler.SetNodeGroupAutoScaling( + clusterCreateReqInfo.IId, + irs.IID{NameId: configCluster.ClusterUpdateInfos.TargetNodeGroupIID.NameId}, + configCluster.ClusterUpdateInfos.OnNodeGroupAutoScaling); err != nil { + cblogger.Error(err) + } else { + spew.Dump(setNodeGroupAutoScalingResult) + } + cblogger.Info("Finish SetNodeGroupAutoScaling()") + case 8: + cblogger.Info("Start ChangeNodeGroupScaling() ...") + if changeNodeGroupScalingResult, err := clusterHandler.ChangeNodeGroupScaling( + clusterCreateReqInfo.IId, + irs.IID{NameId: configCluster.ClusterUpdateInfos.TargetNodeGroupIID.NameId}, + configCluster.ClusterUpdateInfos.ChangeNodeGroupScaling.DesiredNodeSize, + configCluster.ClusterUpdateInfos.ChangeNodeGroupScaling.MinNodeSize, + configCluster.ClusterUpdateInfos.ChangeNodeGroupScaling.MaxNodeSize); err != nil { + cblogger.Error(err) + } else { + spew.Dump(changeNodeGroupScalingResult) + } + cblogger.Info("Finish ChangeNodeGroupScaling()") + case 9: + cblogger.Info("Start UpgradeCluster() ...") + if upgradeResult, err := clusterHandler.UpgradeCluster(clusterCreateReqInfo.IId, configCluster.ClusterUpdateInfos.UpgradeVersion); err != nil { + cblogger.Error(err) + } else { + spew.Dump(upgradeResult) + } + cblogger.Info("Finish UpgradeCluster()") + case 10: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func testTagHandlerListPrint() { + cblogger.Info("Test TagHandler") + cblogger.Info("0. Print Menu") + cblogger.Info("1. AddTag()") + cblogger.Info("2. ListTag()") + cblogger.Info("3. GetTag()") + cblogger.Info("4. RemoveTag()") + cblogger.Info("5. FindTag()") + cblogger.Info("6. Exit") +} + +func inputToRSType(input string) irs.RSType { + switch input { + case "all": + return irs.ALL + case "image": + return irs.IMAGE + case "vpc": + return irs.VPC + case "subnet": + return irs.SUBNET + case "sg": + return irs.SG + case "keypair": + return irs.KEY + case "vm": + return irs.VM + case "nlb": + return irs.NLB + case "disk": + return irs.DISK + case "myimage": + return irs.MYIMAGE + case "cluster": + return irs.CLUSTER + case "nodegroup": + return irs.NODEGROUP + default: + return "" + } +} + +func testTagHandler(config Config) { + resourceHandler, err := getResourceHandler("tag", config) + if err != nil { + cblogger.Error(err) + return + } + tagHandler := resourceHandler.(irs.TagHandler) + + testTagHandlerListPrint() +Loop: + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 0: + testTagHandlerListPrint() + case 1: + cblogger.Info("Start AddTag() ...") + fmt.Println("=== Enter resource type ===") + in := bufio.NewReader(os.Stdin) + resTypeStr, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resTypeStr = strings.TrimSpace(resTypeStr) + result := irs.RSTypeString(irs.RSType(resTypeStr)) + if strings.Contains(result, "not supported") { + cblogger.Error(result) + break Loop + } + resType := inputToRSType(resTypeStr) + + fmt.Println("=== Enter name of the resource ===") + in = bufio.NewReader(os.Stdin) + resName, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resName = strings.TrimSpace(resName) + + fmt.Println("=== Enter tag's key ===") + in = bufio.NewReader(os.Stdin) + tagKey, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + tagKey = strings.TrimSpace(tagKey) + + fmt.Println("=== Enter tag's value ===") + in = bufio.NewReader(os.Stdin) + tagValue, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + tagValue = strings.TrimSpace(tagValue) + + if tagKeyValue, err := tagHandler.AddTag(resType, irs.IID{NameId: resName}, irs.KeyValue{Key: tagKey, Value: tagValue}); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tagKeyValue) + } + cblogger.Info("Finish AddTag()") + case 2: + cblogger.Info("Start ListTag() ...") + fmt.Println("=== Enter resource type ===") + in := bufio.NewReader(os.Stdin) + resTypeStr, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resTypeStr = strings.TrimSpace(resTypeStr) + result := irs.RSTypeString(irs.RSType(resTypeStr)) + if strings.Contains(result, "not supported") { + cblogger.Error(result) + break Loop + } + resType := inputToRSType(resTypeStr) + + fmt.Println("=== Enter name of the resource ===") + in = bufio.NewReader(os.Stdin) + resName, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resName = strings.TrimSpace(resName) + + if tagList, err := tagHandler.ListTag(resType, irs.IID{NameId: resName}); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tagList) + } + cblogger.Info("Finish ListTag()") + case 3: + cblogger.Info("Start GetTag() ...") + fmt.Println("=== Enter resource type ===") + in := bufio.NewReader(os.Stdin) + resTypeStr, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resTypeStr = strings.TrimSpace(resTypeStr) + result := irs.RSTypeString(irs.RSType(resTypeStr)) + if strings.Contains(result, "not supported") { + cblogger.Error(result) + break Loop + } + resType := inputToRSType(resTypeStr) + + fmt.Println("=== Enter name of the resource ===") + in = bufio.NewReader(os.Stdin) + resName, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resName = strings.TrimSpace(resName) + + fmt.Println("=== Enter tag's key ===") + in = bufio.NewReader(os.Stdin) + tagKey, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + tagKey = strings.TrimSpace(tagKey) + + if tagKeyValue, err := tagHandler.GetTag(resType, irs.IID{NameId: resName}, tagKey); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tagKeyValue) + } + cblogger.Info("Finish GetTag()") + case 4: + cblogger.Info("Start RemoveTag() ...") + fmt.Println("=== Enter resource type ===") + in := bufio.NewReader(os.Stdin) + resTypeStr, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resTypeStr = strings.TrimSpace(resTypeStr) + result := irs.RSTypeString(irs.RSType(resTypeStr)) + if strings.Contains(result, "not supported") { + cblogger.Error(result) + break Loop + } + resType := inputToRSType(resTypeStr) + + fmt.Println("=== Enter name of the resource ===") + in = bufio.NewReader(os.Stdin) + resName, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resName = strings.TrimSpace(resName) + + fmt.Println("=== Enter tag's key ===") + in = bufio.NewReader(os.Stdin) + tagKey, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + tagKey = strings.TrimSpace(tagKey) + + if tagKeyValue, err := tagHandler.RemoveTag(resType, irs.IID{NameId: resName}, tagKey); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tagKeyValue) + } + cblogger.Info("Finish RemoveTag()") + case 5: + cblogger.Info("Start FindTag() ...") + fmt.Println("=== Enter resource type ===") + in := bufio.NewReader(os.Stdin) + resTypeStr, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + resTypeStr = strings.TrimSpace(resTypeStr) + result := irs.RSTypeString(irs.RSType(resTypeStr)) + if strings.Contains(result, "not supported") { + cblogger.Error(result) + break Loop + } + resType := inputToRSType(resTypeStr) + + fmt.Println("=== Enter keyword ===") + in = bufio.NewReader(os.Stdin) + keyword, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + keyword = strings.TrimSpace(keyword) + + if tagKeyValue, err := tagHandler.FindTag(resType, keyword); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tagKeyValue) + } + cblogger.Info("Finish FindTag()") + case 6: + cblogger.Info("Exit") + break Loop + } + } + } +} + +func SetResourceTagList()([]irs.KeyValue, error){ + cblogger.Info("0. TagList Setting") + cblogger.Info("1. Continue without TagList") + var tagSetNum int + _, err := fmt.Scan(&tagSetNum) + if err != nil { + return []irs.KeyValue{}, err + } + + var KeyValue []irs.KeyValue + switch tagSetNum{ + case 0: + var tagCount int + + fmt.Print("How many tag? ") + _, err := fmt.Scanln(&tagCount) + if err != nil { + return []irs.KeyValue{}, err + } + + i := 0 + for i < tagCount { + fmt.Println("=== Enter KeyValue ===") + var key string + var value string + + fmt.Print("Key: ") + _, err := fmt.Scanln(&key) + if err != nil { + return []irs.KeyValue{}, err + } + + fmt.Print("Value: ") + _, err = fmt.Scanln(&value) + if err != nil { + return []irs.KeyValue{}, err + } + + KeyValue = append(KeyValue, irs.KeyValue{Key: key, Value: value}) + i++ + } + case 1: + break + } + + return KeyValue, nil +} + + +func main() { + showTestHandlerInfo() + config := readConfigFile() + +Loop: + + for { + var commandNum int + inputCnt, err := fmt.Scan(&commandNum) + if err != nil { + cblogger.Error(err) + } + + if inputCnt == 1 { + switch commandNum { + case 1: + testImageHandler(config) + showTestHandlerInfo() + case 2: + testSecurityHandler(config) + showTestHandlerInfo() + case 3: + testVPCHandler(config) + showTestHandlerInfo() + case 4: + testKeyPairHandler(config) + showTestHandlerInfo() + case 5: + testVMSpecHandler(config) + showTestHandlerInfo() + case 6: + testVMHandler(config) + showTestHandlerInfo() + case 7: + testNLBHandler(config) + showTestHandlerInfo() + case 8: + testDiskHandler(config) + showTestHandlerInfo() + case 9: + testMyImageHandler(config) + showTestHandlerInfo() + case 10: + testRegionZoneHandler(config) + showTestHandlerInfo() + case 11: + testPriceInfoHandler(config) + showTestHandlerInfo() + case 12: + testClusterHandler(config) + showTestHandlerInfo() + case 13: + testTagHandler(config) + showTestHandlerInfo() + case 14: + cblogger.Info("Exit Test ResourceHandler Program") + break Loop + } + } + } +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/ClusterHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/ClusterHandler.go index 074299530..ea67ef313 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/ClusterHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/ClusterHandler.go @@ -1,1993 +1,2017 @@ -package resources - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/platform-services-go-sdk/globaltaggingv1" - "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" - "github.com/IBM/vpc-go-sdk/vpcv1" - call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" - "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/utils/kubernetesserviceapiv1" - idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" - irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" - "github.com/go-openapi/strfmt" - "github.com/hashicorp/go-version" - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "strings" - "sync" - "time" -) - -const ( - // Resource Names - DefaultResourceGroup = "Default" - AutoscalerAddon = "cluster-autoscaler" - ConfigMapNamespace = "kube-system" - AutoscalerConfigMap = "iks-ca-configmap" - AutoscalerConfigMapOptionProperty = "workerPoolsConfig.json" - - // Error Codes - RetrieveUnableErr = "Not visible in IBMCloud-VPC" - GetKubeConfigErr = "Get Kube Config Error" - GetAutoScalerConfigErr = "Get Autoscaler Config Map Error" - - // Retry Counts - EnableAutoScalerRetry = 120 // minutes - DisableAutoScalerRetry = 120 // minutes - InitSecurityGroupRetry = 120 // minutes - RestoreDefaultSGRetry = 120 // minutes - UpgradeMasterRetry = 120 // minutes - - // Status tags - AutoScalerStatus = "CB-SPIDER-PMKS-AUTOSCALER-STATUS:" - SecurityGroupStatus = "CB-SPIDER-PMKS-SECURITYGROUP-STATUS:" - MasterUpgradeStatus = "CB-SPIDER-PMKS-MASTERUPGRADE-STATUS:" - - // State Codes - WAITING = "WAITING" - DEPLOYING = "DEPLOYING" - UPGRADE_DEPLOYING = "UPGRADE-DEPLOYING" - ACTIVE = "ACTIVE" - UNINSTALLING = "UNINSTALLING" - FAILED = "FAILED" - INITIALIZING = "INITIALIZING" - INITIALIZED = "INITIALIZED" - UPGRADING = "UPGRADING" -) - -var autoSaclerStates []string -var securityGroupStates []string -var masterUpgradeStates []string - -func init() { - autoSaclerStates = []string{WAITING, DEPLOYING, UPGRADE_DEPLOYING, ACTIVE, UNINSTALLING, FAILED} - for i, state := range autoSaclerStates { - autoSaclerStates[i] = fmt.Sprintf("%s%s", AutoScalerStatus, state) - } - securityGroupStates = []string{INITIALIZING, INITIALIZED, FAILED} - for i, state := range securityGroupStates { - securityGroupStates[i] = fmt.Sprintf("%s%s", SecurityGroupStatus, state) - } - masterUpgradeStates = []string{WAITING, UPGRADING} - for i, state := range masterUpgradeStates { - masterUpgradeStates[i] = fmt.Sprintf("%s%s", MasterUpgradeStatus, state) - } -} - -type IbmClusterHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - Ctx context.Context - VpcService *vpcv1.VpcV1 - ClusterService *kubernetesserviceapiv1.KubernetesServiceApiV1 - TaggingService *globaltaggingv1.GlobalTaggingV1 -} - -var defaultResourceGroupId string - -func (ic *IbmClusterHandler) CreateCluster(clusterReqInfo irs.ClusterInfo) (irs.ClusterInfo, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterReqInfo.IId.NameId, "CreateCluster()") - start := call.Start() - - // validation - validationErr := ic.validateAtCreateCluster(clusterReqInfo) - if validationErr != nil { - cblogger.Error(validationErr) - LoggingError(hiscallInfo, validationErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", validationErr)) - } - - // get resource group id - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - cblogger.Error(getResourceGroupErr) - LoggingError(hiscallInfo, getResourceGroupErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getResourceGroupErr)) - } - - // get vpc info - vpcHandler := IbmVPCHandler{ - CredentialInfo: ic.CredentialInfo, - Region: ic.Region, - VpcService: ic.VpcService, - Ctx: ic.Ctx, - } - vpcInfo, getVpcInfoErr := vpcHandler.GetVPC(clusterReqInfo.Network.VpcIID) - if getVpcInfoErr != nil { - cblogger.Error(getVpcInfoErr) - LoggingError(hiscallInfo, getVpcInfoErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getVpcInfoErr)) - } - - // get subnet info - subnetInfo, getSubnetInfoErr := ic.validateAndGetSubnetInfo(clusterReqInfo.Network) - if getSubnetInfoErr != nil { - cblogger.Error(getSubnetInfoErr) - LoggingError(hiscallInfo, getSubnetInfoErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getSubnetInfoErr)) - } - - // check exists - _, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(clusterReqInfo.IId.NameId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("false"), - }) - if getClusterErr != nil && getClusterErr.Error() == "Not Found" { - // get first worker pool for cluster creation - workerPool := ic.getWorkerPoolFromNodeGroupInfo(clusterReqInfo.NodeGroupList[0], vpcInfo.IId.SystemId, subnetInfo.IId.SystemId) - - // create cluster if not exists - _, _, createClusterErr := ic.ClusterService.VpcCreateClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcCreateClusterOptions{ - DisablePublicServiceEndpoint: core.BoolPtr(false), - KubeVersion: core.StringPtr(clusterReqInfo.Version), - Name: core.StringPtr(clusterReqInfo.IId.NameId), - Provider: core.StringPtr("vpc-gen2"), - WorkerPool: &workerPool, - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if createClusterErr != nil { - cblogger.Error(createClusterErr) - LoggingError(hiscallInfo, createClusterErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", createClusterErr)) - } - - rawVpcInfo, _, getRawVpcErr := ic.VpcService.GetVPCWithContext(ic.Ctx, &vpcv1.GetVPCOptions{ - ID: core.StringPtr(vpcInfo.IId.SystemId), - }) - if getRawVpcErr != nil { - cblogger.Error(getRawVpcErr) - LoggingError(hiscallInfo, getRawVpcErr) - _, _ = ic.DeleteCluster(clusterReqInfo.IId) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getRawVpcErr)) - } - - sgHander := IbmSecurityHandler{ - CredentialInfo: ic.CredentialInfo, - Region: ic.Region, - Ctx: ic.Ctx, - VpcService: ic.VpcService, - } - - // restore VPC default security group - // VPC default security group lost rules for unknown reasons while creating a cluster with API - // It makes communication failure between worker and master nodes in the cluster and worker status reaches failure - go func() { - cnt := 0 - for cnt < RestoreDefaultSGRetry { - isSkip := false - brokenVpcDefaultSg, getBrokenVpcDefaultSgErr := sgHander.GetSecurity(irs.IID{SystemId: *rawVpcInfo.DefaultSecurityGroup.ID}) - if getBrokenVpcDefaultSgErr != nil { - isSkip = true - } else { - rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(clusterReqInfo.IId.NameId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("true"), - }) - if getClustersErr != nil { - isSkip = true - } - rawCluster := (*rawClusters)[0] - if rawCluster.State != "deploying" { - isSkip = true - } - } - if isSkip { - cnt++ - time.Sleep(time.Minute) - } else { - mandatoriyRuleList := []irs.SecurityRuleInfo{{ - Direction: "inbound", - IPProtocol: "tcp", - FromPort: "22", - ToPort: "22", - }, { - Direction: "inbound", - IPProtocol: "icmp", - FromPort: "-1", - ToPort: "-1", - }, { - Direction: "outbound", - IPProtocol: "all", - FromPort: "-1", - ToPort: "-1", - CIDR: "0.0.0.0/0", - }} - - _, addRuleErr := sgHander.AddRules(brokenVpcDefaultSg.IId, &mandatoriyRuleList) - if addRuleErr != nil { - cblogger.Error(addRuleErr) - LoggingError(hiscallInfo, addRuleErr) - ic.DeleteCluster(clusterReqInfo.IId) - } - break - } - } - }() - - } else if getClusterErr != nil { - cblogger.Error(getClusterErr) - LoggingError(hiscallInfo, getClusterErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getClusterErr)) - } - - // get created cluster info - rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(clusterReqInfo.IId.NameId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("true"), - }) - if getClustersErr != nil { - cblogger.Error(getClustersErr) - LoggingError(hiscallInfo, getClustersErr) - ic.DeleteCluster(clusterReqInfo.IId) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClustersErr)) - } - rawCluster := (*rawClusters)[0] - - // Enable cluster-autoscaler addon and apply autoscaler option - autoScalerErr := ic.installAutoScalerAddon(clusterReqInfo, rawCluster.Id, rawCluster.Crn, resourceGroupId, false) - if autoScalerErr != nil { - cblogger.Error(autoScalerErr) - LoggingError(hiscallInfo, autoScalerErr) - ic.DeleteCluster(clusterReqInfo.IId) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", autoScalerErr)) - } - - // Add remaining worker pools - ic.createRemainingWorkerPools(clusterReqInfo, vpcInfo, subnetInfo, rawCluster, resourceGroupId) - - // Set Security Group - ic.initSecurityGroup(clusterReqInfo, rawCluster.Id, rawCluster.Crn) - - clusterInfo, getClusterErr := ic.GetCluster(irs.IID{SystemId: rawCluster.Id}) - if getClusterErr != nil { - cblogger.Error(getClusterErr) - LoggingError(hiscallInfo, getClusterErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getClusterErr)) - } - - LoggingInfo(hiscallInfo, start) - - return clusterInfo, nil -} - -func (ic *IbmClusterHandler) ListCluster() ([]*irs.ClusterInfo, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, "", "ListCluster()") - start := call.Start() - - resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() - if getResourceGroupIdErr != nil { - cblogger.Error(getResourceGroupIdErr) - LoggingError(hiscallInfo, getResourceGroupIdErr) - return []*irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to List Cluster. err = %s", getResourceGroupIdErr)) - } - - clusterList, _, getClusterListErr := ic.ClusterService.VpcGetClustersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClustersOptions{ - XAuthResourceGroup: core.StringPtr(resourceGroupId), - Provider: core.StringPtr("vpc-gen2"), - }) - if getClusterListErr != nil { - cblogger.Error(getClusterListErr) - LoggingError(hiscallInfo, getClusterListErr) - return []*irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to List Cluster. err = %s", getClusterListErr)) - } - - var wait sync.WaitGroup - wait.Add(len(clusterList)) - var ret []*irs.ClusterInfo - for _, cluster := range clusterList { - go func() { - defer wait.Done() - irsCluster, getIrsClusterErr := ic.GetCluster(irs.IID{SystemId: *cluster.ID}) - if getIrsClusterErr == nil { - ret = append(ret, &irsCluster) - } - }() - } - wait.Wait() - - LoggingInfo(hiscallInfo, start) - - return ret, nil -} - -func (ic *IbmClusterHandler) getRawCluster(clusterIID irs.IID) (kubernetesserviceapiv1.GetClusterDetailResponse, error) { - rawCluster := kubernetesserviceapiv1.GetClusterDetailResponse{} - - if clusterIID.NameId == "" && clusterIID.SystemId == "" { - return rawCluster, errors.New("Failed to Get Cluster. err = invalid IID") - } - - resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() - if getResourceGroupIdErr != nil { - return rawCluster, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getResourceGroupIdErr)) - } - - var cluster string - if clusterIID.SystemId != "" { - cluster = clusterIID.SystemId - } else { - cluster = clusterIID.NameId - } - rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(cluster), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("true"), - }) - if getClustersErr != nil { - return rawCluster, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClustersErr)) - } - - for _, rCluster := range *rawClusters { - if rCluster.Id == clusterIID.SystemId || rCluster.Name == clusterIID.NameId { - return rCluster, nil - } - } - - return rawCluster, errors.New("Failed to Get Cluster. err = cluster not found") -} - -func (ic *IbmClusterHandler) GetCluster(clusterIID irs.IID) (irs.ClusterInfo, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "GetCluster()") - start := call.Start() - - if clusterIID.NameId == "" && clusterIID.SystemId == "" { - return irs.ClusterInfo{}, errors.New("Failed to Get Cluster. err = invalid IID") - } - - resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() - if getResourceGroupIdErr != nil { - cblogger.Error(getResourceGroupIdErr) - LoggingError(hiscallInfo, getResourceGroupIdErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getResourceGroupIdErr)) - } - - var cluster string - if clusterIID.SystemId != "" { - cluster = clusterIID.SystemId - } else { - cluster = clusterIID.NameId - } - rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(cluster), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("true"), - }) - if getClustersErr != nil { - cblogger.Error(getClustersErr) - LoggingError(hiscallInfo, getClustersErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClustersErr)) - } - - for _, rawCluster := range *rawClusters { - if rawCluster.Id == clusterIID.SystemId || rawCluster.Name == clusterIID.NameId { - ret, getClusterInfoErr := ic.setClusterInfo(rawCluster) - if getClusterInfoErr != nil { - cblogger.Error(getClusterInfoErr) - LoggingError(hiscallInfo, getClusterInfoErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClusterInfoErr)) - } - LoggingInfo(hiscallInfo, start) - return ret, nil - } - } - - LoggingInfo(hiscallInfo, start) - return irs.ClusterInfo{}, nil -} - -func (ic *IbmClusterHandler) DeleteCluster(clusterIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "DeleteCluster()") - start := call.Start() - - if clusterIID.NameId == "" && clusterIID.SystemId == "" { - return false, errors.New("Failed to Delete Cluster. err = invalid IID") - } - - // get resource group id - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - cblogger.Error(getResourceGroupErr) - LoggingError(hiscallInfo, getResourceGroupErr) - return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", getResourceGroupErr)) - } - - // check exists - fullClusterIID, getClusterIIDErr := ic.getClusterIID(clusterIID) - if getClusterIIDErr != nil { - cblogger.Error(getClusterIIDErr) - LoggingError(hiscallInfo, getClusterIIDErr) - return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", getClusterIIDErr)) - } - - rawCluster, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(fullClusterIID.SystemId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("false"), - }) - if getClusterErr != nil { - cblogger.Error(getClusterErr) - LoggingError(hiscallInfo, getClusterErr) - return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", getClusterErr)) - } - - // delete cluster - _, deleteClusterErr := ic.ClusterService.RemoveClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.RemoveClusterOptions{ - IdOrName: core.StringPtr((*rawCluster)[0].Id), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - DeleteResources: core.StringPtr("true"), - }) - if deleteClusterErr != nil { - cblogger.Error(deleteClusterErr) - LoggingError(hiscallInfo, deleteClusterErr) - return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", deleteClusterErr)) - } - - LoggingInfo(hiscallInfo, start) - - return true, nil -} - -func (ic *IbmClusterHandler) AddNodeGroup(clusterIID irs.IID, nodeGroupReqInfo irs.NodeGroupInfo) (irs.NodeGroupInfo, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "AddNodeGroup()") - start := call.Start() - - // validation - validateErr := ic.validateAtAddNodeGroup(clusterIID, nodeGroupReqInfo) - if validateErr != nil { - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", validateErr)) - } - - // get resource group id - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - cblogger.Error(getResourceGroupErr) - LoggingError(hiscallInfo, getResourceGroupErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getResourceGroupErr)) - } - - irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) - if getIrsClusterErr != nil { - cblogger.Error(getIrsClusterErr) - LoggingError(hiscallInfo, getIrsClusterErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getIrsClusterErr)) - } - if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting { - clusterStatusErr := errors.New(fmt.Sprintf("Cannot Add Node Group at %s status", irsCluster.Status)) - cblogger.Error(clusterStatusErr) - LoggingError(hiscallInfo, clusterStatusErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", clusterStatusErr)) - } - - // Get Network.Subnet Info - rawVpeList, _, getRawVpeListErr := ic.VpcService.ListEndpointGateways(&vpcv1.ListEndpointGatewaysOptions{ - ResourceGroupID: core.StringPtr(resourceGroupId), - }) - if getRawVpeListErr != nil { - cblogger.Error(getRawVpeListErr) - LoggingError(hiscallInfo, getRawVpeListErr) - return irs.NodeGroupInfo{}, getRawVpeListErr - } - - var target vpcv1.EndpointGateway - for _, rawVpe := range rawVpeList.EndpointGateways { - if *rawVpe.Name == fmt.Sprintf("iks-%s", irsCluster.IId.SystemId) { - target = rawVpe - } - } - - var subnetIID irs.IID - for _, ip := range target.Ips { - if strings.Contains(*ip.Name, irsCluster.IId.SystemId) { - subnetId := strings.Split(*ip.Href, "/")[5] - rawSubnet, _, getRawSubnetErr := ic.VpcService.GetSubnet(&vpcv1.GetSubnetOptions{ - ID: core.StringPtr(subnetId), - }) - if getRawSubnetErr != nil { - cblogger.Error(getRawSubnetErr) - LoggingError(hiscallInfo, getRawSubnetErr) - return irs.NodeGroupInfo{}, getRawSubnetErr - } - subnetIID.NameId = *rawSubnet.Name - subnetIID.SystemId = *rawSubnet.ID - } - } - - addNodeGroupResponse, _, addNodeGroupErr := ic.ClusterService.VpcCreateWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcCreateWorkerPoolOptions{ - Cluster: core.StringPtr(irsCluster.IId.SystemId), - Flavor: core.StringPtr(nodeGroupReqInfo.VMSpecName), - Isolation: core.StringPtr("public"), - Name: core.StringPtr(nodeGroupReqInfo.IId.NameId), - VpcID: core.StringPtr(irsCluster.Network.VpcIID.SystemId), - WorkerCount: core.Int64Ptr(int64(nodeGroupReqInfo.DesiredNodeSize)), - Zones: []kubernetesserviceapiv1.Zone{{ - ID: core.StringPtr(ic.Region.Zone), - SubnetID: core.StringPtr(subnetIID.SystemId), - }}, - Authorization: core.StringPtr(ic.CredentialInfo.AuthToken), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if addNodeGroupErr != nil { - cblogger.Error(addNodeGroupErr) - LoggingError(hiscallInfo, addNodeGroupErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", addNodeGroupErr)) - } - - newNodeGroup, _, getNewNodeGroupErr := ic.ClusterService.VpcGetWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolOptions{ - Cluster: core.StringPtr(irsCluster.IId.SystemId), - Workerpool: addNodeGroupResponse.WorkerPoolID, - XRegion: core.StringPtr(ic.Region.Region), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if getNewNodeGroupErr != nil { - cblogger.Error(getNewNodeGroupErr) - LoggingError(hiscallInfo, getNewNodeGroupErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getNewNodeGroupErr)) - } - - // Apply Node Group autosacler options - irsCluster.NodeGroupList = append(irsCluster.NodeGroupList, nodeGroupReqInfo) - applyAutoScalerOptionErr := ic.applyAutoScalerOptions(irsCluster, irsCluster.IId.SystemId, resourceGroupId) - if applyAutoScalerOptionErr != nil { - cblogger.Error(applyAutoScalerOptionErr) - LoggingError(hiscallInfo, applyAutoScalerOptionErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", applyAutoScalerOptionErr)) - } - - // Get Workers in pool - getWorkersResult, _, getWorkersErr := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ - Cluster: core.StringPtr(irsCluster.IId.SystemId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowDeleted: core.StringPtr("false"), - Pool: newNodeGroup.ID, - }) - if getWorkersErr != nil { - cblogger.Error(getWorkersErr) - LoggingError(hiscallInfo, getWorkersErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getWorkersErr)) - } - - var nodesIID []irs.IID - for _, worker := range getWorkersResult { - nodesIID = append(nodesIID, irs.IID{ - NameId: RetrieveUnableErr, - SystemId: *worker.ID, - }) - } - - LoggingInfo(hiscallInfo, start) - - return irs.NodeGroupInfo{ - IId: irs.IID{ - NameId: *newNodeGroup.PoolName, - SystemId: *newNodeGroup.ID, - }, - ImageIID: irs.IID{ - NameId: RetrieveUnableErr, - SystemId: RetrieveUnableErr, - }, - VMSpecName: *newNodeGroup.Flavor, - RootDiskType: RetrieveUnableErr, - RootDiskSize: RetrieveUnableErr, - KeyPairIID: irs.IID{ - NameId: RetrieveUnableErr, - SystemId: RetrieveUnableErr, - }, - OnAutoScaling: false, - DesiredNodeSize: -1, - MinNodeSize: -1, - MaxNodeSize: -1, - Status: ic.getNodeGroupStatusFromString(*newNodeGroup.Lifecycle.DesiredState), - Nodes: nodesIID, - KeyValueList: nil, - }, nil -} - -func (ic *IbmClusterHandler) SetNodeGroupAutoScaling(clusterIID irs.IID, nodeGroupIID irs.IID, on bool) (bool, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "SetNodeGroupAutoScaling()") - start := call.Start() - - // validation - if clusterIID.SystemId == "" && clusterIID.NameId == "" { - return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Cluster IID") - } - if nodeGroupIID.SystemId == "" && nodeGroupIID.NameId == "" { - return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Node Group IID") - } - - // get resource group id - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - cblogger.Error(getResourceGroupErr) - LoggingError(hiscallInfo, getResourceGroupErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getResourceGroupErr)) - } - - irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) - if getIrsClusterErr != nil { - cblogger.Error(getIrsClusterErr) - LoggingError(hiscallInfo, getIrsClusterErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getIrsClusterErr)) - } - if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting || irsCluster.Status == irs.ClusterUpdating { - clusterStatusErr := errors.New(fmt.Sprintf("Cannot Set Node Group AutoScaling at %s status", irsCluster.Status)) - cblogger.Error(clusterStatusErr) - LoggingError(hiscallInfo, clusterStatusErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group AutoScaling. err = %s", clusterStatusErr)) - } - - nodeGroups, _, getNodeGroupsErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ - Cluster: core.StringPtr(irsCluster.IId.SystemId), - XRegion: core.StringPtr(ic.Region.Region), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if getNodeGroupsErr != nil { - cblogger.Error(getNodeGroupsErr) - LoggingError(hiscallInfo, getNodeGroupsErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getNodeGroupsErr)) - } - - var targetNodeGroup *kubernetesserviceapiv1.GetWorkerPoolsDetailResponse - for _, nodeGroup := range *nodeGroups { - if nodeGroup.Id == nodeGroupIID.SystemId || nodeGroup.PoolName == nodeGroupIID.NameId { - targetNodeGroup = &nodeGroup - break - } - } - if targetNodeGroup == nil { - nodeGroupNotExistErr := errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = cannot find node group: %s", nodeGroupIID)) - cblogger.Error(nodeGroupNotExistErr) - LoggingError(hiscallInfo, nodeGroupNotExistErr) - return false, nodeGroupNotExistErr - } - - nodeGroupName := targetNodeGroup.PoolName - - kubeConfigStr, getKubeConfigErr := ic.getKubeConfig(irsCluster.IId.SystemId, resourceGroupId) - if getKubeConfigErr != nil { - cblogger.Error(getKubeConfigErr) - LoggingError(hiscallInfo, getKubeConfigErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getKubeConfigErr)) - } - - var newNodeGroupInfo []irs.NodeGroupInfo - configMap, getConfigMapErr := ic.getAutoScalerConfigMap(kubeConfigStr) - if getConfigMapErr != nil { - cblogger.Error(getConfigMapErr) - LoggingError(hiscallInfo, getConfigMapErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getConfigMapErr)) - } - if configMap == nil { - configMapNotExistErr := errors.New("Failed to Set Node Group Auto Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") - cblogger.Error(configMapNotExistErr) - LoggingError(hiscallInfo, configMapNotExistErr) - return false, configMapNotExistErr - } else { - jsonProperty, exists := configMap.Data[AutoscalerConfigMapOptionProperty] - if !exists { - propertyNotExistErr := errors.New("Failed to Set Node Group Auto Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") - cblogger.Error(propertyNotExistErr) - LoggingError(hiscallInfo, propertyNotExistErr) - return false, propertyNotExistErr - } - - var workerPoolAutoscalerConfigs []kubernetesserviceapiv1.WorkerPoolAutoscalerConfig - unmarshalErr := json.Unmarshal([]byte(jsonProperty), &workerPoolAutoscalerConfigs) - if unmarshalErr != nil { - cblogger.Error(unmarshalErr) - LoggingError(hiscallInfo, unmarshalErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", unmarshalErr)) - } - - isIncluded := false - for i, config := range workerPoolAutoscalerConfigs { - if config.Name == nodeGroupName { - isIncluded = true - workerPoolAutoscalerConfigs[i].Enabled = on - } - newNodeGroupInfo = append(newNodeGroupInfo, irs.NodeGroupInfo{ - IId: irs.IID{NameId: workerPoolAutoscalerConfigs[i].Name}, - OnAutoScaling: workerPoolAutoscalerConfigs[i].Enabled, - MinNodeSize: workerPoolAutoscalerConfigs[i].MinSize, - MaxNodeSize: workerPoolAutoscalerConfigs[i].MaxSize, - }) - } - - if !isIncluded { - autoScalingSettingNotExistsErr := errors.New("Failed to Set Node Group Auto Scaling. err = Cannot find Node Group Auto Scaling Setting in Auto Scaler Config Map, Please try change Node Group scaling") - cblogger.Error(autoScalingSettingNotExistsErr) - LoggingError(hiscallInfo, autoScalingSettingNotExistsErr) - return false, autoScalingSettingNotExistsErr - } - } - - updateConfigMapErr := ic.updateAutoScalerConfigMap(kubeConfigStr, newNodeGroupInfo) - if updateConfigMapErr != nil { - cblogger.Error(updateConfigMapErr) - LoggingError(hiscallInfo, updateConfigMapErr) - return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", updateConfigMapErr)) - } - - LoggingInfo(hiscallInfo, start) - - return true, nil -} - -func (ic *IbmClusterHandler) ChangeNodeGroupScaling(clusterIID irs.IID, nodeGroupIID irs.IID, DesiredNodeSize int, MinNodeSize int, MaxNodeSize int) (irs.NodeGroupInfo, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "ChangeNodeGroupScaling()") - start := call.Start() - - // validation - validateErr := ic.validateAtChangeNodeGroupScaling(clusterIID, nodeGroupIID, MinNodeSize, MaxNodeSize) - if validateErr != nil { - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", validateErr)) - } - - // get resource group id - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - cblogger.Error(getResourceGroupErr) - LoggingError(hiscallInfo, getResourceGroupErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getResourceGroupErr)) - } - - irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) - if getIrsClusterErr != nil { - cblogger.Error(getIrsClusterErr) - LoggingError(hiscallInfo, getIrsClusterErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getIrsClusterErr)) - } - if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting || irsCluster.Status == irs.ClusterUpdating { - clusterStatusErr := errors.New(fmt.Sprintf("Cannot Change Node Group Scaling at %s status", irsCluster.Status)) - cblogger.Error(clusterStatusErr) - LoggingError(hiscallInfo, clusterStatusErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", clusterStatusErr)) - } - - nodeGroups, _, getNodeGroupsErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ - Cluster: core.StringPtr(irsCluster.IId.SystemId), - XRegion: core.StringPtr(ic.Region.Region), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if getNodeGroupsErr != nil { - cblogger.Error(getNodeGroupsErr) - LoggingError(hiscallInfo, getNodeGroupsErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getNodeGroupsErr)) - } - - var targetNodeGroup *kubernetesserviceapiv1.GetWorkerPoolsDetailResponse - for _, nodeGroup := range *nodeGroups { - if nodeGroup.Id == nodeGroupIID.SystemId || nodeGroup.PoolName == nodeGroupIID.NameId { - targetNodeGroup = &nodeGroup - break - } - } - if targetNodeGroup == nil { - nodeGroupNotExistErr := errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = cannot find node group: %s", nodeGroupIID)) - cblogger.Error(nodeGroupNotExistErr) - LoggingError(hiscallInfo, nodeGroupNotExistErr) - return irs.NodeGroupInfo{}, nodeGroupNotExistErr - } - - nodeGroupName := targetNodeGroup.PoolName - - kubeConfigStr, getKubeConfigErr := ic.getKubeConfig(irsCluster.IId.SystemId, resourceGroupId) - if getKubeConfigErr != nil { - cblogger.Error(getKubeConfigErr) - LoggingError(hiscallInfo, getKubeConfigErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getKubeConfigErr)) - } - - var newNodeGroupInfo []irs.NodeGroupInfo - var changedNodeGroupIndex int - configMap, getConfigMapErr := ic.getAutoScalerConfigMap(kubeConfigStr) - if getConfigMapErr != nil { - cblogger.Error(getConfigMapErr) - LoggingError(hiscallInfo, getConfigMapErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getConfigMapErr)) - } - if configMap == nil { - configMapNotExistErr := errors.New("Failed to Change Node Group Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") - cblogger.Error(configMapNotExistErr) - LoggingError(hiscallInfo, configMapNotExistErr) - return irs.NodeGroupInfo{}, configMapNotExistErr - } else { - jsonProperty, exists := configMap.Data[AutoscalerConfigMapOptionProperty] - if !exists { - propertyNotExistErr := errors.New("Failed to Change Node Group Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") - cblogger.Error(propertyNotExistErr) - LoggingError(hiscallInfo, propertyNotExistErr) - return irs.NodeGroupInfo{}, propertyNotExistErr - } - - var workerPoolAutoscalerConfigs []kubernetesserviceapiv1.WorkerPoolAutoscalerConfig - unmarshalErr := json.Unmarshal([]byte(jsonProperty), &workerPoolAutoscalerConfigs) - if unmarshalErr != nil { - cblogger.Error(unmarshalErr) - LoggingError(hiscallInfo, unmarshalErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", unmarshalErr)) - } - - isIncluded := false - for i, config := range workerPoolAutoscalerConfigs { - if config.Name == nodeGroupName { - isIncluded = true - changedNodeGroupIndex = i - workerPoolAutoscalerConfigs[i].MinSize = MinNodeSize - workerPoolAutoscalerConfigs[i].MaxSize = MaxNodeSize - } - newNodeGroupInfo = append(newNodeGroupInfo, irs.NodeGroupInfo{ - IId: irs.IID{NameId: workerPoolAutoscalerConfigs[i].Name}, - OnAutoScaling: workerPoolAutoscalerConfigs[i].Enabled, - MinNodeSize: workerPoolAutoscalerConfigs[i].MinSize, - MaxNodeSize: workerPoolAutoscalerConfigs[i].MaxSize, - }) - } - - if !isIncluded { - newNodeGroupInfo = append(newNodeGroupInfo, irs.NodeGroupInfo{ - IId: irs.IID{NameId: nodeGroupName}, - OnAutoScaling: false, - MinNodeSize: MinNodeSize, - MaxNodeSize: MaxNodeSize, - }) - changedNodeGroupIndex = len(newNodeGroupInfo) - 1 - } - } - - updateConfigMapErr := ic.updateAutoScalerConfigMap(kubeConfigStr, newNodeGroupInfo) - if updateConfigMapErr != nil { - cblogger.Error(updateConfigMapErr) - LoggingError(hiscallInfo, updateConfigMapErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", updateConfigMapErr)) - } - - // Get Workers in pool - getWorkersResult, _, getWorkersErr := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ - Cluster: core.StringPtr(irsCluster.IId.SystemId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowDeleted: core.StringPtr("false"), - Pool: core.StringPtr(targetNodeGroup.Id), - }) - if getWorkersErr != nil { - cblogger.Error(getWorkersErr) - LoggingError(hiscallInfo, getWorkersErr) - return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getWorkersErr)) - } - - var nodesIID []irs.IID - for _, worker := range getWorkersResult { - nodesIID = append(nodesIID, irs.IID{ - NameId: RetrieveUnableErr, - SystemId: *worker.ID, - }) - } - - LoggingInfo(hiscallInfo, start) - - return irs.NodeGroupInfo{ - IId: irs.IID{ - NameId: targetNodeGroup.PoolName, - SystemId: targetNodeGroup.Id, - }, - ImageIID: irs.IID{ - NameId: RetrieveUnableErr, - SystemId: RetrieveUnableErr, - }, - VMSpecName: targetNodeGroup.Flavor, - RootDiskType: RetrieveUnableErr, - RootDiskSize: RetrieveUnableErr, - KeyPairIID: irs.IID{ - NameId: RetrieveUnableErr, - SystemId: RetrieveUnableErr, - }, - OnAutoScaling: newNodeGroupInfo[changedNodeGroupIndex].OnAutoScaling, - DesiredNodeSize: -1, - MinNodeSize: newNodeGroupInfo[changedNodeGroupIndex].MinNodeSize, - MaxNodeSize: newNodeGroupInfo[changedNodeGroupIndex].MaxNodeSize, - Status: ic.getNodeGroupStatusFromString(targetNodeGroup.Lifecycle.DesiredState), - Nodes: nodesIID, - KeyValueList: nil, - }, nil -} - -func (ic *IbmClusterHandler) RemoveNodeGroup(clusterIID irs.IID, nodeGroupIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "RemoveNodeGroup()") - start := call.Start() - - // validation - if clusterIID.SystemId == "" && clusterIID.NameId == "" { - return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Cluster IID") - } - if nodeGroupIID.SystemId == "" && nodeGroupIID.NameId == "" { - return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Node Group IID") - } - - // get resource group id - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - cblogger.Error(getResourceGroupErr) - LoggingError(hiscallInfo, getResourceGroupErr) - return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", getResourceGroupErr)) - } - - irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) - if getIrsClusterErr != nil { - cblogger.Error(getIrsClusterErr) - LoggingError(hiscallInfo, getIrsClusterErr) - return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", getIrsClusterErr)) - } - if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting { - clusterStatusErr := errors.New(fmt.Sprintf("Cannot Remove Node Group at %s status", irsCluster.Status)) - cblogger.Error(clusterStatusErr) - LoggingError(hiscallInfo, clusterStatusErr) - return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", clusterStatusErr)) - } - - nodeGroups, _, getNodeGroupsErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ - Cluster: core.StringPtr(irsCluster.IId.SystemId), - XRegion: core.StringPtr(ic.Region.Region), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if getNodeGroupsErr != nil { - cblogger.Error(getNodeGroupsErr) - LoggingError(hiscallInfo, getNodeGroupsErr) - return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", getNodeGroupsErr)) - } - - var targetNodeGroup *kubernetesserviceapiv1.GetWorkerPoolsDetailResponse - for _, nodeGroup := range *nodeGroups { - if nodeGroup.Id == nodeGroupIID.SystemId || nodeGroup.PoolName == nodeGroupIID.NameId { - targetNodeGroup = &nodeGroup - break - } - } - - _, removeErr := ic.ClusterService.RemoveWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.RemoveWorkerPoolOptions{ - IdOrName: core.StringPtr(irsCluster.IId.SystemId), - PoolidOrName: core.StringPtr(targetNodeGroup.Id), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if removeErr != nil { - cblogger.Error(removeErr) - LoggingError(hiscallInfo, removeErr) - return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", removeErr)) - } - - LoggingInfo(hiscallInfo, start) - - return true, nil -} - -func (ic *IbmClusterHandler) UpgradeCluster(clusterIID irs.IID, newVersion string) (irs.ClusterInfo, error) { - hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "UpgradeCluster()") - start := call.Start() - - // validation - if clusterIID.SystemId == "" && clusterIID.NameId == "" { - return irs.ClusterInfo{}, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Cluster IID") - } - if newVersion == "" { - return irs.ClusterInfo{}, errors.New("Failed to Set Node Group Auto Scaling. err = New Version is required") - } - - // get resource group id - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - cblogger.Error(getResourceGroupErr) - LoggingError(hiscallInfo, getResourceGroupErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getResourceGroupErr)) - } - - fullClusterIID, getClusterIIDErr := ic.getClusterIID(clusterIID) - if getClusterIIDErr != nil { - cblogger.Error(getClusterIIDErr) - LoggingError(hiscallInfo, getClusterIIDErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getClusterIIDErr)) - } - - prevIrsClsuter, getIrsClusterErr := ic.GetCluster(fullClusterIID) - if getIrsClusterErr != nil { - cblogger.Error(getIrsClusterErr) - LoggingError(hiscallInfo, getIrsClusterErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getIrsClusterErr)) - } - if prevIrsClsuter.Status != irs.ClusterActive { - clusterStatusErr := errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = Cannot upgrade cluster in %s status", prevIrsClsuter.Status)) - cblogger.Error(clusterStatusErr) - LoggingError(hiscallInfo, clusterStatusErr) - return irs.ClusterInfo{}, clusterStatusErr - } - - rawCluster, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(fullClusterIID.SystemId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("true"), - }) - if getClusterErr != nil { - cblogger.Error(getClusterErr) - LoggingError(hiscallInfo, getClusterErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getClusterErr)) - } - targetCluster := (*rawCluster)[0] - - // uninstall autoscaler addon - uninstallErr := ic.uninstallAutoScalerAddon(fullClusterIID.SystemId, targetCluster.Crn, resourceGroupId) - if uninstallErr != nil { - cblogger.Error(uninstallErr) - LoggingError(hiscallInfo, uninstallErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", uninstallErr)) - } - - // upgrade master - _, updateErr := ic.ClusterService.V2UpdateMasterWithContext(ic.Ctx, &kubernetesserviceapiv1.V2UpdateMasterOptions{ - Cluster: core.StringPtr(fullClusterIID.SystemId), - Force: core.BoolPtr(false), - Version: core.StringPtr(newVersion), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if updateErr != nil { - cblogger.Error(updateErr) - LoggingError(hiscallInfo, updateErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", updateErr)) - } - ic.manageStatusTag(targetCluster.Crn, MasterUpgradeStatus, WAITING) - - // upgrade workers - go func() { - // wait until update master and uninstall autoscaler addon is done - cnt := 0 - for cnt < UpgradeMasterRetry { - // get autoscaler tags - rawCluster, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(fullClusterIID.SystemId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("true"), - }) - if getClusterErr != nil { - cnt++ - time.Sleep(time.Minute) - continue - } - targetCluster := (*rawCluster)[0] - tags, _, getTagsErr := ic.TaggingService.ListTagsWithContext(ic.Ctx, &globaltaggingv1.ListTagsOptions{ - TagType: core.StringPtr("user"), - AttachedTo: core.StringPtr(targetCluster.Crn), - }) - if getTagsErr != nil { - cnt++ - time.Sleep(time.Minute) - continue - } - - // check if master upgrade is done - isMasterUpgrading := true - isMasterUpgradeIndicated := strings.Contains(targetCluster.MasterKubeVersion, "-->") - for _, tag := range (*tags).Items { - if isTagStatusOf(*tag.Name, MasterUpgradeStatus) { - if compareTag(*tag.Name, MasterUpgradeStatus, WAITING) { - if isMasterUpgradeIndicated { - ic.manageStatusTag(targetCluster.Crn, MasterUpgradeStatus, UPGRADING) - break - } - } - if compareTag(*tag.Name, MasterUpgradeStatus, UPGRADING) { - if !isMasterUpgradeIndicated { - ic.manageStatusTag(targetCluster.Crn, MasterUpgradeStatus, "") - isMasterUpgrading = false - } - break - } - } - } - if isMasterUpgrading { - cnt++ - time.Sleep(time.Minute) - continue - } - - // upgrade workers - getWorkersResult, _, _ := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ - Cluster: core.StringPtr(fullClusterIID.SystemId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowDeleted: core.StringPtr("false"), - }) - for _, worker := range getWorkersResult { - ic.ClusterService.VpcReplaceWorker(&kubernetesserviceapiv1.VpcReplaceWorkerOptions{ - Cluster: core.StringPtr(fullClusterIID.SystemId), - Update: core.BoolPtr(true), - WorkerID: worker.ID, - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - } - break - } - }() - - // reinstall new autoscaler - prevIrsClsuter.Version = newVersion - autoScalerErr := ic.installAutoScalerAddon(prevIrsClsuter, fullClusterIID.SystemId, targetCluster.Crn, resourceGroupId, true) - if autoScalerErr != nil { - cblogger.Error(autoScalerErr) - LoggingError(hiscallInfo, autoScalerErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", autoScalerErr)) - } - - // get cluster info - irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) - if getIrsClusterErr != nil { - cblogger.Error(getIrsClusterErr) - LoggingError(hiscallInfo, getIrsClusterErr) - return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getIrsClusterErr)) - } - - LoggingInfo(hiscallInfo, start) - - return irsCluster, nil -} - -func (ic *IbmClusterHandler) applyAutoScalerOptions(clusterReqInfo irs.ClusterInfo, clusterId string, resourceGroupId string) error { - kubeConfigStr, getKubeConfigErr := ic.getKubeConfig(clusterId, resourceGroupId) - if getKubeConfigErr != nil { - return getKubeConfigErr - } - patchConfigMapErr := ic.updateAutoScalerConfigMap(kubeConfigStr, clusterReqInfo.NodeGroupList) - if patchConfigMapErr != nil { - return patchConfigMapErr - } - - return nil -} - -func (ic *IbmClusterHandler) manageStatusTag(crn string, tag string, status string) { - var deleteTargets *[]string - switch tag { - case AutoScalerStatus: - deleteTargets = &autoSaclerStates - case SecurityGroupStatus: - deleteTargets = &securityGroupStates - case MasterUpgradeStatus: - deleteTargets = &masterUpgradeStates - default: - } - - if deleteTargets != nil && len(*deleteTargets) != 0 { - ic.TaggingService.DetachTag(&globaltaggingv1.DetachTagOptions{ - Resources: []globaltaggingv1.Resource{{ - ResourceID: core.StringPtr(crn), - }}, - TagNames: *deleteTargets, - TagType: core.StringPtr("user"), - }) - } - - if status != "" { - ic.TaggingService.AttachTag(&globaltaggingv1.AttachTagOptions{ - Resources: []globaltaggingv1.Resource{{ - ResourceID: core.StringPtr(crn), - }}, - TagName: core.StringPtr(fmt.Sprintf("%s%s", tag, status)), - TagType: core.StringPtr("user"), - }) - } -} - -func (ic *IbmClusterHandler) checkIfClusterIsSupported(versionRange string, clusterK8sVersion string) bool { - clusterVersion, err := version.NewVersion(clusterK8sVersion) - if err != nil { - return false - } - - minVersion, err := version.NewVersion(strings.Split(strings.Split(versionRange, " ")[0], ">=")[1]) - if err != nil { - return false - } - - maxVersion, err := version.NewVersion(strings.Split(strings.Split(versionRange, " ")[1], "<")[1]) - if err != nil { - return false - } - - return clusterVersion.GreaterThanOrEqual(minVersion) && clusterVersion.LessThan(maxVersion) -} - -func (ic *IbmClusterHandler) createRemainingWorkerPools(clusterReqInfo irs.ClusterInfo, vpcInfo irs.VPCInfo, subnetInfo irs.SubnetInfo, rawCluster kubernetesserviceapiv1.GetClusterDetailResponse, resourceGroupId string) { - for i := 1; i < len(clusterReqInfo.NodeGroupList); i++ { - workerPool := ic.getWorkerPoolFromNodeGroupInfo(clusterReqInfo.NodeGroupList[i], vpcInfo.IId.SystemId, subnetInfo.IId.SystemId) - _, _, createWorkerPoolErr := ic.ClusterService.VpcCreateWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcCreateWorkerPoolOptions{ - Cluster: core.StringPtr(rawCluster.Id), - Flavor: workerPool.Flavor, - Isolation: workerPool.Isolation, - Name: workerPool.Name, - VpcID: workerPool.VpcID, - WorkerCount: workerPool.WorkerCount, - Zones: []kubernetesserviceapiv1.Zone{{ - ID: core.StringPtr(ic.Region.Zone), - SubnetID: core.StringPtr(subnetInfo.IId.SystemId), - }}, - Authorization: core.StringPtr(ic.CredentialInfo.AuthToken), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - Headers: nil, - }) - if createWorkerPoolErr != nil { - cblogger.Error(createWorkerPoolErr) - ic.DeleteCluster(clusterReqInfo.IId) - } - } -} - -func (ic *IbmClusterHandler) getAddonInfo(clusterId string, resourceGroupId string) (irs.AddonsInfo, error) { - rawClusterAddons, _, getClusterAddonsErr := ic.ClusterService.GetClusterAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.GetClusterAddonsOptions{ - IdOrName: core.StringPtr(clusterId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if getClusterAddonsErr != nil { - return irs.AddonsInfo{}, getClusterAddonsErr - } - var keyValues []irs.KeyValue - for _, clusterAddon := range rawClusterAddons { - addonJsonValue, marshalErr := json.Marshal(clusterAddon) - if marshalErr != nil { - cblogger.Error(marshalErr) - } - keyValues = append(keyValues, irs.KeyValue{ - Key: *clusterAddon.Name, - Value: string(addonJsonValue), - }) - } - clusterAddons := irs.AddonsInfo{KeyValueList: keyValues} - return clusterAddons, nil -} - -func (ic *IbmClusterHandler) getAutoScalerConfigMap(kubeConfigStr string) (*v1.ConfigMap, error) { - k8sClient, getK8sClientErr := ic.ClusterService.GetKubernetesClient(kubeConfigStr) - if getK8sClientErr != nil { - return nil, getK8sClientErr - } - - configMap, getConfigMapErr := k8sClient.CoreV1().ConfigMaps(ConfigMapNamespace).Get(context.Background(), AutoscalerConfigMap, metav1.GetOptions{}) - if getConfigMapErr != nil { - return nil, getConfigMapErr - } - - return configMap, nil -} - -func (ic *IbmClusterHandler) getClusterFinalStatus(clusterStatus irs.ClusterStatus, autoSaclerStatus string, securityGroupStatus string) irs.ClusterStatus { - if compareTag(autoSaclerStatus, AutoScalerStatus, FAILED) || compareTag(securityGroupStatus, SecurityGroupStatus, FAILED) { - return irs.ClusterInactive - } - if compareTag(autoSaclerStatus, AutoScalerStatus, WAITING) || - compareTag(autoSaclerStatus, AutoScalerStatus, DEPLOYING) || - compareTag(securityGroupStatus, SecurityGroupStatus, INITIALIZING) { - return irs.ClusterCreating - } - if compareTag(autoSaclerStatus, AutoScalerStatus, UPGRADE_DEPLOYING) { - return irs.ClusterUpdating - } - return clusterStatus -} - -func (ic *IbmClusterHandler) getClusterIID(clusterIID irs.IID) (irs.IID, error) { - if clusterIID.NameId == "" && clusterIID.SystemId == "" { - return irs.IID{}, errors.New("Failed to Get Cluster IID") - } - - resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() - if getResourceGroupIdErr != nil { - return irs.IID{}, errors.New(fmt.Sprintf("Failed to Get Cluster IID. err = %s", getResourceGroupIdErr)) - } - - var cluster string - if clusterIID.SystemId != "" { - cluster = clusterIID.SystemId - } else { - cluster = clusterIID.NameId - } - rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ - Cluster: core.StringPtr(cluster), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowResources: core.StringPtr("false"), - }) - if getClustersErr != nil { - return irs.IID{}, errors.New(fmt.Sprintf("Failed to Get Cluster IID. err = %s", getClustersErr)) - } - - return irs.IID{ - NameId: (*rawClusters)[0].Name, - SystemId: (*rawClusters)[0].Id, - }, nil -} - -func (ic *IbmClusterHandler) getClusterStatusFromString(clusterStatus string) irs.ClusterStatus { - switch strings.ToLower(clusterStatus) { - case "requested", "deploying", "pending": - return irs.ClusterCreating - case "normal": - return irs.ClusterActive - case "updating": - return irs.ClusterUpdating - case "aborted", "deleting": - return irs.ClusterDeleting - default: - return irs.ClusterInactive - } -} - -func (ic *IbmClusterHandler) getDefaultResourceGroupId() (string, error) { - if defaultResourceGroupId == "" { - var err error - - // create resource controller - resourceManagerManagerOptions := &resourcemanagerv2.ResourceManagerV2Options{ - Authenticator: &core.IamAuthenticator{ - ApiKey: ic.CredentialInfo.ApiKey, - }, - } - resourceManagerService, err := resourcemanagerv2.NewResourceManagerV2UsingExternalConfig(resourceManagerManagerOptions) - if err != nil { - return "", err - } - - resourceGroups, _, listResourceGroupsErr := resourceManagerService.ListResourceGroups(&resourcemanagerv2.ListResourceGroupsOptions{ - Default: core.BoolPtr(true), - }) - if listResourceGroupsErr != nil { - return "", listResourceGroupsErr - } - - for _, resourceGroup := range resourceGroups.Resources { - if strings.EqualFold(*resourceGroup.Name, DefaultResourceGroup) { - defaultResourceGroupId = *resourceGroup.ID - return defaultResourceGroupId, nil - } - } - - return "", errors.New("failed to get default resource group") - } - - return defaultResourceGroupId, nil -} - -func (ic *IbmClusterHandler) getKubeConfig(clusterId string, resourceGroupId string) (string, error) { - kubeConfig, getKubeConfigErr := ic.ClusterService.GetKubeconfigWithContext(ic.Ctx, &kubernetesserviceapiv1.GetKubeconfigOptions{ - Authorization: core.StringPtr(ic.CredentialInfo.ApiKey), - Cluster: core.StringPtr(clusterId), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - Format: core.StringPtr("yaml"), - Admin: core.BoolPtr(true), - Network: core.BoolPtr(false), - }) - if getKubeConfigErr != nil { - return "", getKubeConfigErr - } else { - resultStr, ok := kubeConfig.Result.([]byte) - if !ok { - return "", errors.New("Failed to Get Kube Config String") - } else { - return string(resultStr), nil - } - } -} - -func (ic *IbmClusterHandler) getNodeGroupStatusFromString(nodeGroupStatus string) irs.NodeGroupStatus { - // IBM Node Group does not have Creating or Updating status - // While creating a Node Group, its status is indicated as Active - // While updating Node Group such as autoscale configuration, its status is indicated as Active - switch strings.ToLower(nodeGroupStatus) { - case "active": - return irs.NodeGroupActive - case "deleting": - return irs.NodeGroupDeleting - default: - return irs.NodeGroupInactive - } -} - -func (ic *IbmClusterHandler) getWorkerPoolFromNodeGroupInfo(nodeGroupInfo irs.NodeGroupInfo, vpcId string, subnetId string) kubernetesserviceapiv1.VPCCreateClusterWorkerPool { - return kubernetesserviceapiv1.VPCCreateClusterWorkerPool{ - Name: core.StringPtr(nodeGroupInfo.IId.NameId), - Flavor: core.StringPtr(nodeGroupInfo.VMSpecName), - Isolation: core.StringPtr("public"), - VpcID: core.StringPtr(vpcId), - WorkerCount: core.Int64Ptr(int64(nodeGroupInfo.DesiredNodeSize)), - Zones: []kubernetesserviceapiv1.VPCCreateClusterWorkerPoolZone{{ - ID: core.StringPtr(ic.Region.Zone), - SubnetID: core.StringPtr(subnetId), - }}, - } -} - -func (ic *IbmClusterHandler) initSecurityGroup(clusterReqInfo irs.ClusterInfo, clusterId string, clusterCrn string) { - sgHandler := IbmSecurityHandler{ - CredentialInfo: ic.CredentialInfo, - Region: ic.Region, - VpcService: ic.VpcService, - Ctx: ic.Ctx, - } - - ic.manageStatusTag(clusterCrn, SecurityGroupStatus, INITIALIZING) - go func() { - cnt := 0 - for cnt < InitSecurityGroupRetry { - defaultSgInfo, getDSIErr := sgHandler.GetSecurity(irs.IID{NameId: fmt.Sprintf("kube-%s", clusterId)}) - if getDSIErr != nil { - time.Sleep(time.Minute) - cnt++ - continue - } - - initSuccess := true - for _, sgIID := range clusterReqInfo.Network.SecurityGroupIIDs { - sgInfo, getSgErr := sgHandler.GetSecurity(sgIID) - if getSgErr != nil { - initSuccess = false - ic.manageStatusTag(clusterCrn, SecurityGroupStatus, FAILED) - _, _ = ic.DeleteCluster(clusterReqInfo.IId) - break - } - - var updateRules []irs.SecurityRuleInfo - for _, newRule := range *sgInfo.SecurityRules { - existCheck := false - for _, baseRule := range *defaultSgInfo.SecurityRules { - if equalsRule(newRule, baseRule) { - existCheck = true - break - } - } - if existCheck { - continue - } - updateRules = append(updateRules, newRule) - } - _, sgUpdateErr := sgHandler.AddRules(defaultSgInfo.IId, &updateRules) - if sgUpdateErr != nil { - initSuccess = false - ic.manageStatusTag(clusterCrn, SecurityGroupStatus, FAILED) - _, _ = ic.DeleteCluster(clusterReqInfo.IId) - break - } - } - if initSuccess { - ic.manageStatusTag(clusterCrn, SecurityGroupStatus, INITIALIZED) - } - break - } - }() - - return -} - -func (ic *IbmClusterHandler) installAutoScalerAddon(clusterReqInfo irs.ClusterInfo, clusterId string, clusterCrn string, resourceGroupId string, isUpdating bool) error { - // check exists - addonsInfo, _ := ic.getAddonInfo(clusterId, resourceGroupId) - for _, addon := range addonsInfo.KeyValueList { - if addon.Key == AutoscalerAddon && strings.Contains(addon.Value, "\"healthState\":\"normal\"") { - ic.manageStatusTag(clusterCrn, AutoScalerStatus, ACTIVE) - return nil - } - } - - // start install addon - availableAddons, _, getAvailAddonsErr := ic.ClusterService.GetAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.GetAddonsOptions{}) - if getAvailAddonsErr != nil { - return errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getAvailAddonsErr)) - } - var availableAutoScalerAddons []kubernetesserviceapiv1.AddonCommon - for _, availableAddon := range availableAddons { - if *availableAddon.Name == AutoscalerAddon && - ic.checkIfClusterIsSupported(*availableAddon.SupportedKubeRange, clusterReqInfo.Version) { - availableAutoScalerAddons = append(availableAutoScalerAddons, availableAddon) - } - } - if len(availableAutoScalerAddons) < 1 { - return errors.New(fmt.Sprintf("Failed to install autoscaler addon. err = No available autoscaler addon for this Kubernetes version: %s", clusterReqInfo.Version)) - } - - addons := []kubernetesserviceapiv1.ClusterAddon{{ - Name: availableAutoScalerAddons[0].Name, - Version: availableAutoScalerAddons[0].Version, - }} - - go func() { - cnt := 0 - enableSuccess := false - ic.manageStatusTag(clusterCrn, AutoScalerStatus, WAITING) - for cnt < EnableAutoScalerRetry { - _, enableAddonDetail, enableAddonErr := ic.ClusterService.ManageClusterAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.ManageClusterAddonsOptions{ - IdOrName: core.StringPtr(clusterId), - Addons: addons, - Enable: core.BoolPtr(true), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if enableAddonErr != nil { - resultMap, toMapOk := enableAddonDetail.GetResultAsMap() - if toMapOk { - descriptionStr, toStrOk := resultMap["description"].(string) - if toStrOk { - if !strings.Contains(descriptionStr, "The cluster is not fully deployed, please wait a couple minutes before enabling the add-on.") { - break - } - } - } - } else { - enableSuccess = true - break - } - time.Sleep(time.Minute) - cnt++ - } - if !enableSuccess { - ic.manageStatusTag(clusterCrn, AutoScalerStatus, FAILED) - } else { - if isUpdating { - ic.manageStatusTag(clusterCrn, AutoScalerStatus, UPGRADE_DEPLOYING) - } else { - ic.manageStatusTag(clusterCrn, AutoScalerStatus, DEPLOYING) - } - - go func() { - cnt = 0 - for cnt < EnableAutoScalerRetry { - addonsInfo, _ := ic.getAddonInfo(clusterId, resourceGroupId) - for _, addon := range addonsInfo.KeyValueList { - if addon.Key == AutoscalerAddon && strings.Contains(addon.Value, "\"healthState\":\"normal\"") { - ic.manageStatusTag(clusterCrn, AutoScalerStatus, ACTIVE) - ic.applyAutoScalerOptions(clusterReqInfo, clusterId, resourceGroupId) - return - } - } - - time.Sleep(time.Minute) - cnt++ - } - ic.manageStatusTag(clusterCrn, AutoScalerStatus, FAILED) - if !isUpdating { - ic.DeleteCluster(clusterReqInfo.IId) - } - }() - } - }() - - return nil -} - -func (ic *IbmClusterHandler) setClusterInfo(rawCluster kubernetesserviceapiv1.GetClusterDetailResponse) (irs.ClusterInfo, error) { - resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() - if getResourceGroupErr != nil { - return irs.ClusterInfo{}, getResourceGroupErr - } - - // Get VPC Infos - vpcIID := irs.IID{ - NameId: "", - SystemId: rawCluster.Vpcs[0], - } - vpcInfo, getVPCErr := GetRawVPC(vpcIID, ic.VpcService, ic.Ctx) - if getVPCErr != nil { - return irs.ClusterInfo{}, getVPCErr - } - vpcIID.NameId = *vpcInfo.Name - - // Get Addon Infos - clusterAddons, getAddonErr := ic.getAddonInfo(rawCluster.Id, resourceGroupId) - if getAddonErr != nil { - return irs.ClusterInfo{}, getAddonErr - } - - // Get Worker pool Infos - getWorkerPoolsResult, _, getWorkerPoolErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ - Cluster: core.StringPtr(rawCluster.Id), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if getWorkerPoolErr != nil { - return irs.ClusterInfo{}, getWorkerPoolErr - } - - var nodeGroupList []irs.NodeGroupInfo - for _, element := range *getWorkerPoolsResult { - // Get Workers in pool - getWorkersResult, _, getWorkersErr := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ - Cluster: core.StringPtr(rawCluster.Id), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - ShowDeleted: core.StringPtr("false"), - Pool: core.StringPtr(element.Id), - }) - if getWorkersErr != nil { - return irs.ClusterInfo{}, getWorkersErr - } - - var nodesIID []irs.IID - for _, worker := range getWorkersResult { - nodesIID = append(nodesIID, irs.IID{ - NameId: RetrieveUnableErr, - SystemId: *worker.ID, - }) - } - - nodeGroupList = append(nodeGroupList, irs.NodeGroupInfo{ - IId: irs.IID{ - NameId: element.PoolName, - SystemId: element.Id, - }, - ImageIID: irs.IID{ - NameId: RetrieveUnableErr, - SystemId: RetrieveUnableErr, - }, - VMSpecName: element.Flavor, - RootDiskType: RetrieveUnableErr, - RootDiskSize: RetrieveUnableErr, - KeyPairIID: irs.IID{ - NameId: RetrieveUnableErr, - SystemId: RetrieveUnableErr, - }, - OnAutoScaling: false, - DesiredNodeSize: -1, - MinNodeSize: 0, - MaxNodeSize: 0, - Status: ic.getNodeGroupStatusFromString(element.Lifecycle.DesiredState), - Nodes: nodesIID, - KeyValueList: nil, - }) - } - - // Get Network.Subnet Info - rawVpeList, _, getRawVpeListErr := ic.VpcService.ListEndpointGateways(&vpcv1.ListEndpointGatewaysOptions{ - ResourceGroupID: core.StringPtr(resourceGroupId), - }) - if getRawVpeListErr != nil { - return irs.ClusterInfo{}, getRawVpeListErr - } - - var target vpcv1.EndpointGateway - for _, rawVpe := range rawVpeList.EndpointGateways { - if *rawVpe.Name == fmt.Sprintf("iks-%s", rawCluster.Id) { - target = rawVpe - } - } - - var subnetIIDs []irs.IID - for _, ip := range target.Ips { - if strings.Contains(*ip.Name, rawCluster.Id) { - subnetId := strings.Split(*ip.Href, "/")[5] - rawSubnet, _, getRawSubnetErr := ic.VpcService.GetSubnet(&vpcv1.GetSubnetOptions{ - ID: core.StringPtr(subnetId), - }) - if getRawSubnetErr == nil { - subnetIIDs = append(subnetIIDs, irs.IID{ - NameId: *rawSubnet.Name, - SystemId: *rawSubnet.ID, - }) - } - } - } - - // Get Security Group - sgHandler := IbmSecurityHandler{ - CredentialInfo: ic.CredentialInfo, - Region: ic.Region, - VpcService: ic.VpcService, - Ctx: ic.Ctx, - } - sgInfo, sgInfoErr := sgHandler.GetSecurity(irs.IID{NameId: fmt.Sprintf("kube-%s", rawCluster.Id)}) - if sgInfoErr != nil { - return irs.ClusterInfo{}, sgInfoErr - } - - securityGroups := []irs.IID{sgInfo.IId} - - // Convert Created Time - createdTime, _ := strfmt.ParseDateTime(rawCluster.CreatedDate) - - // Determine Endpoint - var serviceEndpoint string - if rawCluster.ServiceEndpoints.PublicServiceEndpointEnabled { - serviceEndpoint = rawCluster.ServiceEndpoints.PublicServiceEndpointURL - } else { - serviceEndpoint = rawCluster.ServiceEndpoints.PrivateServiceEndpointURL - } - - // Get KubeConfig - kubeConfigStr, getKubeConfigStrErr := ic.getKubeConfig(rawCluster.Id, resourceGroupId) - if getKubeConfigStrErr == nil { - // Get Autoscaling Info - configMap, getAutoScalerConfigMapErr := ic.getAutoScalerConfigMap(kubeConfigStr) - if getAutoScalerConfigMapErr != nil { - cblogger.Error(getAutoScalerConfigMapErr) - } - - if configMap == nil { - for index, _ := range nodeGroupList { - nodeGroupList[index].OnAutoScaling = false - nodeGroupList[index].MinNodeSize = -1 - nodeGroupList[index].MaxNodeSize = -1 - nodeGroupList[index].DesiredNodeSize = -1 - } - } else { - jsonProperty, exists := configMap.Data[AutoscalerConfigMapOptionProperty] - if !exists { - cblogger.Error(errors.New("Failed to get Autoscaler Config from Config Map")) - } - - var workerPoolAutoscalerConfigs []kubernetesserviceapiv1.WorkerPoolAutoscalerConfig - unmarshalErr := json.Unmarshal([]byte(jsonProperty), &workerPoolAutoscalerConfigs) - if unmarshalErr != nil { - cblogger.Error(unmarshalErr) - } - - for index, nodeGroup := range nodeGroupList { - for _, config := range workerPoolAutoscalerConfigs { - if config.Name == nodeGroup.IId.NameId { - nodeGroupList[index].OnAutoScaling = config.Enabled - nodeGroupList[index].MinNodeSize = config.MinSize - nodeGroupList[index].MaxNodeSize = config.MaxSize - nodeGroupList[index].DesiredNodeSize = -1 - } - } - } - } - } else { - cblogger.Error(getKubeConfigStrErr) - } - - // get cluster status - clusterStatus := ic.getClusterStatusFromString(rawCluster.State) - rawTags, _, getTagsErr := ic.TaggingService.ListTagsWithContext(ic.Ctx, &globaltaggingv1.ListTagsOptions{ - TagType: core.StringPtr("user"), - Providers: []string{"ghost"}, - AttachedTo: core.StringPtr(rawCluster.Crn), - }) - if getTagsErr != nil { - clusterStatus = irs.ClusterInactive - } - - autoScalerStatus := fmt.Sprintf("%s%s", AutoScalerStatus, FAILED) - for _, tag := range rawTags.Items { - if isTagStatusOf(*tag.Name, AutoScalerStatus) { - autoScalerStatus = *tag.Name - break - } - } - securityGroupStatus := fmt.Sprintf("%s%s", SecurityGroupStatus, FAILED) - for _, tag := range rawTags.Items { - if isTagStatusOf(*tag.Name, SecurityGroupStatus) { - securityGroupStatus = *tag.Name - break - } - } - clusterStatus = ic.getClusterFinalStatus(clusterStatus, autoScalerStatus, securityGroupStatus) - - // Build result - return irs.ClusterInfo{ - IId: irs.IID{ - NameId: rawCluster.Name, - SystemId: rawCluster.Id, - }, - Version: rawCluster.MasterKubeVersion, - Network: irs.NetworkInfo{ - VpcIID: vpcIID, - SubnetIIDs: subnetIIDs, - SecurityGroupIIDs: securityGroups, - KeyValueList: nil, - }, - NodeGroupList: nodeGroupList, - AccessInfo: irs.AccessInfo{ - Endpoint: serviceEndpoint, - Kubeconfig: kubeConfigStr, - }, - Addons: clusterAddons, - Status: clusterStatus, - CreatedTime: time.Time(createdTime).Local(), - KeyValueList: nil, - }, nil -} - -func (ic *IbmClusterHandler) uninstallAutoScalerAddon(clusterId string, clusterCrn string, resourceGroupId string) error { - addons := []kubernetesserviceapiv1.ClusterAddon{{ - Name: core.StringPtr(AutoscalerAddon), - }} - _, _, disableAddonErr := ic.ClusterService.ManageClusterAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.ManageClusterAddonsOptions{ - IdOrName: core.StringPtr(clusterId), - Addons: addons, - Enable: core.BoolPtr(false), - XAuthResourceGroup: core.StringPtr(resourceGroupId), - }) - if disableAddonErr != nil { - return disableAddonErr - } - - go func() { - ic.manageStatusTag(clusterCrn, AutoScalerStatus, UNINSTALLING) - - cnt := 0 - for cnt < DisableAutoScalerRetry { - autoScalerAddonExists := false - addonsInfo, _ := ic.getAddonInfo(clusterId, resourceGroupId) - for _, addon := range addonsInfo.KeyValueList { - if addon.Key == AutoscalerAddon { - cnt++ - autoScalerAddonExists = true - time.Sleep(time.Minute) - break - } - } - if !autoScalerAddonExists { - // remove autoscaler tag - ic.manageStatusTag(clusterCrn, AutoScalerStatus, "") - break - } - } - }() - - return nil -} - -func (ic *IbmClusterHandler) updateAutoScalerConfigMap(kubeConfigStr string, nodeGroupList []irs.NodeGroupInfo) error { - k8sClient, getK8sClientErr := ic.ClusterService.GetKubernetesClient(kubeConfigStr) - if getK8sClientErr != nil { - return getK8sClientErr - } - - configMap, getConfigMapErr := k8sClient.CoreV1().ConfigMaps(ConfigMapNamespace).Get(context.Background(), AutoscalerConfigMap, metav1.GetOptions{}) - if getConfigMapErr != nil { - return getConfigMapErr - } - - workerPoolAutoscalerConfigs := make([]kubernetesserviceapiv1.WorkerPoolAutoscalerConfig, len(nodeGroupList)) - for i, nodeGroup := range nodeGroupList { - workerPoolAutoscalerConfigs[i].Name = nodeGroup.IId.NameId - workerPoolAutoscalerConfigs[i].Enabled = nodeGroup.OnAutoScaling - workerPoolAutoscalerConfigs[i].MaxSize = nodeGroup.MaxNodeSize - workerPoolAutoscalerConfigs[i].MinSize = nodeGroup.MinNodeSize - } - - newConfigJsonStr, marshalErr := json.Marshal(workerPoolAutoscalerConfigs) - if marshalErr != nil { - return marshalErr - } - configMap.Data[AutoscalerConfigMapOptionProperty] = string(newConfigJsonStr) - - _, updateErr := k8sClient.CoreV1().ConfigMaps(ConfigMapNamespace).Update(context.Background(), configMap, metav1.UpdateOptions{}) - if updateErr != nil { - return updateErr - } - - return nil -} - -func (ic *IbmClusterHandler) validateAndGetSubnetInfo(networkInfo irs.NetworkInfo) (irs.SubnetInfo, error) { - if len(networkInfo.SubnetIIDs) > 1 { - return irs.SubnetInfo{}, errors.New("IBM Kubernetes cluster can be created with only 1 subnet per zone") - } - - vpcHandler := IbmVPCHandler{ - CredentialInfo: ic.CredentialInfo, - Region: ic.Region, - VpcService: ic.VpcService, - Ctx: ic.Ctx, - } - vpcInfo, getVpcErr := vpcHandler.GetVPC(networkInfo.VpcIID) - if getVpcErr != nil { - return irs.SubnetInfo{}, getVpcErr - } - - for _, subnetInfo := range vpcInfo.SubnetInfoList { - if subnetInfo.IId.NameId == networkInfo.SubnetIIDs[0].NameId || - subnetInfo.IId.SystemId == networkInfo.SubnetIIDs[0].SystemId { - return subnetInfo, nil - } - } - return irs.SubnetInfo{}, errors.New(fmt.Sprintf("Cannot use given subnet: %v from VPC: %v", networkInfo.SubnetIIDs[0], vpcInfo.IId)) -} - -func (ic *IbmClusterHandler) validateAtCreateCluster(clusterInfo irs.ClusterInfo) error { - if clusterInfo.IId.NameId == "" { - return errors.New("Cluster name is required") - } - if clusterInfo.Network.VpcIID.SystemId == "" && clusterInfo.Network.VpcIID.NameId == "" { - return errors.New(fmt.Sprintf("Cannot identify VPC. IID: %s", clusterInfo.Network.VpcIID)) - } - if len(clusterInfo.Network.SubnetIIDs) < 1 { - return errors.New("At least one Subnet must be specified") - } - if len(clusterInfo.NodeGroupList) < 1 { - return errors.New("At least one Node Group must be specified") - } - if clusterInfo.Version == "" || clusterInfo.Version == "default" { - clusterInfo.Version = "1.24.8" - } - for i, nodeGroup := range clusterInfo.NodeGroupList { - if i != 0 && nodeGroup.IId.NameId == "" { - return errors.New(fmt.Sprintf("Node Group name is required for Node Group #%d ", i)) - } - if nodeGroup.MaxNodeSize < 1 { - return errors.New(fmt.Sprintf("MaxNodeSize of Node Group: %s cannot be smaller than 1", nodeGroup.IId)) - } - if nodeGroup.MinNodeSize < 1 { - return errors.New(fmt.Sprintf("MinNodeSize of Node Group: %s cannot be smaller than 1", nodeGroup.IId)) - } - if nodeGroup.DesiredNodeSize < 1 { - return errors.New(fmt.Sprintf("DesiredNodeSize of Node Group: %s cannot be smaller than 1", nodeGroup.IId)) - } - if nodeGroup.VMSpecName == "" { - return errors.New("VM Spec Name is required") - } - } - - return nil -} - -func (ic *IbmClusterHandler) validateAtAddNodeGroup(clusterIID irs.IID, nodeGroupInfo irs.NodeGroupInfo) interface{} { - if clusterIID.SystemId == "" && clusterIID.NameId == "" { - return errors.New("Invalid Cluster IID") - } - if nodeGroupInfo.IId.NameId == "" { - return errors.New("Node Group name is required") - } - if nodeGroupInfo.MaxNodeSize < 1 { - return errors.New("MaxNodeSize cannot be smaller than 1") - } - if nodeGroupInfo.MinNodeSize < 1 { - return errors.New("MaxNodeSize cannot be smaller than 1") - } - if nodeGroupInfo.DesiredNodeSize < 1 { - return errors.New("DesiredNodeSize cannot be smaller than 1") - } - if nodeGroupInfo.VMSpecName == "" { - return errors.New("VM Spec Name is required") - } - - return nil -} - -func (ic *IbmClusterHandler) validateAtChangeNodeGroupScaling(clusterIID irs.IID, nodeGroupIID irs.IID, minNodeSize int, maxNodeSize int) error { - if clusterIID.SystemId == "" && clusterIID.NameId == "" { - return errors.New("Invalid Cluster IID") - } - if nodeGroupIID.SystemId == "" && nodeGroupIID.NameId == "" { - return errors.New("Invalid Node Group IID") - } - if minNodeSize < 1 { - return errors.New("MaxNodeSize cannot be smaller than 1") - } - if maxNodeSize < 1 { - return errors.New("MaxNodeSize cannot be smaller than 1") - } - - return nil -} - -func compareTag(tag string, statusCode string, status string) bool { - return strings.EqualFold(tag, fmt.Sprintf("%s%s", statusCode, status)) -} - -func isTagStatusOf(tag string, statusCode string) bool { - return strings.Contains(tag, strings.ToLower(statusCode)) -} +package resources + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" + "github.com/IBM/vpc-go-sdk/vpcv1" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" + "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/utils/kubernetesserviceapiv1" + idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" + irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" + "github.com/go-openapi/strfmt" + "github.com/hashicorp/go-version" + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "strings" + "sync" + "time" +) + +const ( + // Resource Names + DefaultResourceGroup = "Default" + AutoscalerAddon = "cluster-autoscaler" + ConfigMapNamespace = "kube-system" + AutoscalerConfigMap = "iks-ca-configmap" + AutoscalerConfigMapOptionProperty = "workerPoolsConfig.json" + + // Error Codes + RetrieveUnableErr = "Not visible in IBMCloud-VPC" + GetKubeConfigErr = "Get Kube Config Error" + GetAutoScalerConfigErr = "Get Autoscaler Config Map Error" + + // Retry Counts + EnableAutoScalerRetry = 120 // minutes + DisableAutoScalerRetry = 120 // minutes + InitSecurityGroupRetry = 120 // minutes + RestoreDefaultSGRetry = 120 // minutes + UpgradeMasterRetry = 120 // minutes + + // Status tags + AutoScalerStatus = "CB-SPIDER-PMKS-AUTOSCALER-STATUS:" + SecurityGroupStatus = "CB-SPIDER-PMKS-SECURITYGROUP-STATUS:" + MasterUpgradeStatus = "CB-SPIDER-PMKS-MASTERUPGRADE-STATUS:" + + // State Codes + WAITING = "WAITING" + DEPLOYING = "DEPLOYING" + UPGRADE_DEPLOYING = "UPGRADE-DEPLOYING" + ACTIVE = "ACTIVE" + UNINSTALLING = "UNINSTALLING" + FAILED = "FAILED" + INITIALIZING = "INITIALIZING" + INITIALIZED = "INITIALIZED" + UPGRADING = "UPGRADING" +) + +var autoSaclerStates []string +var securityGroupStates []string +var masterUpgradeStates []string + +func init() { + autoSaclerStates = []string{WAITING, DEPLOYING, UPGRADE_DEPLOYING, ACTIVE, UNINSTALLING, FAILED} + for i, state := range autoSaclerStates { + autoSaclerStates[i] = fmt.Sprintf("%s%s", AutoScalerStatus, state) + } + securityGroupStates = []string{INITIALIZING, INITIALIZED, FAILED} + for i, state := range securityGroupStates { + securityGroupStates[i] = fmt.Sprintf("%s%s", SecurityGroupStatus, state) + } + masterUpgradeStates = []string{WAITING, UPGRADING} + for i, state := range masterUpgradeStates { + masterUpgradeStates[i] = fmt.Sprintf("%s%s", MasterUpgradeStatus, state) + } +} + +type IbmClusterHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + Ctx context.Context + VpcService *vpcv1.VpcV1 + ClusterService *kubernetesserviceapiv1.KubernetesServiceApiV1 + TaggingService *globaltaggingv1.GlobalTaggingV1 +} + +var defaultResourceGroupId string + +func (ic *IbmClusterHandler) CreateCluster(clusterReqInfo irs.ClusterInfo) (irs.ClusterInfo, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterReqInfo.IId.NameId, "CreateCluster()") + start := call.Start() + + // validation + validationErr := ic.validateAtCreateCluster(clusterReqInfo) + if validationErr != nil { + cblogger.Error(validationErr) + LoggingError(hiscallInfo, validationErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", validationErr)) + } + + // get resource group id + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + cblogger.Error(getResourceGroupErr) + LoggingError(hiscallInfo, getResourceGroupErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getResourceGroupErr)) + } + + // get vpc info + vpcHandler := IbmVPCHandler{ + CredentialInfo: ic.CredentialInfo, + Region: ic.Region, + VpcService: ic.VpcService, + Ctx: ic.Ctx, + } + vpcInfo, getVpcInfoErr := vpcHandler.GetVPC(clusterReqInfo.Network.VpcIID) + if getVpcInfoErr != nil { + cblogger.Error(getVpcInfoErr) + LoggingError(hiscallInfo, getVpcInfoErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getVpcInfoErr)) + } + + // get subnet info + subnetInfo, getSubnetInfoErr := ic.validateAndGetSubnetInfo(clusterReqInfo.Network) + if getSubnetInfoErr != nil { + cblogger.Error(getSubnetInfoErr) + LoggingError(hiscallInfo, getSubnetInfoErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getSubnetInfoErr)) + } + + // check exists + _, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(clusterReqInfo.IId.NameId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("false"), + }) + if getClusterErr != nil && getClusterErr.Error() == "Not Found" { + // get first worker pool for cluster creation + workerPool := ic.getWorkerPoolFromNodeGroupInfo(clusterReqInfo.NodeGroupList[0], vpcInfo.IId.SystemId, subnetInfo.IId.SystemId) + + // create cluster if not exists + _, _, createClusterErr := ic.ClusterService.VpcCreateClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcCreateClusterOptions{ + DisablePublicServiceEndpoint: core.BoolPtr(false), + KubeVersion: core.StringPtr(clusterReqInfo.Version), + Name: core.StringPtr(clusterReqInfo.IId.NameId), + Provider: core.StringPtr("vpc-gen2"), + WorkerPool: &workerPool, + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if createClusterErr != nil { + cblogger.Error(createClusterErr) + LoggingError(hiscallInfo, createClusterErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", createClusterErr)) + } + + rawVpcInfo, _, getRawVpcErr := ic.VpcService.GetVPCWithContext(ic.Ctx, &vpcv1.GetVPCOptions{ + ID: core.StringPtr(vpcInfo.IId.SystemId), + }) + if getRawVpcErr != nil { + cblogger.Error(getRawVpcErr) + LoggingError(hiscallInfo, getRawVpcErr) + _, _ = ic.DeleteCluster(clusterReqInfo.IId) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getRawVpcErr)) + } + + sgHander := IbmSecurityHandler{ + CredentialInfo: ic.CredentialInfo, + Region: ic.Region, + Ctx: ic.Ctx, + VpcService: ic.VpcService, + } + + // restore VPC default security group + // VPC default security group lost rules for unknown reasons while creating a cluster with API + // It makes communication failure between worker and master nodes in the cluster and worker status reaches failure + go func() { + cnt := 0 + for cnt < RestoreDefaultSGRetry { + isSkip := false + brokenVpcDefaultSg, getBrokenVpcDefaultSgErr := sgHander.GetSecurity(irs.IID{SystemId: *rawVpcInfo.DefaultSecurityGroup.ID}) + if getBrokenVpcDefaultSgErr != nil { + isSkip = true + } else { + rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(clusterReqInfo.IId.NameId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("true"), + }) + if getClustersErr != nil { + isSkip = true + } + rawCluster := (*rawClusters)[0] + if rawCluster.State != "deploying" { + isSkip = true + } + } + if isSkip { + cnt++ + time.Sleep(time.Minute) + } else { + mandatoriyRuleList := []irs.SecurityRuleInfo{{ + Direction: "inbound", + IPProtocol: "tcp", + FromPort: "22", + ToPort: "22", + }, { + Direction: "inbound", + IPProtocol: "icmp", + FromPort: "-1", + ToPort: "-1", + }, { + Direction: "outbound", + IPProtocol: "all", + FromPort: "-1", + ToPort: "-1", + CIDR: "0.0.0.0/0", + }} + + _, addRuleErr := sgHander.AddRules(brokenVpcDefaultSg.IId, &mandatoriyRuleList) + if addRuleErr != nil { + cblogger.Error(addRuleErr) + LoggingError(hiscallInfo, addRuleErr) + ic.DeleteCluster(clusterReqInfo.IId) + } + break + } + } + }() + + } else if getClusterErr != nil { + cblogger.Error(getClusterErr) + LoggingError(hiscallInfo, getClusterErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getClusterErr)) + } + + // get created cluster info + rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(clusterReqInfo.IId.NameId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("true"), + }) + if getClustersErr != nil { + cblogger.Error(getClustersErr) + LoggingError(hiscallInfo, getClustersErr) + ic.DeleteCluster(clusterReqInfo.IId) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClustersErr)) + } + rawCluster := (*rawClusters)[0] + + // Enable cluster-autoscaler addon and apply autoscaler option + autoScalerErr := ic.installAutoScalerAddon(clusterReqInfo, rawCluster.Id, rawCluster.Crn, resourceGroupId, false) + if autoScalerErr != nil { + cblogger.Error(autoScalerErr) + LoggingError(hiscallInfo, autoScalerErr) + ic.DeleteCluster(clusterReqInfo.IId) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", autoScalerErr)) + } + + // Add remaining worker pools + ic.createRemainingWorkerPools(clusterReqInfo, vpcInfo, subnetInfo, rawCluster, resourceGroupId) + + // Set Security Group + ic.initSecurityGroup(clusterReqInfo, rawCluster.Id, rawCluster.Crn) + + clusterInfo, getClusterErr := ic.GetCluster(irs.IID{SystemId: rawCluster.Id}) + if getClusterErr != nil { + cblogger.Error(getClusterErr) + LoggingError(hiscallInfo, getClusterErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getClusterErr)) + } + + LoggingInfo(hiscallInfo, start) + + // Attach Tag + if clusterReqInfo.TagList != nil && len(clusterReqInfo.TagList) > 0 { + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range clusterReqInfo.TagList{ + _, err := tagHandler.AddTag("CLUSTER", clusterReqInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on Cluster err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + return clusterInfo, nil +} + +func (ic *IbmClusterHandler) ListCluster() ([]*irs.ClusterInfo, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, "", "ListCluster()") + start := call.Start() + + resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() + if getResourceGroupIdErr != nil { + cblogger.Error(getResourceGroupIdErr) + LoggingError(hiscallInfo, getResourceGroupIdErr) + return []*irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to List Cluster. err = %s", getResourceGroupIdErr)) + } + + clusterList, _, getClusterListErr := ic.ClusterService.VpcGetClustersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClustersOptions{ + XAuthResourceGroup: core.StringPtr(resourceGroupId), + Provider: core.StringPtr("vpc-gen2"), + }) + if getClusterListErr != nil { + cblogger.Error(getClusterListErr) + LoggingError(hiscallInfo, getClusterListErr) + return []*irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to List Cluster. err = %s", getClusterListErr)) + } + + var wait sync.WaitGroup + wait.Add(len(clusterList)) + var ret []*irs.ClusterInfo + for _, cluster := range clusterList { + go func() { + defer wait.Done() + irsCluster, getIrsClusterErr := ic.GetCluster(irs.IID{SystemId: *cluster.ID}) + if getIrsClusterErr == nil { + ret = append(ret, &irsCluster) + } + }() + } + wait.Wait() + + LoggingInfo(hiscallInfo, start) + + return ret, nil +} + +func (ic *IbmClusterHandler) getRawCluster(clusterIID irs.IID) (kubernetesserviceapiv1.GetClusterDetailResponse, error) { + rawCluster := kubernetesserviceapiv1.GetClusterDetailResponse{} + + if clusterIID.NameId == "" && clusterIID.SystemId == "" { + return rawCluster, errors.New("Failed to Get Cluster. err = invalid IID") + } + + resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() + if getResourceGroupIdErr != nil { + return rawCluster, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getResourceGroupIdErr)) + } + + var cluster string + if clusterIID.SystemId != "" { + cluster = clusterIID.SystemId + } else { + cluster = clusterIID.NameId + } + rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(cluster), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("true"), + }) + if getClustersErr != nil { + return rawCluster, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClustersErr)) + } + + for _, rCluster := range *rawClusters { + if rCluster.Id == clusterIID.SystemId || rCluster.Name == clusterIID.NameId { + return rCluster, nil + } + } + + return rawCluster, errors.New("Failed to Get Cluster. err = cluster not found") +} + +func (ic *IbmClusterHandler) GetCluster(clusterIID irs.IID) (irs.ClusterInfo, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "GetCluster()") + start := call.Start() + + if clusterIID.NameId == "" && clusterIID.SystemId == "" { + return irs.ClusterInfo{}, errors.New("Failed to Get Cluster. err = invalid IID") + } + + resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() + if getResourceGroupIdErr != nil { + cblogger.Error(getResourceGroupIdErr) + LoggingError(hiscallInfo, getResourceGroupIdErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getResourceGroupIdErr)) + } + + var cluster string + if clusterIID.SystemId != "" { + cluster = clusterIID.SystemId + } else { + cluster = clusterIID.NameId + } + rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(cluster), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("true"), + }) + if getClustersErr != nil { + cblogger.Error(getClustersErr) + LoggingError(hiscallInfo, getClustersErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClustersErr)) + } + + for _, rawCluster := range *rawClusters { + if rawCluster.Id == clusterIID.SystemId || rawCluster.Name == clusterIID.NameId { + ret, getClusterInfoErr := ic.setClusterInfo(rawCluster) + if getClusterInfoErr != nil { + cblogger.Error(getClusterInfoErr) + LoggingError(hiscallInfo, getClusterInfoErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Get Cluster. err = %s", getClusterInfoErr)) + } + LoggingInfo(hiscallInfo, start) + return ret, nil + } + } + + LoggingInfo(hiscallInfo, start) + return irs.ClusterInfo{}, nil +} + +func (ic *IbmClusterHandler) DeleteCluster(clusterIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "DeleteCluster()") + start := call.Start() + + if clusterIID.NameId == "" && clusterIID.SystemId == "" { + return false, errors.New("Failed to Delete Cluster. err = invalid IID") + } + + // get resource group id + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + cblogger.Error(getResourceGroupErr) + LoggingError(hiscallInfo, getResourceGroupErr) + return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", getResourceGroupErr)) + } + + // check exists + fullClusterIID, getClusterIIDErr := ic.getClusterIID(clusterIID) + if getClusterIIDErr != nil { + cblogger.Error(getClusterIIDErr) + LoggingError(hiscallInfo, getClusterIIDErr) + return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", getClusterIIDErr)) + } + + rawCluster, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(fullClusterIID.SystemId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("false"), + }) + if getClusterErr != nil { + cblogger.Error(getClusterErr) + LoggingError(hiscallInfo, getClusterErr) + return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", getClusterErr)) + } + + // delete cluster + _, deleteClusterErr := ic.ClusterService.RemoveClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.RemoveClusterOptions{ + IdOrName: core.StringPtr((*rawCluster)[0].Id), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + DeleteResources: core.StringPtr("true"), + }) + if deleteClusterErr != nil { + cblogger.Error(deleteClusterErr) + LoggingError(hiscallInfo, deleteClusterErr) + return false, errors.New(fmt.Sprintf("Failed to Delete Cluster. err = %s", deleteClusterErr)) + } + + LoggingInfo(hiscallInfo, start) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err := tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Cluster Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + + return true, nil +} + +func (ic *IbmClusterHandler) AddNodeGroup(clusterIID irs.IID, nodeGroupReqInfo irs.NodeGroupInfo) (irs.NodeGroupInfo, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "AddNodeGroup()") + start := call.Start() + + // validation + validateErr := ic.validateAtAddNodeGroup(clusterIID, nodeGroupReqInfo) + if validateErr != nil { + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", validateErr)) + } + + // get resource group id + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + cblogger.Error(getResourceGroupErr) + LoggingError(hiscallInfo, getResourceGroupErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getResourceGroupErr)) + } + + irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) + if getIrsClusterErr != nil { + cblogger.Error(getIrsClusterErr) + LoggingError(hiscallInfo, getIrsClusterErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getIrsClusterErr)) + } + if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting { + clusterStatusErr := errors.New(fmt.Sprintf("Cannot Add Node Group at %s status", irsCluster.Status)) + cblogger.Error(clusterStatusErr) + LoggingError(hiscallInfo, clusterStatusErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", clusterStatusErr)) + } + + // Get Network.Subnet Info + rawVpeList, _, getRawVpeListErr := ic.VpcService.ListEndpointGateways(&vpcv1.ListEndpointGatewaysOptions{ + ResourceGroupID: core.StringPtr(resourceGroupId), + }) + if getRawVpeListErr != nil { + cblogger.Error(getRawVpeListErr) + LoggingError(hiscallInfo, getRawVpeListErr) + return irs.NodeGroupInfo{}, getRawVpeListErr + } + + var target vpcv1.EndpointGateway + for _, rawVpe := range rawVpeList.EndpointGateways { + if *rawVpe.Name == fmt.Sprintf("iks-%s", irsCluster.IId.SystemId) { + target = rawVpe + } + } + + var subnetIID irs.IID + for _, ip := range target.Ips { + if strings.Contains(*ip.Name, irsCluster.IId.SystemId) { + subnetId := strings.Split(*ip.Href, "/")[5] + rawSubnet, _, getRawSubnetErr := ic.VpcService.GetSubnet(&vpcv1.GetSubnetOptions{ + ID: core.StringPtr(subnetId), + }) + if getRawSubnetErr != nil { + cblogger.Error(getRawSubnetErr) + LoggingError(hiscallInfo, getRawSubnetErr) + return irs.NodeGroupInfo{}, getRawSubnetErr + } + subnetIID.NameId = *rawSubnet.Name + subnetIID.SystemId = *rawSubnet.ID + } + } + + addNodeGroupResponse, _, addNodeGroupErr := ic.ClusterService.VpcCreateWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcCreateWorkerPoolOptions{ + Cluster: core.StringPtr(irsCluster.IId.SystemId), + Flavor: core.StringPtr(nodeGroupReqInfo.VMSpecName), + Isolation: core.StringPtr("public"), + Name: core.StringPtr(nodeGroupReqInfo.IId.NameId), + VpcID: core.StringPtr(irsCluster.Network.VpcIID.SystemId), + WorkerCount: core.Int64Ptr(int64(nodeGroupReqInfo.DesiredNodeSize)), + Zones: []kubernetesserviceapiv1.Zone{{ + ID: core.StringPtr(ic.Region.Zone), + SubnetID: core.StringPtr(subnetIID.SystemId), + }}, + Authorization: core.StringPtr(ic.CredentialInfo.AuthToken), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if addNodeGroupErr != nil { + cblogger.Error(addNodeGroupErr) + LoggingError(hiscallInfo, addNodeGroupErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", addNodeGroupErr)) + } + + newNodeGroup, _, getNewNodeGroupErr := ic.ClusterService.VpcGetWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolOptions{ + Cluster: core.StringPtr(irsCluster.IId.SystemId), + Workerpool: addNodeGroupResponse.WorkerPoolID, + XRegion: core.StringPtr(ic.Region.Region), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if getNewNodeGroupErr != nil { + cblogger.Error(getNewNodeGroupErr) + LoggingError(hiscallInfo, getNewNodeGroupErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getNewNodeGroupErr)) + } + + // Apply Node Group autosacler options + irsCluster.NodeGroupList = append(irsCluster.NodeGroupList, nodeGroupReqInfo) + applyAutoScalerOptionErr := ic.applyAutoScalerOptions(irsCluster, irsCluster.IId.SystemId, resourceGroupId) + if applyAutoScalerOptionErr != nil { + cblogger.Error(applyAutoScalerOptionErr) + LoggingError(hiscallInfo, applyAutoScalerOptionErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", applyAutoScalerOptionErr)) + } + + // Get Workers in pool + getWorkersResult, _, getWorkersErr := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ + Cluster: core.StringPtr(irsCluster.IId.SystemId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowDeleted: core.StringPtr("false"), + Pool: newNodeGroup.ID, + }) + if getWorkersErr != nil { + cblogger.Error(getWorkersErr) + LoggingError(hiscallInfo, getWorkersErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getWorkersErr)) + } + + var nodesIID []irs.IID + for _, worker := range getWorkersResult { + nodesIID = append(nodesIID, irs.IID{ + NameId: RetrieveUnableErr, + SystemId: *worker.ID, + }) + } + + LoggingInfo(hiscallInfo, start) + + return irs.NodeGroupInfo{ + IId: irs.IID{ + NameId: *newNodeGroup.PoolName, + SystemId: *newNodeGroup.ID, + }, + ImageIID: irs.IID{ + NameId: RetrieveUnableErr, + SystemId: RetrieveUnableErr, + }, + VMSpecName: *newNodeGroup.Flavor, + RootDiskType: RetrieveUnableErr, + RootDiskSize: RetrieveUnableErr, + KeyPairIID: irs.IID{ + NameId: RetrieveUnableErr, + SystemId: RetrieveUnableErr, + }, + OnAutoScaling: false, + DesiredNodeSize: -1, + MinNodeSize: -1, + MaxNodeSize: -1, + Status: ic.getNodeGroupStatusFromString(*newNodeGroup.Lifecycle.DesiredState), + Nodes: nodesIID, + KeyValueList: nil, + }, nil +} + +func (ic *IbmClusterHandler) SetNodeGroupAutoScaling(clusterIID irs.IID, nodeGroupIID irs.IID, on bool) (bool, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "SetNodeGroupAutoScaling()") + start := call.Start() + + // validation + if clusterIID.SystemId == "" && clusterIID.NameId == "" { + return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Cluster IID") + } + if nodeGroupIID.SystemId == "" && nodeGroupIID.NameId == "" { + return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Node Group IID") + } + + // get resource group id + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + cblogger.Error(getResourceGroupErr) + LoggingError(hiscallInfo, getResourceGroupErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getResourceGroupErr)) + } + + irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) + if getIrsClusterErr != nil { + cblogger.Error(getIrsClusterErr) + LoggingError(hiscallInfo, getIrsClusterErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getIrsClusterErr)) + } + if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting || irsCluster.Status == irs.ClusterUpdating { + clusterStatusErr := errors.New(fmt.Sprintf("Cannot Set Node Group AutoScaling at %s status", irsCluster.Status)) + cblogger.Error(clusterStatusErr) + LoggingError(hiscallInfo, clusterStatusErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group AutoScaling. err = %s", clusterStatusErr)) + } + + nodeGroups, _, getNodeGroupsErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ + Cluster: core.StringPtr(irsCluster.IId.SystemId), + XRegion: core.StringPtr(ic.Region.Region), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if getNodeGroupsErr != nil { + cblogger.Error(getNodeGroupsErr) + LoggingError(hiscallInfo, getNodeGroupsErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getNodeGroupsErr)) + } + + var targetNodeGroup *kubernetesserviceapiv1.GetWorkerPoolsDetailResponse + for _, nodeGroup := range *nodeGroups { + if nodeGroup.Id == nodeGroupIID.SystemId || nodeGroup.PoolName == nodeGroupIID.NameId { + targetNodeGroup = &nodeGroup + break + } + } + if targetNodeGroup == nil { + nodeGroupNotExistErr := errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = cannot find node group: %s", nodeGroupIID)) + cblogger.Error(nodeGroupNotExistErr) + LoggingError(hiscallInfo, nodeGroupNotExistErr) + return false, nodeGroupNotExistErr + } + + nodeGroupName := targetNodeGroup.PoolName + + kubeConfigStr, getKubeConfigErr := ic.getKubeConfig(irsCluster.IId.SystemId, resourceGroupId) + if getKubeConfigErr != nil { + cblogger.Error(getKubeConfigErr) + LoggingError(hiscallInfo, getKubeConfigErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getKubeConfigErr)) + } + + var newNodeGroupInfo []irs.NodeGroupInfo + configMap, getConfigMapErr := ic.getAutoScalerConfigMap(kubeConfigStr) + if getConfigMapErr != nil { + cblogger.Error(getConfigMapErr) + LoggingError(hiscallInfo, getConfigMapErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", getConfigMapErr)) + } + if configMap == nil { + configMapNotExistErr := errors.New("Failed to Set Node Group Auto Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") + cblogger.Error(configMapNotExistErr) + LoggingError(hiscallInfo, configMapNotExistErr) + return false, configMapNotExistErr + } else { + jsonProperty, exists := configMap.Data[AutoscalerConfigMapOptionProperty] + if !exists { + propertyNotExistErr := errors.New("Failed to Set Node Group Auto Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") + cblogger.Error(propertyNotExistErr) + LoggingError(hiscallInfo, propertyNotExistErr) + return false, propertyNotExistErr + } + + var workerPoolAutoscalerConfigs []kubernetesserviceapiv1.WorkerPoolAutoscalerConfig + unmarshalErr := json.Unmarshal([]byte(jsonProperty), &workerPoolAutoscalerConfigs) + if unmarshalErr != nil { + cblogger.Error(unmarshalErr) + LoggingError(hiscallInfo, unmarshalErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", unmarshalErr)) + } + + isIncluded := false + for i, config := range workerPoolAutoscalerConfigs { + if config.Name == nodeGroupName { + isIncluded = true + workerPoolAutoscalerConfigs[i].Enabled = on + } + newNodeGroupInfo = append(newNodeGroupInfo, irs.NodeGroupInfo{ + IId: irs.IID{NameId: workerPoolAutoscalerConfigs[i].Name}, + OnAutoScaling: workerPoolAutoscalerConfigs[i].Enabled, + MinNodeSize: workerPoolAutoscalerConfigs[i].MinSize, + MaxNodeSize: workerPoolAutoscalerConfigs[i].MaxSize, + }) + } + + if !isIncluded { + autoScalingSettingNotExistsErr := errors.New("Failed to Set Node Group Auto Scaling. err = Cannot find Node Group Auto Scaling Setting in Auto Scaler Config Map, Please try change Node Group scaling") + cblogger.Error(autoScalingSettingNotExistsErr) + LoggingError(hiscallInfo, autoScalingSettingNotExistsErr) + return false, autoScalingSettingNotExistsErr + } + } + + updateConfigMapErr := ic.updateAutoScalerConfigMap(kubeConfigStr, newNodeGroupInfo) + if updateConfigMapErr != nil { + cblogger.Error(updateConfigMapErr) + LoggingError(hiscallInfo, updateConfigMapErr) + return false, errors.New(fmt.Sprintf("Failed to Set Node Group Auto Scaling. err = %s", updateConfigMapErr)) + } + + LoggingInfo(hiscallInfo, start) + + return true, nil +} + +func (ic *IbmClusterHandler) ChangeNodeGroupScaling(clusterIID irs.IID, nodeGroupIID irs.IID, DesiredNodeSize int, MinNodeSize int, MaxNodeSize int) (irs.NodeGroupInfo, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "ChangeNodeGroupScaling()") + start := call.Start() + + // validation + validateErr := ic.validateAtChangeNodeGroupScaling(clusterIID, nodeGroupIID, MinNodeSize, MaxNodeSize) + if validateErr != nil { + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", validateErr)) + } + + // get resource group id + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + cblogger.Error(getResourceGroupErr) + LoggingError(hiscallInfo, getResourceGroupErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getResourceGroupErr)) + } + + irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) + if getIrsClusterErr != nil { + cblogger.Error(getIrsClusterErr) + LoggingError(hiscallInfo, getIrsClusterErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getIrsClusterErr)) + } + if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting || irsCluster.Status == irs.ClusterUpdating { + clusterStatusErr := errors.New(fmt.Sprintf("Cannot Change Node Group Scaling at %s status", irsCluster.Status)) + cblogger.Error(clusterStatusErr) + LoggingError(hiscallInfo, clusterStatusErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", clusterStatusErr)) + } + + nodeGroups, _, getNodeGroupsErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ + Cluster: core.StringPtr(irsCluster.IId.SystemId), + XRegion: core.StringPtr(ic.Region.Region), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if getNodeGroupsErr != nil { + cblogger.Error(getNodeGroupsErr) + LoggingError(hiscallInfo, getNodeGroupsErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getNodeGroupsErr)) + } + + var targetNodeGroup *kubernetesserviceapiv1.GetWorkerPoolsDetailResponse + for _, nodeGroup := range *nodeGroups { + if nodeGroup.Id == nodeGroupIID.SystemId || nodeGroup.PoolName == nodeGroupIID.NameId { + targetNodeGroup = &nodeGroup + break + } + } + if targetNodeGroup == nil { + nodeGroupNotExistErr := errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = cannot find node group: %s", nodeGroupIID)) + cblogger.Error(nodeGroupNotExistErr) + LoggingError(hiscallInfo, nodeGroupNotExistErr) + return irs.NodeGroupInfo{}, nodeGroupNotExistErr + } + + nodeGroupName := targetNodeGroup.PoolName + + kubeConfigStr, getKubeConfigErr := ic.getKubeConfig(irsCluster.IId.SystemId, resourceGroupId) + if getKubeConfigErr != nil { + cblogger.Error(getKubeConfigErr) + LoggingError(hiscallInfo, getKubeConfigErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getKubeConfigErr)) + } + + var newNodeGroupInfo []irs.NodeGroupInfo + var changedNodeGroupIndex int + configMap, getConfigMapErr := ic.getAutoScalerConfigMap(kubeConfigStr) + if getConfigMapErr != nil { + cblogger.Error(getConfigMapErr) + LoggingError(hiscallInfo, getConfigMapErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", getConfigMapErr)) + } + if configMap == nil { + configMapNotExistErr := errors.New("Failed to Change Node Group Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") + cblogger.Error(configMapNotExistErr) + LoggingError(hiscallInfo, configMapNotExistErr) + return irs.NodeGroupInfo{}, configMapNotExistErr + } else { + jsonProperty, exists := configMap.Data[AutoscalerConfigMapOptionProperty] + if !exists { + propertyNotExistErr := errors.New("Failed to Change Node Group Scaling. err = Cannot find Auto Scaler Config Map, Please try after autoscaler addon is deployed") + cblogger.Error(propertyNotExistErr) + LoggingError(hiscallInfo, propertyNotExistErr) + return irs.NodeGroupInfo{}, propertyNotExistErr + } + + var workerPoolAutoscalerConfigs []kubernetesserviceapiv1.WorkerPoolAutoscalerConfig + unmarshalErr := json.Unmarshal([]byte(jsonProperty), &workerPoolAutoscalerConfigs) + if unmarshalErr != nil { + cblogger.Error(unmarshalErr) + LoggingError(hiscallInfo, unmarshalErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", unmarshalErr)) + } + + isIncluded := false + for i, config := range workerPoolAutoscalerConfigs { + if config.Name == nodeGroupName { + isIncluded = true + changedNodeGroupIndex = i + workerPoolAutoscalerConfigs[i].MinSize = MinNodeSize + workerPoolAutoscalerConfigs[i].MaxSize = MaxNodeSize + } + newNodeGroupInfo = append(newNodeGroupInfo, irs.NodeGroupInfo{ + IId: irs.IID{NameId: workerPoolAutoscalerConfigs[i].Name}, + OnAutoScaling: workerPoolAutoscalerConfigs[i].Enabled, + MinNodeSize: workerPoolAutoscalerConfigs[i].MinSize, + MaxNodeSize: workerPoolAutoscalerConfigs[i].MaxSize, + }) + } + + if !isIncluded { + newNodeGroupInfo = append(newNodeGroupInfo, irs.NodeGroupInfo{ + IId: irs.IID{NameId: nodeGroupName}, + OnAutoScaling: false, + MinNodeSize: MinNodeSize, + MaxNodeSize: MaxNodeSize, + }) + changedNodeGroupIndex = len(newNodeGroupInfo) - 1 + } + } + + updateConfigMapErr := ic.updateAutoScalerConfigMap(kubeConfigStr, newNodeGroupInfo) + if updateConfigMapErr != nil { + cblogger.Error(updateConfigMapErr) + LoggingError(hiscallInfo, updateConfigMapErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Change Node Group Scaling. err = %s", updateConfigMapErr)) + } + + // Get Workers in pool + getWorkersResult, _, getWorkersErr := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ + Cluster: core.StringPtr(irsCluster.IId.SystemId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowDeleted: core.StringPtr("false"), + Pool: core.StringPtr(targetNodeGroup.Id), + }) + if getWorkersErr != nil { + cblogger.Error(getWorkersErr) + LoggingError(hiscallInfo, getWorkersErr) + return irs.NodeGroupInfo{}, errors.New(fmt.Sprintf("Failed to Add Node Group. err = %s", getWorkersErr)) + } + + var nodesIID []irs.IID + for _, worker := range getWorkersResult { + nodesIID = append(nodesIID, irs.IID{ + NameId: RetrieveUnableErr, + SystemId: *worker.ID, + }) + } + + LoggingInfo(hiscallInfo, start) + + return irs.NodeGroupInfo{ + IId: irs.IID{ + NameId: targetNodeGroup.PoolName, + SystemId: targetNodeGroup.Id, + }, + ImageIID: irs.IID{ + NameId: RetrieveUnableErr, + SystemId: RetrieveUnableErr, + }, + VMSpecName: targetNodeGroup.Flavor, + RootDiskType: RetrieveUnableErr, + RootDiskSize: RetrieveUnableErr, + KeyPairIID: irs.IID{ + NameId: RetrieveUnableErr, + SystemId: RetrieveUnableErr, + }, + OnAutoScaling: newNodeGroupInfo[changedNodeGroupIndex].OnAutoScaling, + DesiredNodeSize: -1, + MinNodeSize: newNodeGroupInfo[changedNodeGroupIndex].MinNodeSize, + MaxNodeSize: newNodeGroupInfo[changedNodeGroupIndex].MaxNodeSize, + Status: ic.getNodeGroupStatusFromString(targetNodeGroup.Lifecycle.DesiredState), + Nodes: nodesIID, + KeyValueList: nil, + }, nil +} + +func (ic *IbmClusterHandler) RemoveNodeGroup(clusterIID irs.IID, nodeGroupIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "RemoveNodeGroup()") + start := call.Start() + + // validation + if clusterIID.SystemId == "" && clusterIID.NameId == "" { + return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Cluster IID") + } + if nodeGroupIID.SystemId == "" && nodeGroupIID.NameId == "" { + return false, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Node Group IID") + } + + // get resource group id + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + cblogger.Error(getResourceGroupErr) + LoggingError(hiscallInfo, getResourceGroupErr) + return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", getResourceGroupErr)) + } + + irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) + if getIrsClusterErr != nil { + cblogger.Error(getIrsClusterErr) + LoggingError(hiscallInfo, getIrsClusterErr) + return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", getIrsClusterErr)) + } + if irsCluster.Status == irs.ClusterCreating || irsCluster.Status == irs.ClusterDeleting { + clusterStatusErr := errors.New(fmt.Sprintf("Cannot Remove Node Group at %s status", irsCluster.Status)) + cblogger.Error(clusterStatusErr) + LoggingError(hiscallInfo, clusterStatusErr) + return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", clusterStatusErr)) + } + + nodeGroups, _, getNodeGroupsErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ + Cluster: core.StringPtr(irsCluster.IId.SystemId), + XRegion: core.StringPtr(ic.Region.Region), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if getNodeGroupsErr != nil { + cblogger.Error(getNodeGroupsErr) + LoggingError(hiscallInfo, getNodeGroupsErr) + return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", getNodeGroupsErr)) + } + + var targetNodeGroup *kubernetesserviceapiv1.GetWorkerPoolsDetailResponse + for _, nodeGroup := range *nodeGroups { + if nodeGroup.Id == nodeGroupIID.SystemId || nodeGroup.PoolName == nodeGroupIID.NameId { + targetNodeGroup = &nodeGroup + break + } + } + + _, removeErr := ic.ClusterService.RemoveWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.RemoveWorkerPoolOptions{ + IdOrName: core.StringPtr(irsCluster.IId.SystemId), + PoolidOrName: core.StringPtr(targetNodeGroup.Id), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if removeErr != nil { + cblogger.Error(removeErr) + LoggingError(hiscallInfo, removeErr) + return false, errors.New(fmt.Sprintf("Failed to Remove Node Group. err = %s", removeErr)) + } + + LoggingInfo(hiscallInfo, start) + + return true, nil +} + +func (ic *IbmClusterHandler) UpgradeCluster(clusterIID irs.IID, newVersion string) (irs.ClusterInfo, error) { + hiscallInfo := GetCallLogScheme(ic.Region, call.CLUSTER, clusterIID.NameId, "UpgradeCluster()") + start := call.Start() + + // validation + if clusterIID.SystemId == "" && clusterIID.NameId == "" { + return irs.ClusterInfo{}, errors.New("Failed to Set Node Group Auto Scaling. err = Invalid Cluster IID") + } + if newVersion == "" { + return irs.ClusterInfo{}, errors.New("Failed to Set Node Group Auto Scaling. err = New Version is required") + } + + // get resource group id + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + cblogger.Error(getResourceGroupErr) + LoggingError(hiscallInfo, getResourceGroupErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getResourceGroupErr)) + } + + fullClusterIID, getClusterIIDErr := ic.getClusterIID(clusterIID) + if getClusterIIDErr != nil { + cblogger.Error(getClusterIIDErr) + LoggingError(hiscallInfo, getClusterIIDErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getClusterIIDErr)) + } + + prevIrsClsuter, getIrsClusterErr := ic.GetCluster(fullClusterIID) + if getIrsClusterErr != nil { + cblogger.Error(getIrsClusterErr) + LoggingError(hiscallInfo, getIrsClusterErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getIrsClusterErr)) + } + if prevIrsClsuter.Status != irs.ClusterActive { + clusterStatusErr := errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = Cannot upgrade cluster in %s status", prevIrsClsuter.Status)) + cblogger.Error(clusterStatusErr) + LoggingError(hiscallInfo, clusterStatusErr) + return irs.ClusterInfo{}, clusterStatusErr + } + + rawCluster, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(fullClusterIID.SystemId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("true"), + }) + if getClusterErr != nil { + cblogger.Error(getClusterErr) + LoggingError(hiscallInfo, getClusterErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getClusterErr)) + } + targetCluster := (*rawCluster)[0] + + // uninstall autoscaler addon + uninstallErr := ic.uninstallAutoScalerAddon(fullClusterIID.SystemId, targetCluster.Crn, resourceGroupId) + if uninstallErr != nil { + cblogger.Error(uninstallErr) + LoggingError(hiscallInfo, uninstallErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", uninstallErr)) + } + + // upgrade master + _, updateErr := ic.ClusterService.V2UpdateMasterWithContext(ic.Ctx, &kubernetesserviceapiv1.V2UpdateMasterOptions{ + Cluster: core.StringPtr(fullClusterIID.SystemId), + Force: core.BoolPtr(false), + Version: core.StringPtr(newVersion), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if updateErr != nil { + cblogger.Error(updateErr) + LoggingError(hiscallInfo, updateErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", updateErr)) + } + ic.manageStatusTag(targetCluster.Crn, MasterUpgradeStatus, WAITING) + + // upgrade workers + go func() { + // wait until update master and uninstall autoscaler addon is done + cnt := 0 + for cnt < UpgradeMasterRetry { + // get autoscaler tags + rawCluster, _, getClusterErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(fullClusterIID.SystemId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("true"), + }) + if getClusterErr != nil { + cnt++ + time.Sleep(time.Minute) + continue + } + targetCluster := (*rawCluster)[0] + tags, _, getTagsErr := ic.TaggingService.ListTagsWithContext(ic.Ctx, &globaltaggingv1.ListTagsOptions{ + TagType: core.StringPtr("user"), + AttachedTo: core.StringPtr(targetCluster.Crn), + }) + if getTagsErr != nil { + cnt++ + time.Sleep(time.Minute) + continue + } + + // check if master upgrade is done + isMasterUpgrading := true + isMasterUpgradeIndicated := strings.Contains(targetCluster.MasterKubeVersion, "-->") + for _, tag := range (*tags).Items { + if isTagStatusOf(*tag.Name, MasterUpgradeStatus) { + if compareTag(*tag.Name, MasterUpgradeStatus, WAITING) { + if isMasterUpgradeIndicated { + ic.manageStatusTag(targetCluster.Crn, MasterUpgradeStatus, UPGRADING) + break + } + } + if compareTag(*tag.Name, MasterUpgradeStatus, UPGRADING) { + if !isMasterUpgradeIndicated { + ic.manageStatusTag(targetCluster.Crn, MasterUpgradeStatus, "") + isMasterUpgrading = false + } + break + } + } + } + if isMasterUpgrading { + cnt++ + time.Sleep(time.Minute) + continue + } + + // upgrade workers + getWorkersResult, _, _ := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ + Cluster: core.StringPtr(fullClusterIID.SystemId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowDeleted: core.StringPtr("false"), + }) + for _, worker := range getWorkersResult { + ic.ClusterService.VpcReplaceWorker(&kubernetesserviceapiv1.VpcReplaceWorkerOptions{ + Cluster: core.StringPtr(fullClusterIID.SystemId), + Update: core.BoolPtr(true), + WorkerID: worker.ID, + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + } + break + } + }() + + // reinstall new autoscaler + prevIrsClsuter.Version = newVersion + autoScalerErr := ic.installAutoScalerAddon(prevIrsClsuter, fullClusterIID.SystemId, targetCluster.Crn, resourceGroupId, true) + if autoScalerErr != nil { + cblogger.Error(autoScalerErr) + LoggingError(hiscallInfo, autoScalerErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", autoScalerErr)) + } + + // get cluster info + irsCluster, getIrsClusterErr := ic.GetCluster(clusterIID) + if getIrsClusterErr != nil { + cblogger.Error(getIrsClusterErr) + LoggingError(hiscallInfo, getIrsClusterErr) + return irs.ClusterInfo{}, errors.New(fmt.Sprintf("Failed to Upgrade Cluster. err = %s", getIrsClusterErr)) + } + + LoggingInfo(hiscallInfo, start) + + return irsCluster, nil +} + +func (ic *IbmClusterHandler) applyAutoScalerOptions(clusterReqInfo irs.ClusterInfo, clusterId string, resourceGroupId string) error { + kubeConfigStr, getKubeConfigErr := ic.getKubeConfig(clusterId, resourceGroupId) + if getKubeConfigErr != nil { + return getKubeConfigErr + } + patchConfigMapErr := ic.updateAutoScalerConfigMap(kubeConfigStr, clusterReqInfo.NodeGroupList) + if patchConfigMapErr != nil { + return patchConfigMapErr + } + + return nil +} + +func (ic *IbmClusterHandler) manageStatusTag(crn string, tag string, status string) { + var deleteTargets *[]string + switch tag { + case AutoScalerStatus: + deleteTargets = &autoSaclerStates + case SecurityGroupStatus: + deleteTargets = &securityGroupStates + case MasterUpgradeStatus: + deleteTargets = &masterUpgradeStates + default: + } + + if deleteTargets != nil && len(*deleteTargets) != 0 { + ic.TaggingService.DetachTag(&globaltaggingv1.DetachTagOptions{ + Resources: []globaltaggingv1.Resource{{ + ResourceID: core.StringPtr(crn), + }}, + TagNames: *deleteTargets, + TagType: core.StringPtr("user"), + }) + } + + if status != "" { + ic.TaggingService.AttachTag(&globaltaggingv1.AttachTagOptions{ + Resources: []globaltaggingv1.Resource{{ + ResourceID: core.StringPtr(crn), + }}, + TagName: core.StringPtr(fmt.Sprintf("%s%s", tag, status)), + TagType: core.StringPtr("user"), + }) + } +} + +func (ic *IbmClusterHandler) checkIfClusterIsSupported(versionRange string, clusterK8sVersion string) bool { + clusterVersion, err := version.NewVersion(clusterK8sVersion) + if err != nil { + return false + } + + minVersion, err := version.NewVersion(strings.Split(strings.Split(versionRange, " ")[0], ">=")[1]) + if err != nil { + return false + } + + maxVersion, err := version.NewVersion(strings.Split(strings.Split(versionRange, " ")[1], "<")[1]) + if err != nil { + return false + } + + return clusterVersion.GreaterThanOrEqual(minVersion) && clusterVersion.LessThan(maxVersion) +} + +func (ic *IbmClusterHandler) createRemainingWorkerPools(clusterReqInfo irs.ClusterInfo, vpcInfo irs.VPCInfo, subnetInfo irs.SubnetInfo, rawCluster kubernetesserviceapiv1.GetClusterDetailResponse, resourceGroupId string) { + for i := 1; i < len(clusterReqInfo.NodeGroupList); i++ { + workerPool := ic.getWorkerPoolFromNodeGroupInfo(clusterReqInfo.NodeGroupList[i], vpcInfo.IId.SystemId, subnetInfo.IId.SystemId) + _, _, createWorkerPoolErr := ic.ClusterService.VpcCreateWorkerPoolWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcCreateWorkerPoolOptions{ + Cluster: core.StringPtr(rawCluster.Id), + Flavor: workerPool.Flavor, + Isolation: workerPool.Isolation, + Name: workerPool.Name, + VpcID: workerPool.VpcID, + WorkerCount: workerPool.WorkerCount, + Zones: []kubernetesserviceapiv1.Zone{{ + ID: core.StringPtr(ic.Region.Zone), + SubnetID: core.StringPtr(subnetInfo.IId.SystemId), + }}, + Authorization: core.StringPtr(ic.CredentialInfo.AuthToken), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + Headers: nil, + }) + if createWorkerPoolErr != nil { + cblogger.Error(createWorkerPoolErr) + ic.DeleteCluster(clusterReqInfo.IId) + } + } +} + +func (ic *IbmClusterHandler) getAddonInfo(clusterId string, resourceGroupId string) (irs.AddonsInfo, error) { + rawClusterAddons, _, getClusterAddonsErr := ic.ClusterService.GetClusterAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.GetClusterAddonsOptions{ + IdOrName: core.StringPtr(clusterId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if getClusterAddonsErr != nil { + return irs.AddonsInfo{}, getClusterAddonsErr + } + var keyValues []irs.KeyValue + for _, clusterAddon := range rawClusterAddons { + addonJsonValue, marshalErr := json.Marshal(clusterAddon) + if marshalErr != nil { + cblogger.Error(marshalErr) + } + keyValues = append(keyValues, irs.KeyValue{ + Key: *clusterAddon.Name, + Value: string(addonJsonValue), + }) + } + clusterAddons := irs.AddonsInfo{KeyValueList: keyValues} + return clusterAddons, nil +} + +func (ic *IbmClusterHandler) getAutoScalerConfigMap(kubeConfigStr string) (*v1.ConfigMap, error) { + k8sClient, getK8sClientErr := ic.ClusterService.GetKubernetesClient(kubeConfigStr) + if getK8sClientErr != nil { + return nil, getK8sClientErr + } + + configMap, getConfigMapErr := k8sClient.CoreV1().ConfigMaps(ConfigMapNamespace).Get(context.Background(), AutoscalerConfigMap, metav1.GetOptions{}) + if getConfigMapErr != nil { + return nil, getConfigMapErr + } + + return configMap, nil +} + +func (ic *IbmClusterHandler) getClusterFinalStatus(clusterStatus irs.ClusterStatus, autoSaclerStatus string, securityGroupStatus string) irs.ClusterStatus { + if compareTag(autoSaclerStatus, AutoScalerStatus, FAILED) || compareTag(securityGroupStatus, SecurityGroupStatus, FAILED) { + return irs.ClusterInactive + } + if compareTag(autoSaclerStatus, AutoScalerStatus, WAITING) || + compareTag(autoSaclerStatus, AutoScalerStatus, DEPLOYING) || + compareTag(securityGroupStatus, SecurityGroupStatus, INITIALIZING) { + return irs.ClusterCreating + } + if compareTag(autoSaclerStatus, AutoScalerStatus, UPGRADE_DEPLOYING) { + return irs.ClusterUpdating + } + return clusterStatus +} + +func (ic *IbmClusterHandler) getClusterIID(clusterIID irs.IID) (irs.IID, error) { + if clusterIID.NameId == "" && clusterIID.SystemId == "" { + return irs.IID{}, errors.New("Failed to Get Cluster IID") + } + + resourceGroupId, getResourceGroupIdErr := ic.getDefaultResourceGroupId() + if getResourceGroupIdErr != nil { + return irs.IID{}, errors.New(fmt.Sprintf("Failed to Get Cluster IID. err = %s", getResourceGroupIdErr)) + } + + var cluster string + if clusterIID.SystemId != "" { + cluster = clusterIID.SystemId + } else { + cluster = clusterIID.NameId + } + rawClusters, _, getClustersErr := ic.ClusterService.VpcGetClusterWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetClusterOptions{ + Cluster: core.StringPtr(cluster), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowResources: core.StringPtr("false"), + }) + if getClustersErr != nil { + return irs.IID{}, errors.New(fmt.Sprintf("Failed to Get Cluster IID. err = %s", getClustersErr)) + } + + return irs.IID{ + NameId: (*rawClusters)[0].Name, + SystemId: (*rawClusters)[0].Id, + }, nil +} + +func (ic *IbmClusterHandler) getClusterStatusFromString(clusterStatus string) irs.ClusterStatus { + switch strings.ToLower(clusterStatus) { + case "requested", "deploying", "pending": + return irs.ClusterCreating + case "normal": + return irs.ClusterActive + case "updating": + return irs.ClusterUpdating + case "aborted", "deleting": + return irs.ClusterDeleting + default: + return irs.ClusterInactive + } +} + +func (ic *IbmClusterHandler) getDefaultResourceGroupId() (string, error) { + if defaultResourceGroupId == "" { + var err error + + // create resource controller + resourceManagerManagerOptions := &resourcemanagerv2.ResourceManagerV2Options{ + Authenticator: &core.IamAuthenticator{ + ApiKey: ic.CredentialInfo.ApiKey, + }, + } + resourceManagerService, err := resourcemanagerv2.NewResourceManagerV2UsingExternalConfig(resourceManagerManagerOptions) + if err != nil { + return "", err + } + + resourceGroups, _, listResourceGroupsErr := resourceManagerService.ListResourceGroups(&resourcemanagerv2.ListResourceGroupsOptions{ + Default: core.BoolPtr(true), + }) + if listResourceGroupsErr != nil { + return "", listResourceGroupsErr + } + + for _, resourceGroup := range resourceGroups.Resources { + if strings.EqualFold(*resourceGroup.Name, DefaultResourceGroup) { + defaultResourceGroupId = *resourceGroup.ID + return defaultResourceGroupId, nil + } + } + + return "", errors.New("failed to get default resource group") + } + + return defaultResourceGroupId, nil +} + +func (ic *IbmClusterHandler) getKubeConfig(clusterId string, resourceGroupId string) (string, error) { + kubeConfig, getKubeConfigErr := ic.ClusterService.GetKubeconfigWithContext(ic.Ctx, &kubernetesserviceapiv1.GetKubeconfigOptions{ + Authorization: core.StringPtr(ic.CredentialInfo.ApiKey), + Cluster: core.StringPtr(clusterId), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + Format: core.StringPtr("yaml"), + Admin: core.BoolPtr(true), + Network: core.BoolPtr(false), + }) + if getKubeConfigErr != nil { + return "", getKubeConfigErr + } else { + resultStr, ok := kubeConfig.Result.([]byte) + if !ok { + return "", errors.New("Failed to Get Kube Config String") + } else { + return string(resultStr), nil + } + } +} + +func (ic *IbmClusterHandler) getNodeGroupStatusFromString(nodeGroupStatus string) irs.NodeGroupStatus { + // IBM Node Group does not have Creating or Updating status + // While creating a Node Group, its status is indicated as Active + // While updating Node Group such as autoscale configuration, its status is indicated as Active + switch strings.ToLower(nodeGroupStatus) { + case "active": + return irs.NodeGroupActive + case "deleting": + return irs.NodeGroupDeleting + default: + return irs.NodeGroupInactive + } +} + +func (ic *IbmClusterHandler) getWorkerPoolFromNodeGroupInfo(nodeGroupInfo irs.NodeGroupInfo, vpcId string, subnetId string) kubernetesserviceapiv1.VPCCreateClusterWorkerPool { + return kubernetesserviceapiv1.VPCCreateClusterWorkerPool{ + Name: core.StringPtr(nodeGroupInfo.IId.NameId), + Flavor: core.StringPtr(nodeGroupInfo.VMSpecName), + Isolation: core.StringPtr("public"), + VpcID: core.StringPtr(vpcId), + WorkerCount: core.Int64Ptr(int64(nodeGroupInfo.DesiredNodeSize)), + Zones: []kubernetesserviceapiv1.VPCCreateClusterWorkerPoolZone{{ + ID: core.StringPtr(ic.Region.Zone), + SubnetID: core.StringPtr(subnetId), + }}, + } +} + +func (ic *IbmClusterHandler) initSecurityGroup(clusterReqInfo irs.ClusterInfo, clusterId string, clusterCrn string) { + sgHandler := IbmSecurityHandler{ + CredentialInfo: ic.CredentialInfo, + Region: ic.Region, + VpcService: ic.VpcService, + Ctx: ic.Ctx, + } + + ic.manageStatusTag(clusterCrn, SecurityGroupStatus, INITIALIZING) + go func() { + cnt := 0 + for cnt < InitSecurityGroupRetry { + defaultSgInfo, getDSIErr := sgHandler.GetSecurity(irs.IID{NameId: fmt.Sprintf("kube-%s", clusterId)}) + if getDSIErr != nil { + time.Sleep(time.Minute) + cnt++ + continue + } + + initSuccess := true + for _, sgIID := range clusterReqInfo.Network.SecurityGroupIIDs { + sgInfo, getSgErr := sgHandler.GetSecurity(sgIID) + if getSgErr != nil { + initSuccess = false + ic.manageStatusTag(clusterCrn, SecurityGroupStatus, FAILED) + _, _ = ic.DeleteCluster(clusterReqInfo.IId) + break + } + + var updateRules []irs.SecurityRuleInfo + for _, newRule := range *sgInfo.SecurityRules { + existCheck := false + for _, baseRule := range *defaultSgInfo.SecurityRules { + if equalsRule(newRule, baseRule) { + existCheck = true + break + } + } + if existCheck { + continue + } + updateRules = append(updateRules, newRule) + } + _, sgUpdateErr := sgHandler.AddRules(defaultSgInfo.IId, &updateRules) + if sgUpdateErr != nil { + initSuccess = false + ic.manageStatusTag(clusterCrn, SecurityGroupStatus, FAILED) + _, _ = ic.DeleteCluster(clusterReqInfo.IId) + break + } + } + if initSuccess { + ic.manageStatusTag(clusterCrn, SecurityGroupStatus, INITIALIZED) + } + break + } + }() + + return +} + +func (ic *IbmClusterHandler) installAutoScalerAddon(clusterReqInfo irs.ClusterInfo, clusterId string, clusterCrn string, resourceGroupId string, isUpdating bool) error { + // check exists + addonsInfo, _ := ic.getAddonInfo(clusterId, resourceGroupId) + for _, addon := range addonsInfo.KeyValueList { + if addon.Key == AutoscalerAddon && strings.Contains(addon.Value, "\"healthState\":\"normal\"") { + ic.manageStatusTag(clusterCrn, AutoScalerStatus, ACTIVE) + return nil + } + } + + // start install addon + availableAddons, _, getAvailAddonsErr := ic.ClusterService.GetAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.GetAddonsOptions{}) + if getAvailAddonsErr != nil { + return errors.New(fmt.Sprintf("Failed to Create Cluster. err = %s", getAvailAddonsErr)) + } + var availableAutoScalerAddons []kubernetesserviceapiv1.AddonCommon + for _, availableAddon := range availableAddons { + if *availableAddon.Name == AutoscalerAddon && + ic.checkIfClusterIsSupported(*availableAddon.SupportedKubeRange, clusterReqInfo.Version) { + availableAutoScalerAddons = append(availableAutoScalerAddons, availableAddon) + } + } + if len(availableAutoScalerAddons) < 1 { + return errors.New(fmt.Sprintf("Failed to install autoscaler addon. err = No available autoscaler addon for this Kubernetes version: %s", clusterReqInfo.Version)) + } + + addons := []kubernetesserviceapiv1.ClusterAddon{{ + Name: availableAutoScalerAddons[0].Name, + Version: availableAutoScalerAddons[0].Version, + }} + + go func() { + cnt := 0 + enableSuccess := false + ic.manageStatusTag(clusterCrn, AutoScalerStatus, WAITING) + for cnt < EnableAutoScalerRetry { + _, enableAddonDetail, enableAddonErr := ic.ClusterService.ManageClusterAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.ManageClusterAddonsOptions{ + IdOrName: core.StringPtr(clusterId), + Addons: addons, + Enable: core.BoolPtr(true), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if enableAddonErr != nil { + resultMap, toMapOk := enableAddonDetail.GetResultAsMap() + if toMapOk { + descriptionStr, toStrOk := resultMap["description"].(string) + if toStrOk { + if !strings.Contains(descriptionStr, "The cluster is not fully deployed, please wait a couple minutes before enabling the add-on.") { + break + } + } + } + } else { + enableSuccess = true + break + } + time.Sleep(time.Minute) + cnt++ + } + if !enableSuccess { + ic.manageStatusTag(clusterCrn, AutoScalerStatus, FAILED) + } else { + if isUpdating { + ic.manageStatusTag(clusterCrn, AutoScalerStatus, UPGRADE_DEPLOYING) + } else { + ic.manageStatusTag(clusterCrn, AutoScalerStatus, DEPLOYING) + } + + go func() { + cnt = 0 + for cnt < EnableAutoScalerRetry { + addonsInfo, _ := ic.getAddonInfo(clusterId, resourceGroupId) + for _, addon := range addonsInfo.KeyValueList { + if addon.Key == AutoscalerAddon && strings.Contains(addon.Value, "\"healthState\":\"normal\"") { + ic.manageStatusTag(clusterCrn, AutoScalerStatus, ACTIVE) + ic.applyAutoScalerOptions(clusterReqInfo, clusterId, resourceGroupId) + return + } + } + + time.Sleep(time.Minute) + cnt++ + } + ic.manageStatusTag(clusterCrn, AutoScalerStatus, FAILED) + if !isUpdating { + ic.DeleteCluster(clusterReqInfo.IId) + } + }() + } + }() + + return nil +} + +func (ic *IbmClusterHandler) setClusterInfo(rawCluster kubernetesserviceapiv1.GetClusterDetailResponse) (irs.ClusterInfo, error) { + resourceGroupId, getResourceGroupErr := ic.getDefaultResourceGroupId() + if getResourceGroupErr != nil { + return irs.ClusterInfo{}, getResourceGroupErr + } + + // Get VPC Infos + vpcIID := irs.IID{ + NameId: "", + SystemId: rawCluster.Vpcs[0], + } + vpcInfo, getVPCErr := GetRawVPC(vpcIID, ic.VpcService, ic.Ctx) + if getVPCErr != nil { + return irs.ClusterInfo{}, getVPCErr + } + vpcIID.NameId = *vpcInfo.Name + + // Get Addon Infos + clusterAddons, getAddonErr := ic.getAddonInfo(rawCluster.Id, resourceGroupId) + if getAddonErr != nil { + return irs.ClusterInfo{}, getAddonErr + } + + // Get Worker pool Infos + getWorkerPoolsResult, _, getWorkerPoolErr := ic.ClusterService.VpcGetWorkerPoolsWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkerPoolsOptions{ + Cluster: core.StringPtr(rawCluster.Id), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if getWorkerPoolErr != nil { + return irs.ClusterInfo{}, getWorkerPoolErr + } + + var nodeGroupList []irs.NodeGroupInfo + for _, element := range *getWorkerPoolsResult { + // Get Workers in pool + getWorkersResult, _, getWorkersErr := ic.ClusterService.VpcGetWorkersWithContext(ic.Ctx, &kubernetesserviceapiv1.VpcGetWorkersOptions{ + Cluster: core.StringPtr(rawCluster.Id), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + ShowDeleted: core.StringPtr("false"), + Pool: core.StringPtr(element.Id), + }) + if getWorkersErr != nil { + return irs.ClusterInfo{}, getWorkersErr + } + + var nodesIID []irs.IID + for _, worker := range getWorkersResult { + nodesIID = append(nodesIID, irs.IID{ + NameId: RetrieveUnableErr, + SystemId: *worker.ID, + }) + } + + nodeGroupList = append(nodeGroupList, irs.NodeGroupInfo{ + IId: irs.IID{ + NameId: element.PoolName, + SystemId: element.Id, + }, + ImageIID: irs.IID{ + NameId: RetrieveUnableErr, + SystemId: RetrieveUnableErr, + }, + VMSpecName: element.Flavor, + RootDiskType: RetrieveUnableErr, + RootDiskSize: RetrieveUnableErr, + KeyPairIID: irs.IID{ + NameId: RetrieveUnableErr, + SystemId: RetrieveUnableErr, + }, + OnAutoScaling: false, + DesiredNodeSize: -1, + MinNodeSize: 0, + MaxNodeSize: 0, + Status: ic.getNodeGroupStatusFromString(element.Lifecycle.DesiredState), + Nodes: nodesIID, + KeyValueList: nil, + }) + } + + // Get Network.Subnet Info + rawVpeList, _, getRawVpeListErr := ic.VpcService.ListEndpointGateways(&vpcv1.ListEndpointGatewaysOptions{ + ResourceGroupID: core.StringPtr(resourceGroupId), + }) + if getRawVpeListErr != nil { + return irs.ClusterInfo{}, getRawVpeListErr + } + + var target vpcv1.EndpointGateway + for _, rawVpe := range rawVpeList.EndpointGateways { + if *rawVpe.Name == fmt.Sprintf("iks-%s", rawCluster.Id) { + target = rawVpe + } + } + + var subnetIIDs []irs.IID + for _, ip := range target.Ips { + if strings.Contains(*ip.Name, rawCluster.Id) { + subnetId := strings.Split(*ip.Href, "/")[5] + rawSubnet, _, getRawSubnetErr := ic.VpcService.GetSubnet(&vpcv1.GetSubnetOptions{ + ID: core.StringPtr(subnetId), + }) + if getRawSubnetErr == nil { + subnetIIDs = append(subnetIIDs, irs.IID{ + NameId: *rawSubnet.Name, + SystemId: *rawSubnet.ID, + }) + } + } + } + + // Get Security Group + sgHandler := IbmSecurityHandler{ + CredentialInfo: ic.CredentialInfo, + Region: ic.Region, + VpcService: ic.VpcService, + Ctx: ic.Ctx, + } + sgInfo, sgInfoErr := sgHandler.GetSecurity(irs.IID{NameId: fmt.Sprintf("kube-%s", rawCluster.Id)}) + if sgInfoErr != nil { + return irs.ClusterInfo{}, sgInfoErr + } + + securityGroups := []irs.IID{sgInfo.IId} + + // Convert Created Time + createdTime, _ := strfmt.ParseDateTime(rawCluster.CreatedDate) + + // Determine Endpoint + var serviceEndpoint string + if rawCluster.ServiceEndpoints.PublicServiceEndpointEnabled { + serviceEndpoint = rawCluster.ServiceEndpoints.PublicServiceEndpointURL + } else { + serviceEndpoint = rawCluster.ServiceEndpoints.PrivateServiceEndpointURL + } + + // Get KubeConfig + kubeConfigStr, getKubeConfigStrErr := ic.getKubeConfig(rawCluster.Id, resourceGroupId) + if getKubeConfigStrErr == nil { + // Get Autoscaling Info + configMap, getAutoScalerConfigMapErr := ic.getAutoScalerConfigMap(kubeConfigStr) + if getAutoScalerConfigMapErr != nil { + cblogger.Error(getAutoScalerConfigMapErr) + } + + if configMap == nil { + for index, _ := range nodeGroupList { + nodeGroupList[index].OnAutoScaling = false + nodeGroupList[index].MinNodeSize = -1 + nodeGroupList[index].MaxNodeSize = -1 + nodeGroupList[index].DesiredNodeSize = -1 + } + } else { + jsonProperty, exists := configMap.Data[AutoscalerConfigMapOptionProperty] + if !exists { + cblogger.Error(errors.New("Failed to get Autoscaler Config from Config Map")) + } + + var workerPoolAutoscalerConfigs []kubernetesserviceapiv1.WorkerPoolAutoscalerConfig + unmarshalErr := json.Unmarshal([]byte(jsonProperty), &workerPoolAutoscalerConfigs) + if unmarshalErr != nil { + cblogger.Error(unmarshalErr) + } + + for index, nodeGroup := range nodeGroupList { + for _, config := range workerPoolAutoscalerConfigs { + if config.Name == nodeGroup.IId.NameId { + nodeGroupList[index].OnAutoScaling = config.Enabled + nodeGroupList[index].MinNodeSize = config.MinSize + nodeGroupList[index].MaxNodeSize = config.MaxSize + nodeGroupList[index].DesiredNodeSize = -1 + } + } + } + } + } else { + cblogger.Error(getKubeConfigStrErr) + } + + // get cluster status + clusterStatus := ic.getClusterStatusFromString(rawCluster.State) + rawTags, _, getTagsErr := ic.TaggingService.ListTagsWithContext(ic.Ctx, &globaltaggingv1.ListTagsOptions{ + TagType: core.StringPtr("user"), + Providers: []string{"ghost"}, + AttachedTo: core.StringPtr(rawCluster.Crn), + }) + if getTagsErr != nil { + clusterStatus = irs.ClusterInactive + } + + autoScalerStatus := fmt.Sprintf("%s%s", AutoScalerStatus, FAILED) + for _, tag := range rawTags.Items { + if isTagStatusOf(*tag.Name, AutoScalerStatus) { + autoScalerStatus = *tag.Name + break + } + } + securityGroupStatus := fmt.Sprintf("%s%s", SecurityGroupStatus, FAILED) + for _, tag := range rawTags.Items { + if isTagStatusOf(*tag.Name, SecurityGroupStatus) { + securityGroupStatus = *tag.Name + break + } + } + clusterStatus = ic.getClusterFinalStatus(clusterStatus, autoScalerStatus, securityGroupStatus) + + // Build result + return irs.ClusterInfo{ + IId: irs.IID{ + NameId: rawCluster.Name, + SystemId: rawCluster.Id, + }, + Version: rawCluster.MasterKubeVersion, + Network: irs.NetworkInfo{ + VpcIID: vpcIID, + SubnetIIDs: subnetIIDs, + SecurityGroupIIDs: securityGroups, + KeyValueList: nil, + }, + NodeGroupList: nodeGroupList, + AccessInfo: irs.AccessInfo{ + Endpoint: serviceEndpoint, + Kubeconfig: kubeConfigStr, + }, + Addons: clusterAddons, + Status: clusterStatus, + CreatedTime: time.Time(createdTime).Local(), + KeyValueList: nil, + }, nil +} + +func (ic *IbmClusterHandler) uninstallAutoScalerAddon(clusterId string, clusterCrn string, resourceGroupId string) error { + addons := []kubernetesserviceapiv1.ClusterAddon{{ + Name: core.StringPtr(AutoscalerAddon), + }} + _, _, disableAddonErr := ic.ClusterService.ManageClusterAddonsWithContext(ic.Ctx, &kubernetesserviceapiv1.ManageClusterAddonsOptions{ + IdOrName: core.StringPtr(clusterId), + Addons: addons, + Enable: core.BoolPtr(false), + XAuthResourceGroup: core.StringPtr(resourceGroupId), + }) + if disableAddonErr != nil { + return disableAddonErr + } + + go func() { + ic.manageStatusTag(clusterCrn, AutoScalerStatus, UNINSTALLING) + + cnt := 0 + for cnt < DisableAutoScalerRetry { + autoScalerAddonExists := false + addonsInfo, _ := ic.getAddonInfo(clusterId, resourceGroupId) + for _, addon := range addonsInfo.KeyValueList { + if addon.Key == AutoscalerAddon { + cnt++ + autoScalerAddonExists = true + time.Sleep(time.Minute) + break + } + } + if !autoScalerAddonExists { + // remove autoscaler tag + ic.manageStatusTag(clusterCrn, AutoScalerStatus, "") + break + } + } + }() + + return nil +} + +func (ic *IbmClusterHandler) updateAutoScalerConfigMap(kubeConfigStr string, nodeGroupList []irs.NodeGroupInfo) error { + k8sClient, getK8sClientErr := ic.ClusterService.GetKubernetesClient(kubeConfigStr) + if getK8sClientErr != nil { + return getK8sClientErr + } + + configMap, getConfigMapErr := k8sClient.CoreV1().ConfigMaps(ConfigMapNamespace).Get(context.Background(), AutoscalerConfigMap, metav1.GetOptions{}) + if getConfigMapErr != nil { + return getConfigMapErr + } + + workerPoolAutoscalerConfigs := make([]kubernetesserviceapiv1.WorkerPoolAutoscalerConfig, len(nodeGroupList)) + for i, nodeGroup := range nodeGroupList { + workerPoolAutoscalerConfigs[i].Name = nodeGroup.IId.NameId + workerPoolAutoscalerConfigs[i].Enabled = nodeGroup.OnAutoScaling + workerPoolAutoscalerConfigs[i].MaxSize = nodeGroup.MaxNodeSize + workerPoolAutoscalerConfigs[i].MinSize = nodeGroup.MinNodeSize + } + + newConfigJsonStr, marshalErr := json.Marshal(workerPoolAutoscalerConfigs) + if marshalErr != nil { + return marshalErr + } + configMap.Data[AutoscalerConfigMapOptionProperty] = string(newConfigJsonStr) + + _, updateErr := k8sClient.CoreV1().ConfigMaps(ConfigMapNamespace).Update(context.Background(), configMap, metav1.UpdateOptions{}) + if updateErr != nil { + return updateErr + } + + return nil +} + +func (ic *IbmClusterHandler) validateAndGetSubnetInfo(networkInfo irs.NetworkInfo) (irs.SubnetInfo, error) { + if len(networkInfo.SubnetIIDs) > 1 { + return irs.SubnetInfo{}, errors.New("IBM Kubernetes cluster can be created with only 1 subnet per zone") + } + + vpcHandler := IbmVPCHandler{ + CredentialInfo: ic.CredentialInfo, + Region: ic.Region, + VpcService: ic.VpcService, + Ctx: ic.Ctx, + } + vpcInfo, getVpcErr := vpcHandler.GetVPC(networkInfo.VpcIID) + if getVpcErr != nil { + return irs.SubnetInfo{}, getVpcErr + } + + for _, subnetInfo := range vpcInfo.SubnetInfoList { + if subnetInfo.IId.NameId == networkInfo.SubnetIIDs[0].NameId || + subnetInfo.IId.SystemId == networkInfo.SubnetIIDs[0].SystemId { + return subnetInfo, nil + } + } + return irs.SubnetInfo{}, errors.New(fmt.Sprintf("Cannot use given subnet: %v from VPC: %v", networkInfo.SubnetIIDs[0], vpcInfo.IId)) +} + +func (ic *IbmClusterHandler) validateAtCreateCluster(clusterInfo irs.ClusterInfo) error { + if clusterInfo.IId.NameId == "" { + return errors.New("Cluster name is required") + } + if clusterInfo.Network.VpcIID.SystemId == "" && clusterInfo.Network.VpcIID.NameId == "" { + return errors.New(fmt.Sprintf("Cannot identify VPC. IID: %s", clusterInfo.Network.VpcIID)) + } + if len(clusterInfo.Network.SubnetIIDs) < 1 { + return errors.New("At least one Subnet must be specified") + } + if len(clusterInfo.NodeGroupList) < 1 { + return errors.New("At least one Node Group must be specified") + } + if clusterInfo.Version == "" || clusterInfo.Version == "default" { + clusterInfo.Version = "1.24.8" + } + for i, nodeGroup := range clusterInfo.NodeGroupList { + if i != 0 && nodeGroup.IId.NameId == "" { + return errors.New(fmt.Sprintf("Node Group name is required for Node Group #%d ", i)) + } + if nodeGroup.MaxNodeSize < 1 { + return errors.New(fmt.Sprintf("MaxNodeSize of Node Group: %s cannot be smaller than 1", nodeGroup.IId)) + } + if nodeGroup.MinNodeSize < 1 { + return errors.New(fmt.Sprintf("MinNodeSize of Node Group: %s cannot be smaller than 1", nodeGroup.IId)) + } + if nodeGroup.DesiredNodeSize < 1 { + return errors.New(fmt.Sprintf("DesiredNodeSize of Node Group: %s cannot be smaller than 1", nodeGroup.IId)) + } + if nodeGroup.VMSpecName == "" { + return errors.New("VM Spec Name is required") + } + } + + return nil +} + +func (ic *IbmClusterHandler) validateAtAddNodeGroup(clusterIID irs.IID, nodeGroupInfo irs.NodeGroupInfo) interface{} { + if clusterIID.SystemId == "" && clusterIID.NameId == "" { + return errors.New("Invalid Cluster IID") + } + if nodeGroupInfo.IId.NameId == "" { + return errors.New("Node Group name is required") + } + if nodeGroupInfo.MaxNodeSize < 1 { + return errors.New("MaxNodeSize cannot be smaller than 1") + } + if nodeGroupInfo.MinNodeSize < 1 { + return errors.New("MaxNodeSize cannot be smaller than 1") + } + if nodeGroupInfo.DesiredNodeSize < 1 { + return errors.New("DesiredNodeSize cannot be smaller than 1") + } + if nodeGroupInfo.VMSpecName == "" { + return errors.New("VM Spec Name is required") + } + + return nil +} + +func (ic *IbmClusterHandler) validateAtChangeNodeGroupScaling(clusterIID irs.IID, nodeGroupIID irs.IID, minNodeSize int, maxNodeSize int) error { + if clusterIID.SystemId == "" && clusterIID.NameId == "" { + return errors.New("Invalid Cluster IID") + } + if nodeGroupIID.SystemId == "" && nodeGroupIID.NameId == "" { + return errors.New("Invalid Node Group IID") + } + if minNodeSize < 1 { + return errors.New("MaxNodeSize cannot be smaller than 1") + } + if maxNodeSize < 1 { + return errors.New("MaxNodeSize cannot be smaller than 1") + } + + return nil +} + +func compareTag(tag string, statusCode string, status string) bool { + return strings.EqualFold(tag, fmt.Sprintf("%s%s", statusCode, status)) +} + +func isTagStatusOf(tag string, statusCode string) bool { + return strings.Contains(tag, strings.ToLower(statusCode)) +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/DiskHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/DiskHandler.go index ee8bd8fb8..a09c653ce 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/DiskHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/DiskHandler.go @@ -1,422 +1,446 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - 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" - "sort" - "strconv" - "time" -) - -type IbmDiskHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - VpcService *vpcv1.VpcV1 - Ctx context.Context -} - -func (diskHandler *IbmDiskHandler) CreateDisk(diskReqInfo irs.DiskInfo) (irs.DiskInfo, error) { - hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskReqInfo.IId.NameId, "CreateDisk()") - start := call.Start() - intCapacity, capacityAtoiErr := strconv.Atoi(diskReqInfo.DiskSize) - var ptrCapacity *int64 - if capacityAtoiErr == nil { - ptrCapacity = core.Int64Ptr(int64(intCapacity)) - } - if ptrCapacity == nil || *ptrCapacity < 10 { - // set default capacity as minimum - ptrCapacity = core.Int64Ptr(50) - } - if &diskReqInfo.DiskType == nil || diskReqInfo.DiskType == "" || diskReqInfo.DiskType == "default" { - // set default type as least performance - diskReqInfo.DiskType = "general-purpose" - } - createVolumeOptions := &vpcv1.CreateVolumeOptions{} - createVolumeOptions.SetVolumePrototype(&vpcv1.VolumePrototype{ - Profile: &vpcv1.VolumeProfileIdentity{ - Name: &diskReqInfo.DiskType, - }, - Zone: &vpcv1.ZoneIdentity{ - Name: &diskReqInfo.Zone, - }, - Name: &diskReqInfo.IId.NameId, - Capacity: ptrCapacity, - }) - - createdDisk, _, createVolumeErr := diskHandler.VpcService.CreateVolume(createVolumeOptions) - if createVolumeErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Disk. err = %s", createVolumeErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.DiskInfo{}, createErr - } - LoggingInfo(hiscallInfo, start) - - return *diskHandler.ToIRSDisk(createdDisk), nil -} - -func (diskHandler *IbmDiskHandler) ListDisk() ([]*irs.DiskInfo, error) { - hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, "DISK", "ListDisk()") - - start := call.Start() - rawDiskList, listDiskErr := getRawDiskList(diskHandler.VpcService, diskHandler.Ctx) - if listDiskErr != nil { - getErr := errors.New(fmt.Sprintf("Failed to List Disk. err = %s", listDiskErr.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - var irsDiskInfoList []*irs.DiskInfo - for _, rawDisk := range *rawDiskList { - irsDiskInfoList = append(irsDiskInfoList, diskHandler.ToIRSDisk(&rawDisk)) - } - LoggingInfo(hiscallInfo, start) - return irsDiskInfoList, nil -} - -func (diskHandler *IbmDiskHandler) GetDisk(diskIID irs.IID) (irs.DiskInfo, error) { - hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "GetDisk()") - - start := call.Start() - rawDisk, getDiskErr := getRawDisk(diskHandler.VpcService, diskHandler.Ctx, diskIID) - if getDiskErr != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get Disk. err = %s", getDiskErr.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.DiskInfo{}, getErr - } - LoggingInfo(hiscallInfo, start) - - return *diskHandler.ToIRSDisk(rawDisk), nil -} - -func (diskHandler *IbmDiskHandler) ChangeDiskSize(diskIID irs.IID, size string) (bool, error) { - hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "ChangeDisk()") - start := call.Start() - targetSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) - if getDiskSystemIdErr != nil { - changeErr := errors.New(fmt.Sprintf("Failed to ChangeDiskSize. err = %s", getDiskSystemIdErr.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - - updateMaps := make(map[string]interface{}) - intSize, err := strconv.Atoi(size) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to ChangeDiskSize. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - updateMaps["capacity"] = core.Int64Ptr(int64(intSize)) - - updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ - ID: core.StringPtr(targetSystemId), - VolumePatch: updateMaps, - } - - _, _, updateDiskErr := diskHandler.VpcService.UpdateVolumeWithContext(diskHandler.Ctx, updateVolumeOptions) - if updateDiskErr != nil { - changeErr := errors.New(fmt.Sprintf("Failed to ChangeDiskSize. err = %s", updateDiskErr.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - LoggingInfo(hiscallInfo, start) - - return true, nil -} - -func (diskHandler *IbmDiskHandler) DeleteDisk(diskIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "DeleteDisk()") - start := call.Start() - targetSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) - if getDiskSystemIdErr != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Disk. err = %s", getDiskSystemIdErr.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - - deleteVolumeOptions := &vpcv1.DeleteVolumeOptions{ - ID: core.StringPtr(targetSystemId), - } - - _, deleteDiskErr := diskHandler.VpcService.DeleteVolumeWithContext(diskHandler.Ctx, deleteVolumeOptions) - if deleteDiskErr != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Disk. err = %s", deleteDiskErr.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - LoggingInfo(hiscallInfo, start) - - return true, nil -} - -func (diskHandler *IbmDiskHandler) AttachDisk(diskIID irs.IID, ownerVM irs.IID) (irs.DiskInfo, error) { - hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "AttachDisk()") - start := call.Start() - instance, getInstanceError := getRawInstance(ownerVM, diskHandler.VpcService, diskHandler.Ctx) - if getInstanceError != nil { - attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", getInstanceError.Error())) - cblogger.Error(attachErr.Error()) - LoggingError(hiscallInfo, attachErr) - return irs.DiskInfo{}, attachErr - } - - targetVolumeSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) - if getDiskSystemIdErr != nil { - attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", getInstanceError.Error())) - cblogger.Error(attachErr.Error()) - LoggingError(hiscallInfo, attachErr) - return irs.DiskInfo{}, attachErr - } - - createInstanceVolumeAttachmentOptions := &vpcv1.CreateInstanceVolumeAttachmentOptions{} - createInstanceVolumeAttachmentOptions.SetInstanceID(*instance.ID) - createInstanceVolumeAttachmentOptions.SetVolume(&vpcv1.VolumeAttachmentPrototypeVolumeVolumeIdentityVolumeIdentityByID{ID: &targetVolumeSystemId}) - createInstanceVolumeAttachmentOptions.SetDeleteVolumeOnInstanceDelete(false) - - _, _, attachDiskErr := diskHandler.VpcService.CreateInstanceVolumeAttachmentWithContext(diskHandler.Ctx, createInstanceVolumeAttachmentOptions) - if attachDiskErr != nil { - attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", attachDiskErr.Error())) - cblogger.Error(attachErr.Error()) - LoggingError(hiscallInfo, attachErr) - return irs.DiskInfo{}, attachErr - } - - attachedDisk, getDiskErr := diskHandler.GetDisk(diskIID) - if getDiskErr != nil { - attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", getDiskErr.Error())) - cblogger.Error(attachErr.Error()) - LoggingError(hiscallInfo, attachErr) - return irs.DiskInfo{}, attachErr - } - LoggingInfo(hiscallInfo, start) - return attachedDisk, nil -} - -func (diskHandler *IbmDiskHandler) DetachDisk(diskIID irs.IID, ownerVM irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "DetachDisk()") - start := call.Start() - - instance, getInstanceError := getRawInstance(ownerVM, diskHandler.VpcService, diskHandler.Ctx) - if getInstanceError != nil { - detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", getInstanceError.Error())) - cblogger.Error(detachErr.Error()) - LoggingError(hiscallInfo, detachErr) - return false, detachErr - } - - targetVolumeSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) - if getDiskSystemIdErr != nil { - detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", getDiskSystemIdErr.Error())) - cblogger.Error(detachErr.Error()) - LoggingError(hiscallInfo, detachErr) - return false, detachErr - } - - listInstanceVolumeAttachmentsOptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{} - listInstanceVolumeAttachmentsOptions.SetInstanceID(*instance.ID) - volumeAttachments, _, listVolumeAttachmentsErr := diskHandler.VpcService.ListInstanceVolumeAttachmentsWithContext(diskHandler.Ctx, listInstanceVolumeAttachmentsOptions) - if listVolumeAttachmentsErr != nil { - detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", listVolumeAttachmentsErr.Error())) - cblogger.Error(detachErr.Error()) - LoggingError(hiscallInfo, detachErr) - return false, detachErr - } - - targetVolumeAttachmentId := "" - for _, volumeAttachment := range (*volumeAttachments).VolumeAttachments { - if *volumeAttachment.Volume.ID == targetVolumeSystemId { - targetVolumeAttachmentId = *volumeAttachment.ID - break - } - } - if targetVolumeAttachmentId == "" { - detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = Cannot find Volume Attachment")) - cblogger.Error(detachErr.Error()) - LoggingError(hiscallInfo, detachErr) - return false, detachErr - } - - deleteInstanceVolumeAttachmentOptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{} - deleteInstanceVolumeAttachmentOptions.SetID(targetVolumeAttachmentId) - deleteInstanceVolumeAttachmentOptions.SetInstanceID(*instance.ID) - - _, detachDiskErr := diskHandler.VpcService.DeleteInstanceVolumeAttachmentWithContext(diskHandler.Ctx, deleteInstanceVolumeAttachmentOptions) - if detachDiskErr != nil { - detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", detachDiskErr.Error())) - cblogger.Error(detachErr.Error()) - LoggingError(hiscallInfo, detachErr) - return false, detachErr - } - LoggingInfo(hiscallInfo, start) - return true, nil -} - -func (diskHandler *IbmDiskHandler) ToIRSDisk(disk *vpcv1.Volume) *irs.DiskInfo { - var diskKeyValueList []irs.KeyValue - if disk != nil { - if disk.Iops != nil { - strIops := strconv.Itoa(int(*disk.Iops)) - diskKeyValueList = append(diskKeyValueList, irs.KeyValue{Key: "Iops", Value: strIops}) - } - if disk.ResourceGroup != nil { - diskKeyValueList = append(diskKeyValueList, irs.KeyValue{Key: "ResourceGroup", Value: *disk.ResourceGroup.Name}) - } - - var diskStatus irs.DiskStatus - var ownerVmIID irs.IID - if len(disk.VolumeAttachments) > 0 { - diskStatus = irs.DiskAttached - ownerVmIID = irs.IID{ - NameId: *disk.VolumeAttachments[0].Instance.Name, - SystemId: *disk.VolumeAttachments[0].Instance.ID, - } - } else { - diskStatus = getDiskStatus(*disk.Status) - ownerVmIID = irs.IID{} - } - - strCapacity := strconv.Itoa(int(*disk.Capacity)) - return &irs.DiskInfo{ - IId: irs.IID{ - SystemId: *disk.ID, - NameId: *disk.Name, - }, - Zone: *disk.Zone.Name, - DiskType: *disk.Profile.Name, - DiskSize: strCapacity, - Status: diskStatus, - OwnerVM: ownerVmIID, - CreatedTime: time.Time(*disk.CreatedAt).Local(), - KeyValueList: diskKeyValueList, - } - } - - return &irs.DiskInfo{} -} - -func getRawDiskList(vpcService *vpcv1.VpcV1, ctx context.Context) (*[]vpcv1.Volume, error) { - listVolumeOptions := &vpcv1.ListVolumesOptions{} - - var entireRawDiskList []vpcv1.Volume - for { - curIter, _, listDiskErr := vpcService.ListVolumesWithContext(ctx, listVolumeOptions) - if listDiskErr != nil { - return nil, listDiskErr - } - - if len(curIter.Volumes) > 0 { - entireRawDiskList = append(entireRawDiskList, curIter.Volumes...) - } else { - break - } - - nextIter := "" - if curIter.Next != nil && curIter.Next.Href != nil { - nextIter, _ = getNextHref(*curIter.Next.Href) - } - if nextIter != "" { - listVolumeOptions = &vpcv1.ListVolumesOptions{ - Start: core.StringPtr(nextIter), - } - } else { - break - } - } - - return &entireRawDiskList, nil -} - -func getRawDisk(vpcService *vpcv1.VpcV1, ctx context.Context, diskIID irs.IID) (*vpcv1.Volume, error) { - targetSystemId, getDiskSystemIdErr := getDiskSystemId(vpcService, ctx, diskIID) - if getDiskSystemIdErr != nil { - return nil, getDiskSystemIdErr - } - - getVolumeOptions := &vpcv1.GetVolumeOptions{ - ID: core.StringPtr(targetSystemId), - } - - rawDisk, _, getDiskErr := vpcService.GetVolumeWithContext(ctx, getVolumeOptions) - if getDiskErr != nil { - return nil, getDiskErr - } - - return rawDisk, nil -} - -func listRawAttachedDiskByVmIID(vpcService *vpcv1.VpcV1, ctx context.Context, ownerVMIID irs.IID) (*vpcv1.VolumeAttachmentCollection, error) { - instance, getInstanceErr := getRawInstance(ownerVMIID, vpcService, ctx) - if getInstanceErr != nil { - return nil, getInstanceErr - } - - listInstanceVolumeAttachmentsOptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{} - listInstanceVolumeAttachmentsOptions.SetInstanceID(*instance.ID) - volumeAttachments, _, listVolumeAttachmentsErr := vpcService.ListInstanceVolumeAttachmentsWithContext(ctx, listInstanceVolumeAttachmentsOptions) - if listVolumeAttachmentsErr != nil { - return nil, errors.New(fmt.Sprintf("Failed to List Volume Attachments. err = %s", listVolumeAttachmentsErr)) - } - - temp := volumeAttachments.VolumeAttachments - - sort.Slice(temp, func(i, j int) bool { - return temp[i].CreatedAt.String() < temp[j].CreatedAt.String() - }) - volumeAttachments.VolumeAttachments = temp - - return volumeAttachments, nil -} - -func getDiskStatus(status string) irs.DiskStatus { - switch status { - case "available": - return irs.DiskAvailable - case "failed", "unusable", "updating": - return irs.DiskError - case "pending": - return irs.DiskCreating - case "pending_deletion": - return irs.DiskDeleting - default: - return irs.DiskError - } -} - -func getDiskSystemId(vpcService *vpcv1.VpcV1, ctx context.Context, iid irs.IID) (string, error) { - if iid.NameId == "" && iid.SystemId == "" { - return "", errors.New("Disk Name ID or System ID required.") - } - - if iid.SystemId != "" { - return iid.SystemId, nil - } - - var targetSystemId string - if iid.SystemId == "" { - rawDiskList, getRawDiskListErr := getRawDiskList(vpcService, ctx) - if getRawDiskListErr != nil { - return "", errors.New(fmt.Sprintf("Failed to List Disk. err = %s", getRawDiskListErr)) - } - for _, rawDisk := range *rawDiskList { - if *rawDisk.Name == iid.NameId { - targetSystemId = *rawDisk.ID - } - } - } else { - targetSystemId = iid.SystemId - } - - return targetSystemId, nil -} +package resources + +import ( + "context" + "errors" + "fmt" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/vpc-go-sdk/vpcv1" + 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" + "sort" + "strconv" + "time" +) + +type IbmDiskHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + VpcService *vpcv1.VpcV1 + Ctx context.Context +} + +func (diskHandler *IbmDiskHandler) CreateDisk(diskReqInfo irs.DiskInfo) (irs.DiskInfo, error) { + hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskReqInfo.IId.NameId, "CreateDisk()") + start := call.Start() + intCapacity, capacityAtoiErr := strconv.Atoi(diskReqInfo.DiskSize) + var ptrCapacity *int64 + if capacityAtoiErr == nil { + ptrCapacity = core.Int64Ptr(int64(intCapacity)) + } + if ptrCapacity == nil || *ptrCapacity < 10 { + // set default capacity as minimum + ptrCapacity = core.Int64Ptr(50) + } + if &diskReqInfo.DiskType == nil || diskReqInfo.DiskType == "" || diskReqInfo.DiskType == "default" { + // set default type as least performance + diskReqInfo.DiskType = "general-purpose" + } + createVolumeOptions := &vpcv1.CreateVolumeOptions{} + createVolumeOptions.SetVolumePrototype(&vpcv1.VolumePrototype{ + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &diskReqInfo.DiskType, + }, + Zone: &vpcv1.ZoneIdentity{ + Name: &diskReqInfo.Zone, + }, + Name: &diskReqInfo.IId.NameId, + Capacity: ptrCapacity, + }) + + createdDisk, _, createVolumeErr := diskHandler.VpcService.CreateVolume(createVolumeOptions) + if createVolumeErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Disk. err = %s", createVolumeErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.DiskInfo{}, createErr + } + LoggingInfo(hiscallInfo, start) + + // Attach Tag + if diskReqInfo.TagList != nil && len(diskReqInfo.TagList) > 0 { + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range diskReqInfo.TagList{ + _, err := tagHandler.AddTag("DISK", diskReqInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on Disk err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + return *diskHandler.ToIRSDisk(createdDisk), nil +} + +func (diskHandler *IbmDiskHandler) ListDisk() ([]*irs.DiskInfo, error) { + hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, "DISK", "ListDisk()") + + start := call.Start() + rawDiskList, listDiskErr := getRawDiskList(diskHandler.VpcService, diskHandler.Ctx) + if listDiskErr != nil { + getErr := errors.New(fmt.Sprintf("Failed to List Disk. err = %s", listDiskErr.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + var irsDiskInfoList []*irs.DiskInfo + for _, rawDisk := range *rawDiskList { + irsDiskInfoList = append(irsDiskInfoList, diskHandler.ToIRSDisk(&rawDisk)) + } + LoggingInfo(hiscallInfo, start) + return irsDiskInfoList, nil +} + +func (diskHandler *IbmDiskHandler) GetDisk(diskIID irs.IID) (irs.DiskInfo, error) { + hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "GetDisk()") + + start := call.Start() + rawDisk, getDiskErr := getRawDisk(diskHandler.VpcService, diskHandler.Ctx, diskIID) + if getDiskErr != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get Disk. err = %s", getDiskErr.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.DiskInfo{}, getErr + } + LoggingInfo(hiscallInfo, start) + + return *diskHandler.ToIRSDisk(rawDisk), nil +} + +func (diskHandler *IbmDiskHandler) ChangeDiskSize(diskIID irs.IID, size string) (bool, error) { + hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "ChangeDisk()") + start := call.Start() + targetSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) + if getDiskSystemIdErr != nil { + changeErr := errors.New(fmt.Sprintf("Failed to ChangeDiskSize. err = %s", getDiskSystemIdErr.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + + updateMaps := make(map[string]interface{}) + intSize, err := strconv.Atoi(size) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to ChangeDiskSize. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + updateMaps["capacity"] = core.Int64Ptr(int64(intSize)) + + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: core.StringPtr(targetSystemId), + VolumePatch: updateMaps, + } + + _, _, updateDiskErr := diskHandler.VpcService.UpdateVolumeWithContext(diskHandler.Ctx, updateVolumeOptions) + if updateDiskErr != nil { + changeErr := errors.New(fmt.Sprintf("Failed to ChangeDiskSize. err = %s", updateDiskErr.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + LoggingInfo(hiscallInfo, start) + + return true, nil +} + +func (diskHandler *IbmDiskHandler) DeleteDisk(diskIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "DeleteDisk()") + start := call.Start() + targetSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) + if getDiskSystemIdErr != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Disk. err = %s", getDiskSystemIdErr.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + + deleteVolumeOptions := &vpcv1.DeleteVolumeOptions{ + ID: core.StringPtr(targetSystemId), + } + + _, deleteDiskErr := diskHandler.VpcService.DeleteVolumeWithContext(diskHandler.Ctx, deleteVolumeOptions) + if deleteDiskErr != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Disk. err = %s", deleteDiskErr.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err := tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Disk Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + return true, nil +} + +func (diskHandler *IbmDiskHandler) AttachDisk(diskIID irs.IID, ownerVM irs.IID) (irs.DiskInfo, error) { + hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "AttachDisk()") + start := call.Start() + instance, getInstanceError := getRawInstance(ownerVM, diskHandler.VpcService, diskHandler.Ctx) + if getInstanceError != nil { + attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", getInstanceError.Error())) + cblogger.Error(attachErr.Error()) + LoggingError(hiscallInfo, attachErr) + return irs.DiskInfo{}, attachErr + } + + targetVolumeSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) + if getDiskSystemIdErr != nil { + attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", getInstanceError.Error())) + cblogger.Error(attachErr.Error()) + LoggingError(hiscallInfo, attachErr) + return irs.DiskInfo{}, attachErr + } + + createInstanceVolumeAttachmentOptions := &vpcv1.CreateInstanceVolumeAttachmentOptions{} + createInstanceVolumeAttachmentOptions.SetInstanceID(*instance.ID) + createInstanceVolumeAttachmentOptions.SetVolume(&vpcv1.VolumeAttachmentPrototypeVolumeVolumeIdentityVolumeIdentityByID{ID: &targetVolumeSystemId}) + createInstanceVolumeAttachmentOptions.SetDeleteVolumeOnInstanceDelete(false) + + _, _, attachDiskErr := diskHandler.VpcService.CreateInstanceVolumeAttachmentWithContext(diskHandler.Ctx, createInstanceVolumeAttachmentOptions) + if attachDiskErr != nil { + attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", attachDiskErr.Error())) + cblogger.Error(attachErr.Error()) + LoggingError(hiscallInfo, attachErr) + return irs.DiskInfo{}, attachErr + } + + attachedDisk, getDiskErr := diskHandler.GetDisk(diskIID) + if getDiskErr != nil { + attachErr := errors.New(fmt.Sprintf("Failed to Attach Disk. err = %s", getDiskErr.Error())) + cblogger.Error(attachErr.Error()) + LoggingError(hiscallInfo, attachErr) + return irs.DiskInfo{}, attachErr + } + LoggingInfo(hiscallInfo, start) + return attachedDisk, nil +} + +func (diskHandler *IbmDiskHandler) DetachDisk(diskIID irs.IID, ownerVM irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(diskHandler.Region, call.DISK, diskIID.SystemId, "DetachDisk()") + start := call.Start() + + instance, getInstanceError := getRawInstance(ownerVM, diskHandler.VpcService, diskHandler.Ctx) + if getInstanceError != nil { + detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", getInstanceError.Error())) + cblogger.Error(detachErr.Error()) + LoggingError(hiscallInfo, detachErr) + return false, detachErr + } + + targetVolumeSystemId, getDiskSystemIdErr := getDiskSystemId(diskHandler.VpcService, diskHandler.Ctx, diskIID) + if getDiskSystemIdErr != nil { + detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", getDiskSystemIdErr.Error())) + cblogger.Error(detachErr.Error()) + LoggingError(hiscallInfo, detachErr) + return false, detachErr + } + + listInstanceVolumeAttachmentsOptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{} + listInstanceVolumeAttachmentsOptions.SetInstanceID(*instance.ID) + volumeAttachments, _, listVolumeAttachmentsErr := diskHandler.VpcService.ListInstanceVolumeAttachmentsWithContext(diskHandler.Ctx, listInstanceVolumeAttachmentsOptions) + if listVolumeAttachmentsErr != nil { + detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", listVolumeAttachmentsErr.Error())) + cblogger.Error(detachErr.Error()) + LoggingError(hiscallInfo, detachErr) + return false, detachErr + } + + targetVolumeAttachmentId := "" + for _, volumeAttachment := range (*volumeAttachments).VolumeAttachments { + if *volumeAttachment.Volume.ID == targetVolumeSystemId { + targetVolumeAttachmentId = *volumeAttachment.ID + break + } + } + if targetVolumeAttachmentId == "" { + detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = Cannot find Volume Attachment")) + cblogger.Error(detachErr.Error()) + LoggingError(hiscallInfo, detachErr) + return false, detachErr + } + + deleteInstanceVolumeAttachmentOptions := &vpcv1.DeleteInstanceVolumeAttachmentOptions{} + deleteInstanceVolumeAttachmentOptions.SetID(targetVolumeAttachmentId) + deleteInstanceVolumeAttachmentOptions.SetInstanceID(*instance.ID) + + _, detachDiskErr := diskHandler.VpcService.DeleteInstanceVolumeAttachmentWithContext(diskHandler.Ctx, deleteInstanceVolumeAttachmentOptions) + if detachDiskErr != nil { + detachErr := errors.New(fmt.Sprintf("Failed to Detach Disk. err = %s", detachDiskErr.Error())) + cblogger.Error(detachErr.Error()) + LoggingError(hiscallInfo, detachErr) + return false, detachErr + } + LoggingInfo(hiscallInfo, start) + return true, nil +} + +func (diskHandler *IbmDiskHandler) ToIRSDisk(disk *vpcv1.Volume) *irs.DiskInfo { + var diskKeyValueList []irs.KeyValue + if disk != nil { + if disk.Iops != nil { + strIops := strconv.Itoa(int(*disk.Iops)) + diskKeyValueList = append(diskKeyValueList, irs.KeyValue{Key: "Iops", Value: strIops}) + } + if disk.ResourceGroup != nil { + diskKeyValueList = append(diskKeyValueList, irs.KeyValue{Key: "ResourceGroup", Value: *disk.ResourceGroup.Name}) + } + + var diskStatus irs.DiskStatus + var ownerVmIID irs.IID + if len(disk.VolumeAttachments) > 0 { + diskStatus = irs.DiskAttached + ownerVmIID = irs.IID{ + NameId: *disk.VolumeAttachments[0].Instance.Name, + SystemId: *disk.VolumeAttachments[0].Instance.ID, + } + } else { + diskStatus = getDiskStatus(*disk.Status) + ownerVmIID = irs.IID{} + } + + strCapacity := strconv.Itoa(int(*disk.Capacity)) + return &irs.DiskInfo{ + IId: irs.IID{ + SystemId: *disk.ID, + NameId: *disk.Name, + }, + Zone: *disk.Zone.Name, + DiskType: *disk.Profile.Name, + DiskSize: strCapacity, + Status: diskStatus, + OwnerVM: ownerVmIID, + CreatedTime: time.Time(*disk.CreatedAt).Local(), + KeyValueList: diskKeyValueList, + } + } + + return &irs.DiskInfo{} +} + +func getRawDiskList(vpcService *vpcv1.VpcV1, ctx context.Context) (*[]vpcv1.Volume, error) { + listVolumeOptions := &vpcv1.ListVolumesOptions{} + + var entireRawDiskList []vpcv1.Volume + for { + curIter, _, listDiskErr := vpcService.ListVolumesWithContext(ctx, listVolumeOptions) + if listDiskErr != nil { + return nil, listDiskErr + } + + if len(curIter.Volumes) > 0 { + entireRawDiskList = append(entireRawDiskList, curIter.Volumes...) + } else { + break + } + + nextIter := "" + if curIter.Next != nil && curIter.Next.Href != nil { + nextIter, _ = getNextHref(*curIter.Next.Href) + } + if nextIter != "" { + listVolumeOptions = &vpcv1.ListVolumesOptions{ + Start: core.StringPtr(nextIter), + } + } else { + break + } + } + + return &entireRawDiskList, nil +} + +func getRawDisk(vpcService *vpcv1.VpcV1, ctx context.Context, diskIID irs.IID) (*vpcv1.Volume, error) { + targetSystemId, getDiskSystemIdErr := getDiskSystemId(vpcService, ctx, diskIID) + if getDiskSystemIdErr != nil { + return nil, getDiskSystemIdErr + } + + getVolumeOptions := &vpcv1.GetVolumeOptions{ + ID: core.StringPtr(targetSystemId), + } + + rawDisk, _, getDiskErr := vpcService.GetVolumeWithContext(ctx, getVolumeOptions) + if getDiskErr != nil { + return nil, getDiskErr + } + + return rawDisk, nil +} + +func listRawAttachedDiskByVmIID(vpcService *vpcv1.VpcV1, ctx context.Context, ownerVMIID irs.IID) (*vpcv1.VolumeAttachmentCollection, error) { + instance, getInstanceErr := getRawInstance(ownerVMIID, vpcService, ctx) + if getInstanceErr != nil { + return nil, getInstanceErr + } + + listInstanceVolumeAttachmentsOptions := &vpcv1.ListInstanceVolumeAttachmentsOptions{} + listInstanceVolumeAttachmentsOptions.SetInstanceID(*instance.ID) + volumeAttachments, _, listVolumeAttachmentsErr := vpcService.ListInstanceVolumeAttachmentsWithContext(ctx, listInstanceVolumeAttachmentsOptions) + if listVolumeAttachmentsErr != nil { + return nil, errors.New(fmt.Sprintf("Failed to List Volume Attachments. err = %s", listVolumeAttachmentsErr)) + } + + temp := volumeAttachments.VolumeAttachments + + sort.Slice(temp, func(i, j int) bool { + return temp[i].CreatedAt.String() < temp[j].CreatedAt.String() + }) + volumeAttachments.VolumeAttachments = temp + + return volumeAttachments, nil +} + +func getDiskStatus(status string) irs.DiskStatus { + switch status { + case "available": + return irs.DiskAvailable + case "failed", "unusable", "updating": + return irs.DiskError + case "pending": + return irs.DiskCreating + case "pending_deletion": + return irs.DiskDeleting + default: + return irs.DiskError + } +} + +func getDiskSystemId(vpcService *vpcv1.VpcV1, ctx context.Context, iid irs.IID) (string, error) { + if iid.NameId == "" && iid.SystemId == "" { + return "", errors.New("Disk Name ID or System ID required.") + } + + if iid.SystemId != "" { + return iid.SystemId, nil + } + + var targetSystemId string + if iid.SystemId == "" { + rawDiskList, getRawDiskListErr := getRawDiskList(vpcService, ctx) + if getRawDiskListErr != nil { + return "", errors.New(fmt.Sprintf("Failed to List Disk. err = %s", getRawDiskListErr)) + } + for _, rawDisk := range *rawDiskList { + if *rawDisk.Name == iid.NameId { + targetSystemId = *rawDisk.ID + } + } + } else { + targetSystemId = iid.SystemId + } + + return targetSystemId, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/KeyPairHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/KeyPairHandler.go index 5b322fc17..af7f19565 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/KeyPairHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/KeyPairHandler.go @@ -1,302 +1,328 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" - keypair "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/common" - idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" - irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" - "net/url" -) - -type IbmKeyPairHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - VpcService *vpcv1.VpcV1 - Ctx context.Context -} - -func (keyPairHandler *IbmKeyPairHandler) CreateKey(keyPairReqInfo irs.KeyPairReqInfo) (irs.KeyPairInfo, error) { - hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, keyPairReqInfo.IId.NameId, "CreateKey()") - - //IID확인 - err := checkValidKeyReqInfo(keyPairReqInfo) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.KeyPairInfo{}, createErr - } - //존재여부 확인 - exist, err := keyPairHandler.existKey(keyPairReqInfo.IId) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.KeyPairInfo{}, createErr - } - - if exist { - createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = The Key already exists")) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.KeyPairInfo{}, createErr - } - - start := call.Start() - - privateKey, publicKey, err := keypair.GenKeyPair() - - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.KeyPairInfo{}, createErr - } - - options := &vpcv1.CreateKeyOptions{} - options.SetName(keyPairReqInfo.IId.NameId) - options.SetPublicKey(string(publicKey)) - key, _, err := keyPairHandler.VpcService.CreateKeyWithContext(keyPairHandler.Ctx, options) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.KeyPairInfo{}, createErr - } - createKeypairInfo, err := setKeyInfo(*key, string(privateKey)) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.KeyPairInfo{}, createErr - } - LoggingInfo(hiscallInfo, start) - return createKeypairInfo, nil -} - -func (keyPairHandler *IbmKeyPairHandler) ListKey() ([]*irs.KeyPairInfo, error) { - hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, "VMKEYPAIR", "ListKey()") - start := call.Start() - listKeysOptions := &vpcv1.ListKeysOptions{} - keys, _, err := keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List Key err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - var ListKeys []*irs.KeyPairInfo - for { - for _, key := range keys.Keys { - keyInfo, err := setKeyInfo(key, "") - if err != nil { - cblogger.Error(err.Error()) - LoggingError(hiscallInfo, err) - continue - } - ListKeys = append(ListKeys, &keyInfo) - } - nextstr, _ := getKeyNextHref(keys.Next) - if nextstr != "" { - listKeysOptions := &vpcv1.ListKeysOptions{ - Start: core.StringPtr(nextstr), - } - keys, _, err = keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List Key err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - //break - } - } else { - break - } - } - LoggingInfo(hiscallInfo, start) - return ListKeys, nil -} - -func (keyPairHandler *IbmKeyPairHandler) GetKey(keyIID irs.IID) (irs.KeyPairInfo, error) { - hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, keyIID.NameId, "GetKey()") - start := call.Start() - key, err := getRawKey(keyIID, keyPairHandler.VpcService, keyPairHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get Key err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.KeyPairInfo{}, getErr - } - keyInfo, err := setKeyInfo(key, "") - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get Key err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.KeyPairInfo{}, getErr - } - LoggingInfo(hiscallInfo, start) - return keyInfo, nil -} - -func (keyPairHandler *IbmKeyPairHandler) DeleteKey(keyIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, keyIID.NameId, "DeleteKey()") - start := call.Start() - - //존재여부 확인 - exist, err := keyPairHandler.existKey(keyIID) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = %s", err)) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - - if !exist { - delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = The Key is not found")) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - - key, err := getRawKey(keyIID, keyPairHandler.VpcService, keyPairHandler.Ctx) - - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = %s", err)) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - - deleteKeyOptions := &vpcv1.DeleteKeyOptions{} - deleteKeyOptions.SetID(*key.ID) - _, err = keyPairHandler.VpcService.DeleteKeyWithContext(keyPairHandler.Ctx, deleteKeyOptions) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = %s", err)) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - LoggingInfo(hiscallInfo, start) - return true, nil -} - -func (keyPairHandler *IbmKeyPairHandler) existKey(keyIID irs.IID) (bool, error) { - if keyIID.NameId == "" { - return false, errors.New("inValid Name") - } else { - listKeysOptions := &vpcv1.ListKeysOptions{} - keys, _, err := keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) - if err != nil { - return false, err - } - for { - for _, key := range keys.Keys { - if *key.Name == keyIID.NameId { - return true, nil - } - } - nextstr, _ := getKeyNextHref(keys.Next) - if nextstr != "" { - listKeysOptions := &vpcv1.ListKeysOptions{ - Start: core.StringPtr(nextstr), - } - keys, _, err = keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) - if err != nil { - return false, errors.New("failed Get KeyList") - } - } else { - break - } - } - return false, nil - } -} - -func setKeyInfo(key vpcv1.Key, privateKey string) (irs.KeyPairInfo, error) { - keypairInfo := irs.KeyPairInfo{ - IId: irs.IID{ - NameId: *key.Name, - SystemId: *key.ID, - }, - Fingerprint: *key.Fingerprint, - PublicKey: *key.PublicKey, - PrivateKey: privateKey, - } - return keypairInfo, nil -} - -func checkValidKeyReqInfo(keyReqInfo irs.KeyPairReqInfo) error { - if keyReqInfo.IId.NameId == "" { - return errors.New("invalid VPCReqInfo NameId") - } - return nil -} - -func getRawKey(keyIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Key, error) { - if keyIID.SystemId == "" { - if keyIID.NameId == "" { - err := errors.New("invalid IId") - return vpcv1.Key{}, err - } - listKeysOptions := &vpcv1.ListKeysOptions{} - keys, _, err := vpcService.ListKeysWithContext(ctx, listKeysOptions) - if err != nil { - return vpcv1.Key{}, err - } - for { - for _, key := range keys.Keys { - if *key.Name == keyIID.NameId { - return key, nil - } - } - nextstr, _ := getKeyNextHref(keys.Next) - if nextstr != "" { - listKeysOptions := &vpcv1.ListKeysOptions{ - Start: core.StringPtr(nextstr), - } - keys, _, err = vpcService.ListKeysWithContext(ctx, listKeysOptions) - if err != nil { - // LoggingError(hiscallInfo, err) - return vpcv1.Key{}, err - //break - } - } else { - break - } - } - err = errors.New(fmt.Sprintf("not found Key %s", keyIID.NameId)) - return vpcv1.Key{}, err - } else { - options := &vpcv1.GetKeyOptions{ - ID: core.StringPtr(keyIID.SystemId), - } - key, _, err := vpcService.GetKeyWithContext(ctx, options) - if err != nil { - return vpcv1.Key{}, err - } - return *key, nil - } -} - -func getKeyNextHref(next *vpcv1.KeyCollectionNext) (string, error) { - if next != nil { - href := *next.Href - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - } - return "", errors.New("NOT NEXT") -} +package resources + +import ( + "context" + "errors" + "fmt" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/vpc-go-sdk/vpcv1" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" + keypair "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/common" + idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" + irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" + "net/url" +) + +type IbmKeyPairHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + VpcService *vpcv1.VpcV1 + Ctx context.Context +} + +func (keyPairHandler *IbmKeyPairHandler) CreateKey(keyPairReqInfo irs.KeyPairReqInfo) (irs.KeyPairInfo, error) { + hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, keyPairReqInfo.IId.NameId, "CreateKey()") + + //IID확인 + err := checkValidKeyReqInfo(keyPairReqInfo) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyPairInfo{}, createErr + } + //존재여부 확인 + exist, err := keyPairHandler.existKey(keyPairReqInfo.IId) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyPairInfo{}, createErr + } + + if exist { + createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = The Key already exists")) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyPairInfo{}, createErr + } + + start := call.Start() + + privateKey, publicKey, err := keypair.GenKeyPair() + + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyPairInfo{}, createErr + } + + options := &vpcv1.CreateKeyOptions{} + options.SetName(keyPairReqInfo.IId.NameId) + options.SetPublicKey(string(publicKey)) + key, _, err := keyPairHandler.VpcService.CreateKeyWithContext(keyPairHandler.Ctx, options) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyPairInfo{}, createErr + } + createKeypairInfo, err := setKeyInfo(*key, string(privateKey)) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Key. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyPairInfo{}, createErr + } + LoggingInfo(hiscallInfo, start) + + // Attach Tag + if keyPairReqInfo.TagList != nil && len(keyPairReqInfo.TagList) > 0{ + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range keyPairReqInfo.TagList{ + _, err := tagHandler.AddTag("KEY", keyPairReqInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on KEY err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + return createKeypairInfo, nil +} + +func (keyPairHandler *IbmKeyPairHandler) ListKey() ([]*irs.KeyPairInfo, error) { + hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, "VMKEYPAIR", "ListKey()") + start := call.Start() + listKeysOptions := &vpcv1.ListKeysOptions{} + keys, _, err := keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List Key err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + var ListKeys []*irs.KeyPairInfo + for { + for _, key := range keys.Keys { + keyInfo, err := setKeyInfo(key, "") + if err != nil { + cblogger.Error(err.Error()) + LoggingError(hiscallInfo, err) + continue + } + ListKeys = append(ListKeys, &keyInfo) + } + nextstr, _ := getKeyNextHref(keys.Next) + if nextstr != "" { + listKeysOptions := &vpcv1.ListKeysOptions{ + Start: core.StringPtr(nextstr), + } + keys, _, err = keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List Key err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + //break + } + } else { + break + } + } + LoggingInfo(hiscallInfo, start) + return ListKeys, nil +} + +func (keyPairHandler *IbmKeyPairHandler) GetKey(keyIID irs.IID) (irs.KeyPairInfo, error) { + hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, keyIID.NameId, "GetKey()") + start := call.Start() + key, err := getRawKey(keyIID, keyPairHandler.VpcService, keyPairHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get Key err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.KeyPairInfo{}, getErr + } + keyInfo, err := setKeyInfo(key, "") + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get Key err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.KeyPairInfo{}, getErr + } + LoggingInfo(hiscallInfo, start) + return keyInfo, nil +} + +func (keyPairHandler *IbmKeyPairHandler) DeleteKey(keyIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(keyPairHandler.Region, call.VMKEYPAIR, keyIID.NameId, "DeleteKey()") + start := call.Start() + + //존재여부 확인 + exist, err := keyPairHandler.existKey(keyIID) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = %s", err)) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + + if !exist { + delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = The Key is not found")) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + + key, err := getRawKey(keyIID, keyPairHandler.VpcService, keyPairHandler.Ctx) + + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = %s", err)) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + + deleteKeyOptions := &vpcv1.DeleteKeyOptions{} + deleteKeyOptions.SetID(*key.ID) + _, err = keyPairHandler.VpcService.DeleteKeyWithContext(keyPairHandler.Ctx, deleteKeyOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Key. err = %s", err)) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete KEY Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + return true, nil +} + +func (keyPairHandler *IbmKeyPairHandler) existKey(keyIID irs.IID) (bool, error) { + if keyIID.NameId == "" { + return false, errors.New("inValid Name") + } else { + listKeysOptions := &vpcv1.ListKeysOptions{} + keys, _, err := keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) + if err != nil { + return false, err + } + for { + for _, key := range keys.Keys { + if *key.Name == keyIID.NameId { + return true, nil + } + } + nextstr, _ := getKeyNextHref(keys.Next) + if nextstr != "" { + listKeysOptions := &vpcv1.ListKeysOptions{ + Start: core.StringPtr(nextstr), + } + keys, _, err = keyPairHandler.VpcService.ListKeysWithContext(keyPairHandler.Ctx, listKeysOptions) + if err != nil { + return false, errors.New("failed Get KeyList") + } + } else { + break + } + } + return false, nil + } +} + +func setKeyInfo(key vpcv1.Key, privateKey string) (irs.KeyPairInfo, error) { + keypairInfo := irs.KeyPairInfo{ + IId: irs.IID{ + NameId: *key.Name, + SystemId: *key.ID, + }, + Fingerprint: *key.Fingerprint, + PublicKey: *key.PublicKey, + PrivateKey: privateKey, + } + return keypairInfo, nil +} + +func checkValidKeyReqInfo(keyReqInfo irs.KeyPairReqInfo) error { + if keyReqInfo.IId.NameId == "" { + return errors.New("invalid VPCReqInfo NameId") + } + return nil +} + +func getRawKey(keyIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Key, error) { + if keyIID.SystemId == "" { + if keyIID.NameId == "" { + err := errors.New("invalid IId") + return vpcv1.Key{}, err + } + listKeysOptions := &vpcv1.ListKeysOptions{} + keys, _, err := vpcService.ListKeysWithContext(ctx, listKeysOptions) + if err != nil { + return vpcv1.Key{}, err + } + for { + for _, key := range keys.Keys { + if *key.Name == keyIID.NameId { + return key, nil + } + } + nextstr, _ := getKeyNextHref(keys.Next) + if nextstr != "" { + listKeysOptions := &vpcv1.ListKeysOptions{ + Start: core.StringPtr(nextstr), + } + keys, _, err = vpcService.ListKeysWithContext(ctx, listKeysOptions) + if err != nil { + // LoggingError(hiscallInfo, err) + return vpcv1.Key{}, err + //break + } + } else { + break + } + } + err = errors.New(fmt.Sprintf("not found Key %s", keyIID.NameId)) + return vpcv1.Key{}, err + } else { + options := &vpcv1.GetKeyOptions{ + ID: core.StringPtr(keyIID.SystemId), + } + key, _, err := vpcService.GetKeyWithContext(ctx, options) + if err != nil { + return vpcv1.Key{}, err + } + return *key, nil + } +} + +func getKeyNextHref(next *vpcv1.KeyCollectionNext) (string, error) { + if next != nil { + href := *next.Href + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + } + return "", errors.New("NOT NEXT") +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/MyImageHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/MyImageHandler.go index 1f74109b7..71bcfb922 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/MyImageHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/MyImageHandler.go @@ -1,281 +1,327 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "github.com/IBM/vpc-go-sdk/vpcv1" - 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" - "strings" - "time" -) - -type IbmMyImageHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - VpcService *vpcv1.VpcV1 - Ctx context.Context -} - -const DEV = "-dev-" - -func (myImageHandler *IbmMyImageHandler) SnapshotVM(snapshotReqInfo irs.MyImageInfo) (irs.MyImageInfo, error) { - hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, snapshotReqInfo.IId.NameId, "SnapshotVM()") - - if len(snapshotReqInfo.IId.NameId) > 55 { - createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = MyImage Name ID cannot be longer than 55 characters")) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.MyImageInfo{}, createErr - } - if strings.Contains(snapshotReqInfo.IId.NameId, DEV) { - createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = MyImage Name ID cannot include reserved string : %s", DEV)) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.MyImageInfo{}, createErr - } - - attachedDiskList, listAttachedDiskErr := listRawAttachedDiskByVmIID(myImageHandler.VpcService, myImageHandler.Ctx, snapshotReqInfo.SourceVM) - if listAttachedDiskErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = %s", listAttachedDiskErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.MyImageInfo{}, createErr - } - - start := call.Start() - mountIndex := 0 - for _, attachedDisk := range (*attachedDiskList).VolumeAttachments { - mountIndex++ - snapshotName := fmt.Sprintf("%s%s%d", snapshotReqInfo.IId.NameId, DEV, mountIndex) - createSnapshotOptions := vpcv1.CreateSnapshotOptions{ - Name: &snapshotName, - SourceVolume: &vpcv1.VolumeIdentityByID{ - ID: attachedDisk.Volume.ID, - }, - } - _, _, createSnapshotErr := myImageHandler.VpcService.CreateSnapshotWithContext(myImageHandler.Ctx, &createSnapshotOptions) - if createSnapshotErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = %s", createSnapshotErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.MyImageInfo{}, createErr - } - } - LoggingInfo(hiscallInfo, start) - - // get myimage info - converted, convertErr := myImageHandler.GetMyImage(irs.IID{NameId: snapshotReqInfo.IId.NameId}) - if convertErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = %s", convertErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.MyImageInfo{}, createErr - } - - return converted, nil -} - -func (myImageHandler *IbmMyImageHandler) ListMyImage() ([]*irs.MyImageInfo, error) { - hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, "MYIMAGE", "ListMyImage()") - - start := call.Start() - snapshotList, _, listSnapshotErr := myImageHandler.VpcService.ListSnapshotsWithContext(myImageHandler.Ctx, &vpcv1.ListSnapshotsOptions{}) - if listSnapshotErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to List MyImage. err = %s", listSnapshotErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return nil, createErr - } - - groupByImageResult := make(map[string][]vpcv1.Snapshot) - for _, snapshot := range snapshotList.Snapshots { - if strings.Contains(*snapshot.Name, DEV) { - groupByKey := strings.Split(*snapshot.Name, DEV)[0] - groupByImageResult[groupByKey] = append(groupByImageResult[groupByKey], snapshot) - } - } - - var myImageInfoList []*irs.MyImageInfo - for _, associatedSnapshots := range groupByImageResult { - myImage, toMyImageErr := myImageHandler.ToISRMyImage(associatedSnapshots) - if toMyImageErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to List MyImage. err = %s", toMyImageErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return nil, createErr - } - myImageInfoList = append(myImageInfoList, &myImage) - } - LoggingInfo(hiscallInfo, start) - - return myImageInfoList, nil -} - -func (myImageHandler *IbmMyImageHandler) GetMyImage(myImageIID irs.IID) (irs.MyImageInfo, error) { - hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, myImageIID.NameId, "GetMyImage()") - start := call.Start() - if myImageIID.NameId == "" && myImageIID.SystemId == "" { - createErr := errors.New(fmt.Sprintf("Failed to Get MyImage. err = MyImage Name ID or System ID is required")) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.MyImageInfo{}, createErr - } - - myImageList, err := myImageHandler.ListMyImage() - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Get MyImage. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.MyImageInfo{}, createErr - } - - for _, myImage := range myImageList { - if myImage.IId.SystemId == myImageIID.SystemId { - return *myImage, nil - } else if myImage.IId.NameId == myImageIID.NameId { - return *myImage, nil - } - } - LoggingInfo(hiscallInfo, start) - - return irs.MyImageInfo{}, errors.New(fmt.Sprintf("Failed to Get MyImage. err = MyImage not found")) -} - -func (myImageHandler *IbmMyImageHandler) DeleteMyImage(myImageIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, myImageIID.NameId, "DeleteMyImage()") - start := call.Start() - if myImageIID.NameId == "" && myImageIID.SystemId == "" { - delErr := errors.New(fmt.Sprintf("Failed to Delete MyImage. err = MyImage Name ID or System ID is required")) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - if err := myImageHandler.cleanSnapshotByMyImage(myImageIID); err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete MyImage. err = %s", err)) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - LoggingInfo(hiscallInfo, start) - - return true, nil -} - -func (myImageHandler *IbmMyImageHandler) ToISRMyImage(snapshotList []vpcv1.Snapshot) (irs.MyImageInfo, error) { - if len(snapshotList) == 0 { - return irs.MyImageInfo{}, errors.New("Cannot find MyImage") - } - - var myImageNameId string - var myImageSystemId string - var sourceVmNameId string - var sourceVmSystemId string - myImageStatus := irs.MyImageAvailable - var myImageCreatedTime time.Time - for _, snapshot := range snapshotList { - if *snapshot.Bootable == true { - myImageNameId = strings.Split(*snapshot.Name, DEV)[0] - myImageSystemId = *snapshot.ID - - getVolumeOptions := vpcv1.GetVolumeOptions{ - ID: snapshot.SourceVolume.ID, - } - rawSourceVolume, _, getSourceVolumeErr := myImageHandler.VpcService.GetVolumeWithContext(myImageHandler.Ctx, &getVolumeOptions) - sourceVmNameId = "Deleted" - sourceVmSystemId = "Deleted" - if getSourceVolumeErr == nil && len((*rawSourceVolume).VolumeAttachments) != 0 { - sourceVmNameId = *(*rawSourceVolume).VolumeAttachments[0].Instance.Name - sourceVmSystemId = *(*rawSourceVolume).VolumeAttachments[0].Instance.ID - } - - myImageCreatedTime = time.Time(*snapshot.CreatedAt).Local() - } - - if myImageStatus == irs.MyImageAvailable && getSnapshotStatus(*snapshot.LifecycleState) == irs.MyImageUnavailable { - myImageStatus = irs.MyImageUnavailable - } - } - - return irs.MyImageInfo{ - IId: irs.IID{NameId: myImageNameId, SystemId: myImageSystemId}, - SourceVM: irs.IID{NameId: sourceVmNameId, SystemId: sourceVmSystemId}, - Status: myImageStatus, - CreatedTime: myImageCreatedTime, - }, nil -} - -func (myImageHandler *IbmMyImageHandler) cleanSnapshotByMyImage(myImageIID irs.IID) error { - snapshotList, _, listSnapshotErr := myImageHandler.VpcService.ListSnapshotsWithContext(myImageHandler.Ctx, &vpcv1.ListSnapshotsOptions{}) - if listSnapshotErr != nil { - return listSnapshotErr - } - - myImageNameId := "" - if myImageIID.NameId != "" { - myImageNameId = myImageIID.NameId - } else { - for _, snapshot := range snapshotList.Snapshots { - if *snapshot.ID == myImageIID.SystemId { - myImageNameId = strings.Split(*snapshot.Name, DEV)[0] - } - } - } - - if myImageNameId != "" { - for _, snapshot := range snapshotList.Snapshots { - parsed := strings.Split(*snapshot.Name, DEV)[0] - if parsed == myImageNameId { - deleteSnapshotOptions := vpcv1.DeleteSnapshotOptions{ - ID: snapshot.ID, - } - myImageHandler.VpcService.DeleteSnapshotWithContext(myImageHandler.Ctx, &deleteSnapshotOptions) - } - } - } - - return nil -} - -func getSnapshotStatus(status string) irs.MyImageStatus { - switch status { - case "deleting", "failed", "pending", "suspended", "updating", "waiting": - return irs.MyImageUnavailable - case "stable": - return irs.MyImageAvailable - default: - return irs.MyImageUnavailable - } -} - -func (myImageHandler *IbmMyImageHandler) CheckWindowsImage(myImageIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, myImageIID.NameId, "CheckWindowsImage()") - start := call.Start() - var getMyImageErr error - myImage, getMyImageErr := myImageHandler.GetMyImage(myImageIID) - if getMyImageErr != nil { - checkWindowsImageErr := errors.New(fmt.Sprintf("Failed to CheckWindowsImage By MyImage. err = %s", getMyImageErr.Error())) - cblogger.Error(checkWindowsImageErr.Error()) - LoggingError(hiscallInfo, checkWindowsImageErr) - return false, checkWindowsImageErr - } - if myImage.Status != irs.MyImageAvailable { - checkWindowsImageErr := errors.New(fmt.Sprintf("Failed to CheckWindowsImage By MyImage. err = Source Image status is not Available")) - cblogger.Error(checkWindowsImageErr.Error()) - LoggingError(hiscallInfo, checkWindowsImageErr) - return false, checkWindowsImageErr - } - rawSnapshot, _, getRawSnapshotErr := myImageHandler.VpcService.GetSnapshotWithContext(myImageHandler.Ctx, &vpcv1.GetSnapshotOptions{ID: &myImage.IId.SystemId}) - if getRawSnapshotErr != nil { - checkWindowsImageErr := errors.New(fmt.Sprintf("Failed to CheckWindowsImage By MyImage. err = %s", getRawSnapshotErr.Error())) - cblogger.Error(checkWindowsImageErr.Error()) - LoggingError(hiscallInfo, checkWindowsImageErr) - return false, checkWindowsImageErr - } - - isWindows := strings.Contains(strings.ToLower(*rawSnapshot.OperatingSystem.Name), "windows") - LoggingInfo(hiscallInfo, start) - return isWindows, nil -} +package resources + +import ( + "context" + "errors" + "fmt" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + 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" + "strings" + "time" +) + +type IbmMyImageHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + VpcService *vpcv1.VpcV1 + Ctx context.Context +} + +const DEV = "-dev-" + +func (myImageHandler *IbmMyImageHandler) SnapshotVM(snapshotReqInfo irs.MyImageInfo) (irs.MyImageInfo, error) { + hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, snapshotReqInfo.IId.NameId, "SnapshotVM()") + + if len(snapshotReqInfo.IId.NameId) > 55 { + createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = MyImage Name ID cannot be longer than 55 characters")) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.MyImageInfo{}, createErr + } + if strings.Contains(snapshotReqInfo.IId.NameId, DEV) { + createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = MyImage Name ID cannot include reserved string : %s", DEV)) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.MyImageInfo{}, createErr + } + + attachedDiskList, listAttachedDiskErr := listRawAttachedDiskByVmIID(myImageHandler.VpcService, myImageHandler.Ctx, snapshotReqInfo.SourceVM) + if listAttachedDiskErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = %s", listAttachedDiskErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.MyImageInfo{}, createErr + } + + start := call.Start() + mountIndex := 0 + for _, attachedDisk := range (*attachedDiskList).VolumeAttachments { + mountIndex++ + snapshotName := fmt.Sprintf("%s%s%d", snapshotReqInfo.IId.NameId, DEV, mountIndex) + createSnapshotOptions := vpcv1.CreateSnapshotOptions{ + Name: &snapshotName, + SourceVolume: &vpcv1.VolumeIdentityByID{ + ID: attachedDisk.Volume.ID, + }, + } + _, _, createSnapshotErr := myImageHandler.VpcService.CreateSnapshotWithContext(myImageHandler.Ctx, &createSnapshotOptions) + if createSnapshotErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = %s", createSnapshotErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.MyImageInfo{}, createErr + } + } + LoggingInfo(hiscallInfo, start) + + // get myimage info + converted, convertErr := myImageHandler.GetMyImage(irs.IID{NameId: snapshotReqInfo.IId.NameId}) + if convertErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to SnapshotVM VM. err = %s", convertErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.MyImageInfo{}, createErr + } + + // Attach Tag + if snapshotReqInfo.TagList != nil && len(snapshotReqInfo.TagList) > 0 { + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range snapshotReqInfo.TagList{ + _, err := tagHandler.AddTag("MYIMAGE", snapshotReqInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on MyImage err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + return converted, nil +} + +func (myImageHandler *IbmMyImageHandler) ListMyImage() ([]*irs.MyImageInfo, error) { + hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, "MYIMAGE", "ListMyImage()") + + start := call.Start() + snapshotList, _, listSnapshotErr := myImageHandler.VpcService.ListSnapshotsWithContext(myImageHandler.Ctx, &vpcv1.ListSnapshotsOptions{}) + if listSnapshotErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to List MyImage. err = %s", listSnapshotErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return nil, createErr + } + + groupByImageResult := make(map[string][]vpcv1.Snapshot) + for _, snapshot := range snapshotList.Snapshots { + if strings.Contains(*snapshot.Name, DEV) { + groupByKey := strings.Split(*snapshot.Name, DEV)[0] + groupByImageResult[groupByKey] = append(groupByImageResult[groupByKey], snapshot) + } + } + + var myImageInfoList []*irs.MyImageInfo + for _, associatedSnapshots := range groupByImageResult { + myImage, toMyImageErr := myImageHandler.ToISRMyImage(associatedSnapshots) + if toMyImageErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to List MyImage. err = %s", toMyImageErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return nil, createErr + } + myImageInfoList = append(myImageInfoList, &myImage) + } + LoggingInfo(hiscallInfo, start) + + return myImageInfoList, nil +} + +// Create Function: GetRawMyImage +// Return Type: vpc.snapshot +// Using: TagHandler +func (myImageHandler *IbmMyImageHandler) GetRawMyImage(myImageIID irs.IID) (*vpcv1.Snapshot, error) { + hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, "MYIMAGE", "GetRawMyImage()") + start := call.Start() + + snapshot, _, getSnapshotErr := myImageHandler.VpcService.GetSnapshotWithContext(myImageHandler.Ctx, &vpcv1.GetSnapshotOptions{ID: &myImageIID.NameId}) + if getSnapshotErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to List MyImage. err = %s", getSnapshotErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return nil, createErr + } + + LoggingInfo(hiscallInfo, start) + + return snapshot, nil +} + +func (myImageHandler *IbmMyImageHandler) GetMyImage(myImageIID irs.IID) (irs.MyImageInfo, error) { + hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, myImageIID.NameId, "GetMyImage()") + start := call.Start() + if myImageIID.NameId == "" && myImageIID.SystemId == "" { + createErr := errors.New(fmt.Sprintf("Failed to Get MyImage. err = MyImage Name ID or System ID is required")) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.MyImageInfo{}, createErr + } + + myImageList, err := myImageHandler.ListMyImage() + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Get MyImage. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.MyImageInfo{}, createErr + } + + for _, myImage := range myImageList { + if myImage.IId.SystemId == myImageIID.SystemId { + return *myImage, nil + } else if myImage.IId.NameId == myImageIID.NameId { + return *myImage, nil + } + } + LoggingInfo(hiscallInfo, start) + + return irs.MyImageInfo{}, errors.New(fmt.Sprintf("Failed to Get MyImage. err = MyImage not found")) +} + +func (myImageHandler *IbmMyImageHandler) DeleteMyImage(myImageIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, myImageIID.NameId, "DeleteMyImage()") + start := call.Start() + if myImageIID.NameId == "" && myImageIID.SystemId == "" { + delErr := errors.New(fmt.Sprintf("Failed to Delete MyImage. err = MyImage Name ID or System ID is required")) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + if err := myImageHandler.cleanSnapshotByMyImage(myImageIID); err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete MyImage. err = %s", err)) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err := tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete MyImage Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + + return true, nil +} + +func (myImageHandler *IbmMyImageHandler) ToISRMyImage(snapshotList []vpcv1.Snapshot) (irs.MyImageInfo, error) { + if len(snapshotList) == 0 { + return irs.MyImageInfo{}, errors.New("Cannot find MyImage") + } + + var myImageNameId string + var myImageSystemId string + var sourceVmNameId string + var sourceVmSystemId string + myImageStatus := irs.MyImageAvailable + var myImageCreatedTime time.Time + for _, snapshot := range snapshotList { + if *snapshot.Bootable == true { + myImageNameId = strings.Split(*snapshot.Name, DEV)[0] + myImageSystemId = *snapshot.ID + + getVolumeOptions := vpcv1.GetVolumeOptions{ + ID: snapshot.SourceVolume.ID, + } + rawSourceVolume, _, getSourceVolumeErr := myImageHandler.VpcService.GetVolumeWithContext(myImageHandler.Ctx, &getVolumeOptions) + sourceVmNameId = "Deleted" + sourceVmSystemId = "Deleted" + if getSourceVolumeErr == nil && len((*rawSourceVolume).VolumeAttachments) != 0 { + sourceVmNameId = *(*rawSourceVolume).VolumeAttachments[0].Instance.Name + sourceVmSystemId = *(*rawSourceVolume).VolumeAttachments[0].Instance.ID + } + + myImageCreatedTime = time.Time(*snapshot.CreatedAt).Local() + } + + if myImageStatus == irs.MyImageAvailable && getSnapshotStatus(*snapshot.LifecycleState) == irs.MyImageUnavailable { + myImageStatus = irs.MyImageUnavailable + } + } + + return irs.MyImageInfo{ + IId: irs.IID{NameId: myImageNameId, SystemId: myImageSystemId}, + SourceVM: irs.IID{NameId: sourceVmNameId, SystemId: sourceVmSystemId}, + Status: myImageStatus, + CreatedTime: myImageCreatedTime, + }, nil +} + +func (myImageHandler *IbmMyImageHandler) cleanSnapshotByMyImage(myImageIID irs.IID) error { + snapshotList, _, listSnapshotErr := myImageHandler.VpcService.ListSnapshotsWithContext(myImageHandler.Ctx, &vpcv1.ListSnapshotsOptions{}) + if listSnapshotErr != nil { + return listSnapshotErr + } + + myImageNameId := "" + if myImageIID.NameId != "" { + myImageNameId = myImageIID.NameId + } else { + for _, snapshot := range snapshotList.Snapshots { + if *snapshot.ID == myImageIID.SystemId { + myImageNameId = strings.Split(*snapshot.Name, DEV)[0] + } + } + } + + if myImageNameId != "" { + for _, snapshot := range snapshotList.Snapshots { + parsed := strings.Split(*snapshot.Name, DEV)[0] + if parsed == myImageNameId { + deleteSnapshotOptions := vpcv1.DeleteSnapshotOptions{ + ID: snapshot.ID, + } + myImageHandler.VpcService.DeleteSnapshotWithContext(myImageHandler.Ctx, &deleteSnapshotOptions) + } + } + } + + return nil +} + +func getSnapshotStatus(status string) irs.MyImageStatus { + switch status { + case "deleting", "failed", "pending", "suspended", "updating", "waiting": + return irs.MyImageUnavailable + case "stable": + return irs.MyImageAvailable + default: + return irs.MyImageUnavailable + } +} + +func (myImageHandler *IbmMyImageHandler) CheckWindowsImage(myImageIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(myImageHandler.Region, call.MYIMAGE, myImageIID.NameId, "CheckWindowsImage()") + start := call.Start() + var getMyImageErr error + myImage, getMyImageErr := myImageHandler.GetMyImage(myImageIID) + if getMyImageErr != nil { + checkWindowsImageErr := errors.New(fmt.Sprintf("Failed to CheckWindowsImage By MyImage. err = %s", getMyImageErr.Error())) + cblogger.Error(checkWindowsImageErr.Error()) + LoggingError(hiscallInfo, checkWindowsImageErr) + return false, checkWindowsImageErr + } + if myImage.Status != irs.MyImageAvailable { + checkWindowsImageErr := errors.New(fmt.Sprintf("Failed to CheckWindowsImage By MyImage. err = Source Image status is not Available")) + cblogger.Error(checkWindowsImageErr.Error()) + LoggingError(hiscallInfo, checkWindowsImageErr) + return false, checkWindowsImageErr + } + rawSnapshot, _, getRawSnapshotErr := myImageHandler.VpcService.GetSnapshotWithContext(myImageHandler.Ctx, &vpcv1.GetSnapshotOptions{ID: &myImage.IId.SystemId}) + if getRawSnapshotErr != nil { + checkWindowsImageErr := errors.New(fmt.Sprintf("Failed to CheckWindowsImage By MyImage. err = %s", getRawSnapshotErr.Error())) + cblogger.Error(checkWindowsImageErr.Error()) + LoggingError(hiscallInfo, checkWindowsImageErr) + return false, checkWindowsImageErr + } + + isWindows := strings.Contains(strings.ToLower(*rawSnapshot.OperatingSystem.Name), "windows") + LoggingInfo(hiscallInfo, start) + return isWindows, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/NLBHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/NLBHandler.go index a8c073183..84d875846 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/NLBHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/NLBHandler.go @@ -1,1519 +1,1545 @@ -package resources - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - 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" - "net/url" - "reflect" - "strconv" - "strings" - "sync" - "time" -) - -type NLBType string -type NLBScope string -type NLBVMStatus string - -const ( - NLBPublicType NLBType = "PUBLIC" - NLBInternalType NLBType = "INTERNAL" - NLBGlobalType NLBScope = "GLOBAL" - NLBRegionType NLBScope = "REGION" - NLBVMStatusFault NLBVMStatus = "faulted" - NLBVMStatusOK NLBVMStatus = "ok" - NLBVMStatusUnknown NLBVMStatus = "unknown" -) - -type IbmNLBHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - VpcService *vpcv1.VpcV1 - Ctx context.Context -} - -// ------ NLB Management -func (nlbHandler *IbmNLBHandler) CreateNLB(nlbReqInfo irs.NLBInfo) (irs.NLBInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbReqInfo.IId.NameId, "CreateNLB()") - start := call.Start() - rawNLB, err := nlbHandler.createNLB(nlbReqInfo) - if err != nil { - nlbHandler.cleanerNLB(nlbReqInfo.IId) - createErr := errors.New(fmt.Sprintf("Failed to Create NLB. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.NLBInfo{}, createErr - } - info, err := nlbHandler.setterNLB(rawNLB) - if err != nil { - nlbHandler.cleanerNLB(nlbReqInfo.IId) - createErr := errors.New(fmt.Sprintf("Failed to Create NLB. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.NLBInfo{}, createErr - } - LoggingInfo(hiscallInfo, start) - return *info, nil -} -func (nlbHandler *IbmNLBHandler) ListNLB() ([]*irs.NLBInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", "NLB", "ListNLB()") - start := call.Start() - - nlbList, err := nlbHandler.getRawNLBList() - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List NLB. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - - nlbInfoList := make([]*irs.NLBInfo, len(*nlbList)) - - var wait sync.WaitGroup - wait.Add(len(*nlbList)) - var errList []string - - for i, nlb := range *nlbList { - go func() { - defer wait.Done() - info, getErr := nlbHandler.setterNLB(nlb) - if getErr != nil { - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - errList = append(errList, getErr.Error()) - } - nlbInfoList[i] = info - }() - } - wait.Wait() - LoggingInfo(hiscallInfo, start) - - if len(errList) > 0 { - errList = append([]string{"Failed to List NLB. err = "}, errList...) - getErr := errors.New(fmt.Sprintf("Failed to List NLB. err = %s", strings.Join(errList, "\n\t"))) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - - return nlbInfoList, nil -} -func (nlbHandler *IbmNLBHandler) GetNLB(nlbIID irs.IID) (irs.NLBInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "GetNLB()") - start := call.Start() - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get NLB. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.NLBInfo{}, getErr - } - info, err := nlbHandler.setterNLB(rawNLB) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get NLB. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.NLBInfo{}, getErr - } - LoggingInfo(hiscallInfo, start) - return *info, err -} -func (nlbHandler *IbmNLBHandler) DeleteNLB(nlbIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "DeleteNLB()") - start := call.Start() - - _, err := nlbHandler.cleanerNLB(nlbIID) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete NLB. err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - LoggingInfo(hiscallInfo, start) - return true, nil -} - -// ------ Frontend Control -func (nlbHandler *IbmNLBHandler) ChangeListener(nlbIID irs.IID, listener irs.ListenerInfo) (irs.ListenerInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "ChangeListener()") - start := call.Start() - - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - nlbId := *rawNLB.ID - if rawNLB.Listeners == nil || len(rawNLB.Listeners) < 1 { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = listener does not exist within that NLB")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - ListenerOption := vpcv1.GetLoadBalancerListenerOptions{} - ListenerOption.SetLoadBalancerID(*rawNLB.ID) - ListenerOption.SetID(*rawNLB.Listeners[0].ID) - rawListener, _, err := nlbHandler.VpcService.GetLoadBalancerListenerWithContext(nlbHandler.Ctx, &ListenerOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - if listener.Protocol != "" && !strings.EqualFold(strings.ToUpper(listener.Protocol), strings.ToUpper(*rawListener.Protocol)) { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = changing the protocol of the Listener is not supported.")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - oldListenerPort := int(*rawListener.Port) - listenerPort, err := strconv.Atoi(listener.Port) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - if oldListenerPort != listenerPort { - if listenerPort > 65535 || listenerPort < 1 { - return irs.ListenerInfo{}, errors.New("ibm-NLB Listener provides an port of between 1 and 65535") - } - - listenerPort64 := int64(listenerPort) - - updateMaps := make(map[string]interface{}) - updateMaps["port"] = core.Int64Ptr(listenerPort64) - - updateOption := vpcv1.UpdateLoadBalancerListenerOptions{} - updateOption.SetID(*rawListener.ID) - updateOption.SetLoadBalancerID(nlbId) - updateOption.SetLoadBalancerListenerPatch(updateMaps) - - _, _, err = nlbHandler.VpcService.UpdateLoadBalancerListenerWithContext(nlbHandler.Ctx, &updateOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - - } - updatedRawNLB, err := nlbHandler.checkUpdatableNLB(nlbId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - - info, err := nlbHandler.setterNLB(updatedRawNLB) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.ListenerInfo{}, changeErr - } - LoggingInfo(hiscallInfo, start) - return info.Listener, err -} - -// ------ Backend Control -func (nlbHandler *IbmNLBHandler) ChangeVMGroupInfo(nlbIID irs.IID, vmGroup irs.VMGroupInfo) (irs.VMGroupInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "ChangeVMGroupInfo()") - start := call.Start() - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = VMGroup does not exist within that NLB")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - updatePoolId := *rawNLB.Pools[0].ID - updateNLBId := *rawNLB.ID - - poolOption := vpcv1.GetLoadBalancerPoolOptions{} - poolOption.SetLoadBalancerID(updateNLBId) - poolOption.SetID(updatePoolId) - - rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - vmGroupPort, err := nlbHandler.getPoolPort(updateNLBId, updatePoolId) - - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - if vmGroup.Protocol != "" && !strings.EqualFold(strings.ToUpper(vmGroup.Protocol), strings.ToUpper(*rawPool.Protocol)) { - changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = changing the protocol of the Listener is not supported.")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - // 변경시만 업데이트 하도록 - if !strings.EqualFold(vmGroup.Port, strconv.Itoa(vmGroupPort)) { - memberPort, err := strconv.Atoi(vmGroup.Port) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - if memberPort > 65535 || memberPort < 1 { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = ibm-NLB vmGroup Port provides an port of between 1 and 65535")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - updateMaps := make(map[string]interface{}) - updateMaps["name"] = generatePoolName(vmGroup.Port) - - updatePoolOption := vpcv1.UpdateLoadBalancerPoolOptions{} - updatePoolOption.SetID(updatePoolId) - updatePoolOption.SetLoadBalancerID(updateNLBId) - updatePoolOption.SetLoadBalancerPoolPatch(updateMaps) - - _, err = nlbHandler.checkUpdatableNLB(updateNLBId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - _, _, err = nlbHandler.VpcService.UpdateLoadBalancerPoolWithContext(nlbHandler.Ctx, &updatePoolOption) - - _, err = nlbHandler.checkUpdatableNLB(updateNLBId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} - poolMemberListOptions.SetLoadBalancerID(updateNLBId) - poolMemberListOptions.SetPoolID(updatePoolId) - - poolAllMembers, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - vmIIDs, err := nlbHandler.getAllVMIIDsByMembers(poolAllMembers.Members) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - vmGroup.VMs = &vmIIDs - - memberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(vmGroup) - updateMemberOption := vpcv1.ReplaceLoadBalancerPoolMembersOptions{} - updateMemberOption.SetPoolID(updatePoolId) - updateMemberOption.SetLoadBalancerID(updateNLBId) - updateMemberOption.SetMembers(memberArrayOption) - - _, _, err = nlbHandler.VpcService.ReplaceLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &updateMemberOption) - - _, err = nlbHandler.checkUpdatableNLB(updateNLBId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - } - rawNLB, err = nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - info, err := nlbHandler.setterNLB(rawNLB) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - LoggingInfo(hiscallInfo, start) - return info.VMGroup, nil -} -func (nlbHandler *IbmNLBHandler) AddVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (irs.VMGroupInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "AddVMs()") - start := call.Start() - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = vmGroup does not exist within that NLB")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - updatePoolId := *rawNLB.Pools[0].ID - updateNLBId := *rawNLB.ID - - // Current vmGroup - vmGroup, err := nlbHandler.getVMGroup(rawNLB) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - currentVMIIDs := *vmGroup.VMs - addedVm := *vmIIDs - for _, addVMIId := range addedVm { - for _, currentIId := range currentVMIIDs { - if strings.EqualFold(addVMIId.NameId, currentIId.NameId) { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = can't add already exist vm")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - } - } - - addedVm = append(currentVMIIDs, addedVm...) - vmGroup.VMs = &addedVm - - memberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(vmGroup) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - - updateMemberOption := vpcv1.ReplaceLoadBalancerPoolMembersOptions{} - updateMemberOption.SetPoolID(updatePoolId) - updateMemberOption.SetLoadBalancerID(updateNLBId) - updateMemberOption.SetMembers(memberArrayOption) - - _, _, err = nlbHandler.VpcService.ReplaceLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &updateMemberOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - updatedNLB, err := nlbHandler.checkUpdatableNLB(updateNLBId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - info, err := nlbHandler.setterNLB(updatedNLB) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.VMGroupInfo{}, changeErr - } - LoggingInfo(hiscallInfo, start) - return info.VMGroup, nil -} -func (nlbHandler *IbmNLBHandler) RemoveVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "RemoveVMs()") - start := call.Start() - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { - changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = vmGroup does not exist within that NLB")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - - updatePoolId := *rawNLB.Pools[0].ID - updateNLBId := *rawNLB.ID - - // Current vmGroup - vmGroup, err := nlbHandler.getVMGroup(rawNLB) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - - currentVMIIDs := *vmGroup.VMs - - removedIIDs := *vmIIDs - for _, removedVMIId := range removedIIDs { - existCheck := false - for _, currentIId := range currentVMIIDs { - if strings.EqualFold(removedVMIId.NameId, currentIId.NameId) { - existCheck = true - break - } - } - if !existCheck { - changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = can't remove a vm that does not exist")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - - } - var updatevmIId []irs.IID - for _, currentIId := range currentVMIIDs { - removeCheck := false - for _, removedVMIId := range removedIIDs { - if strings.EqualFold(removedVMIId.NameId, currentIId.NameId) { - removeCheck = true - break - } - } - if !removeCheck { - updatevmIId = append(updatevmIId, currentIId) - } - } - - vmGroup.VMs = &updatevmIId - - updateMemberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(vmGroup) - - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - updateMemberOption := vpcv1.ReplaceLoadBalancerPoolMembersOptions{} - updateMemberOption.SetPoolID(updatePoolId) - updateMemberOption.SetLoadBalancerID(updateNLBId) - updateMemberOption.SetMembers(updateMemberArrayOption) - - _, _, err = nlbHandler.VpcService.ReplaceLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &updateMemberOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - _, err = nlbHandler.checkUpdatableNLB(updateNLBId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return false, changeErr - } - LoggingInfo(hiscallInfo, start) - return true, nil -} -func (nlbHandler *IbmNLBHandler) GetVMGroupHealthInfo(nlbIID irs.IID) (irs.HealthInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "GetVMGroupHealthInfo()") - start := call.Start() - - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthInfo{}, changeErr - } - if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { - changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = VMGroup does not exist within that NLB")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthInfo{}, changeErr - } - - updatePoolId := *rawNLB.Pools[0].ID - updateNLBId := *rawNLB.ID - - poolOption := vpcv1.GetLoadBalancerPoolOptions{} - poolOption.SetLoadBalancerID(updateNLBId) - poolOption.SetID(updatePoolId) - - rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthInfo{}, changeErr - } - if rawPool.Members == nil || len(rawPool.Members) < 1 { - // not exist - return irs.HealthInfo{}, nil - } - - poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} - poolMemberListOptions.SetLoadBalancerID(updateNLBId) - poolMemberListOptions.SetPoolID(updatePoolId) - - members, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthInfo{}, changeErr - } - info, err := nlbHandler.getHealthInfoByMembers(members.Members) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthInfo{}, changeErr - } - LoggingInfo(hiscallInfo, start) - return info, nil -} -func (nlbHandler *IbmNLBHandler) ChangeHealthCheckerInfo(nlbIID irs.IID, healthChecker irs.HealthCheckerInfo) (irs.HealthCheckerInfo, error) { - hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "ChangeHealthCheckerInfo()") - start := call.Start() - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = VMGroup does not exist within that NLB")) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - updatePoolId := *rawNLB.Pools[0].ID - updateNLBId := *rawNLB.ID - - poolOption := vpcv1.GetLoadBalancerPoolOptions{} - poolOption.SetLoadBalancerID(updateNLBId) - poolOption.SetID(updatePoolId) - - rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - - currentHealthCheckerInfo, err := convertHealthMonitorToHealthCheckerInfo(rawPool.HealthMonitor) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - if reflect.DeepEqual(healthChecker, currentHealthCheckerInfo) { - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - info, err := nlbHandler.setterNLB(rawNLB) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - // not Update - return info.HealthChecker, nil - } else { - poolHealthOption, err := convertCBHealthToIbmHealth(healthChecker) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - updateMaps := make(map[string]interface{}) - updateMaps["health_monitor"] = &poolHealthOption - - updatePoolOption := vpcv1.UpdateLoadBalancerPoolOptions{} - updatePoolOption.SetID(updatePoolId) - updatePoolOption.SetLoadBalancerID(updateNLBId) - updatePoolOption.SetLoadBalancerPoolPatch(updateMaps) - - _, err = nlbHandler.checkUpdatableNLB(updateNLBId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - _, _, err = nlbHandler.VpcService.UpdateLoadBalancerPoolWithContext(nlbHandler.Ctx, &updatePoolOption) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - _, err = nlbHandler.checkUpdatableNLB(updateNLBId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - } - rawNLB, err = nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - info, err := nlbHandler.setterNLB(rawNLB) - if err != nil { - changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) - cblogger.Error(changeErr.Error()) - LoggingError(hiscallInfo, changeErr) - return irs.HealthCheckerInfo{}, changeErr - } - LoggingInfo(hiscallInfo, start) - return info.HealthChecker, nil -} - -func checkVmGroupHealth(health string) bool { - if health == "" { - return false - } - if NLBVMStatus(health) == NLBVMStatusOK { - return true - } - return false -} - -func (nlbHandler *IbmNLBHandler) setterNLB(nlb vpcv1.LoadBalancer) (*irs.NLBInfo, error) { - nlbInfo := irs.NLBInfo{ - IId: irs.IID{ - NameId: *nlb.Name, - SystemId: *nlb.ID, - }, - Scope: string(NLBRegionType), - Type: string(NLBPublicType), - } - - if !*nlb.IsPublic { - nlbInfo.Type = string(NLBInternalType) - } - - var apiCallFunctions []func(rawNlb vpcv1.LoadBalancer, irsNlb *irs.NLBInfo) error - // define and register get VPC IID - apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { - vpcIId, err := nlbHandler.getVPCIID(nlbInner) - if err != nil { - return err - } - nlbInfoInner.VpcIID = vpcIId - return nil - }) - // define and register get VM Group - apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { - vmGroup, err := nlbHandler.getVMGroup(nlb) - if err != nil { - return err - } - nlbInfo.VMGroup = vmGroup - return nil - }) - // define and register get Listener - apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { - listenerInfo, err := nlbHandler.getListenerInfo(nlb) - if err != nil { - return err - } - nlbInfo.Listener = listenerInfo - return nil - }) - // define and register get HealthChecker - apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { - healthCheckerInfo, err := nlbHandler.getHealthCheckerInfo(nlb) - if err != nil { - return err - } - nlbInfo.HealthChecker = healthCheckerInfo - return nil - }) - - // prepare api call - var wait sync.WaitGroup - wait.Add(len(apiCallFunctions)) - var errList []string - - // define api call done behaviour - callAndWaitGroup := func(call func(rawNlb vpcv1.LoadBalancer, irsNlb *irs.NLBInfo) error) { - defer wait.Done() - if err := call(nlb, &nlbInfo); err != nil { - errList = append(errList, err.Error()) - } - } - - // asynchronously call registered apis - for _, apiCallFunction := range apiCallFunctions { - go callAndWaitGroup(apiCallFunction) - } - - // wait for all registered api call is done - wait.Wait() - - // return all errors if occurs - if len(errList) > 0 { - return &irs.NLBInfo{}, errors.New(strings.Join(errList, "\n\t")) - } - - nlbInfo.CreatedTime = time.Time(*nlb.CreatedAt) - - return &nlbInfo, nil -} - -func (nlbHandler *IbmNLBHandler) getRawNLBById(nlbID string) (vpcv1.LoadBalancer, error) { - if nlbID == "" { - return vpcv1.LoadBalancer{}, errors.New("id cannot be an empty value") - } - options := &vpcv1.GetLoadBalancerOptions{} - options.SetID(nlbID) - lb, _, err := nlbHandler.VpcService.GetLoadBalancer(options) - if err != nil { - return vpcv1.LoadBalancer{}, err - } - return *lb, nil -} -func (nlbHandler *IbmNLBHandler) getListenerInfo(nlb vpcv1.LoadBalancer) (irs.ListenerInfo, error) { - listenerInfo := irs.ListenerInfo{} - if len(nlb.PublicIps) > 0 { - listenerInfo.IP = *nlb.PublicIps[0].Address - } - if len(nlb.Listeners) > 0 { - listeners := nlb.Listeners - listenerOptions := vpcv1.GetLoadBalancerListenerOptions{} - listenerOptions.SetID(*listeners[0].ID) - listenerOptions.SetLoadBalancerID(*nlb.ID) - listener, _, err := nlbHandler.VpcService.GetLoadBalancerListenerWithContext(nlbHandler.Ctx, &listenerOptions) - if err != nil { - return irs.ListenerInfo{}, err - } - listenerInfo.CspID = *listener.ID - listenerInfo.Protocol = strings.ToUpper(*listener.Protocol) - listenerInfo.Port = strconv.Itoa(int(*listener.Port)) - } - return listenerInfo, nil -} -func (nlbHandler *IbmNLBHandler) getVPCIID(nlb vpcv1.LoadBalancer) (irs.IID, error) { - if len(nlb.Subnets) < 1 { - return irs.IID{}, errors.New("not found Subnets") - } - cbOnlyOneSubnet := nlb.Subnets[0] - - getSubnetOptions := vpcv1.GetSubnetOptions{} - getSubnetOptions.SetID(*cbOnlyOneSubnet.ID) - // TODO : VPC 정보 GET - rawSubnet, _, err := nlbHandler.VpcService.GetSubnetWithContext(nlbHandler.Ctx, &getSubnetOptions) - if err != nil { - return irs.IID{}, errors.New("not found Subnets") - } - if rawSubnet.VPC != nil { - return irs.IID{ - NameId: *rawSubnet.VPC.Name, - SystemId: *rawSubnet.VPC.ID, - }, nil - } - return irs.IID{}, errors.New("not found Subnets") -} - -func (nlbHandler *IbmNLBHandler) getHealthCheckerInfo(nlb vpcv1.LoadBalancer) (irs.HealthCheckerInfo, error) { - healthCheckerInfo := irs.HealthCheckerInfo{} - if len(nlb.Pools) > 0 { - backendPools := nlb.Pools - getPoolOption := vpcv1.GetLoadBalancerPoolOptions{} - getPoolOption.SetID(*backendPools[0].ID) - getPoolOption.SetLoadBalancerID(*nlb.ID) - cbOnlyOneBackendPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &getPoolOption) - if err != nil { - return irs.HealthCheckerInfo{}, err - } - healthCheckerInfo, err = convertHealthMonitorToHealthCheckerInfo(cbOnlyOneBackendPool.HealthMonitor) - if err != nil { - return irs.HealthCheckerInfo{}, err - } - } else { - return healthCheckerInfo, errors.New("VMGroup does not exist within that NLB") - } - return healthCheckerInfo, nil -} - -func convertHealthMonitorToHealthCheckerInfo(rawHealthMonitor *vpcv1.LoadBalancerPoolHealthMonitor) (irs.HealthCheckerInfo, error) { - healthCheckerInfo := irs.HealthCheckerInfo{} - if rawHealthMonitor != nil { - port := "-1" - if rawHealthMonitor.Port != nil { - port = strconv.Itoa(int(*rawHealthMonitor.Port)) - } - healthCheckerInfo.Port = port - healthCheckerInfo.Protocol = strings.ToUpper(*rawHealthMonitor.Type) - healthCheckerInfo.Interval = int(*rawHealthMonitor.Delay) - healthCheckerInfo.Threshold = int(*rawHealthMonitor.MaxRetries) - healthCheckerInfo.Timeout = int(*rawHealthMonitor.Timeout) - return healthCheckerInfo, nil - } - return healthCheckerInfo, errors.New("not exist HealthMonitor") -} - -func getCreateListenerOptions(nlbReqInfo irs.NLBInfo, poolName *string) ([]vpcv1.LoadBalancerListenerPrototypeLoadBalancerContext, error) { - if poolName == nil || *poolName == "" { - return nil, errors.New("invalid PoolName") - } - listenerDefaultPoolName := *poolName - listenerPort, err := strconv.Atoi(nlbReqInfo.Listener.Port) - if err != nil { - return nil, err - } - if listenerPort > 65535 || listenerPort < 1 { - return nil, errors.New("ibm-NLB Listener provides an port of between 1 and 65535") - } - - listenerPort64 := int64(listenerPort) - - listenerProtocol := "" - switch strings.ToLower(nlbReqInfo.Listener.Protocol) { - case "tcp", "udp": - listenerProtocol = strings.ToLower(nlbReqInfo.Listener.Protocol) - default: - return nil, errors.New("ibm-NLB Listener provides only TCP and UDP protocols") - } - - listener := vpcv1.LoadBalancerListenerPrototypeLoadBalancerContext{ - Port: &listenerPort64, - Protocol: &listenerProtocol, - DefaultPool: &vpcv1.LoadBalancerPoolIdentityByName{ - Name: &listenerDefaultPoolName, - }, - } - - var listenerArray = []vpcv1.LoadBalancerListenerPrototypeLoadBalancerContext{ - listener, - } - return listenerArray, nil -} - -func (nlbHandler *IbmNLBHandler) getCreatePoolOptions(nlbReqInfo irs.NLBInfo) ([]vpcv1.LoadBalancerPoolPrototype, error) { - // memberOption := vpcv1.LoadBalancerPoolMemberTargetPrototype{} - var poolArray []vpcv1.LoadBalancerPoolPrototype - - memberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(nlbReqInfo.VMGroup) - if err != nil { - return nil, err - } - - poolHealthOption, err := convertCBHealthToIbmHealth(nlbReqInfo.HealthChecker) - if err != nil { - return nil, err - } - - poolAlgorithm := "round_robin" - poolProtocol := "" - switch strings.ToLower(nlbReqInfo.VMGroup.Protocol) { - case "tcp", "udp": - poolProtocol = strings.ToLower(nlbReqInfo.VMGroup.Protocol) - default: - return nil, errors.New("ibm-NLB VMGroup provides only TCP and UDP protocols") - } - - poolName := generatePoolName(nlbReqInfo.VMGroup.Port) - - poolOption := vpcv1.LoadBalancerPoolPrototype{ - Algorithm: core.StringPtr(poolAlgorithm), - Protocol: core.StringPtr(poolProtocol), - Name: core.StringPtr(poolName), - HealthMonitor: &poolHealthOption, - Members: memberArrayOption, - } - poolArray = append(poolArray, poolOption) - return poolArray, nil -} - -func (nlbHandler *IbmNLBHandler) convertCBVMGroupToIbmPoolMember(vmGroup irs.VMGroupInfo) ([]vpcv1.LoadBalancerPoolMemberPrototype, error) { - vms := *vmGroup.VMs - memberPort, err := strconv.Atoi(vmGroup.Port) - if err != nil { - return nil, err - } - if memberPort > 65535 || memberPort < 1 { - return nil, errors.New("ibm-NLB vmGroup Port provides an port of between 1 and 65535") - } - memberArrayOption := make([]vpcv1.LoadBalancerPoolMemberPrototype, len(vms)) - memberPort64 := int64(memberPort) - var allVMS *[]vpcv1.Instance - for i, vmIID := range vms { - vmSystemId := vmIID.SystemId - if vmSystemId == "" { - if allVMS == nil { - allVMS, err = nlbHandler.getRawVMList() - if err != nil { - return nil, err - } - } - for _, rawVM := range *allVMS { - if strings.EqualFold(*rawVM.Name, vmIID.NameId) { - vmSystemId = *rawVM.ID - } - } - if vmSystemId == "" { - return nil, errors.New(fmt.Sprintf("not found VM %s", vmIID.NameId)) - } - } - memberArrayOption[i] = vpcv1.LoadBalancerPoolMemberPrototype{ - Port: core.Int64Ptr(memberPort64), - Target: &vpcv1.LoadBalancerPoolMemberTargetPrototype{ - ID: core.StringPtr(vmSystemId), - }, - } - } - return memberArrayOption, nil -} - -func convertCBHealthToIbmHealth(healthChecker irs.HealthCheckerInfo) (vpcv1.LoadBalancerPoolHealthMonitorPrototype, error) { - HealthProtocol := "" - switch strings.ToLower(healthChecker.Protocol) { - case "tcp", "http": - HealthProtocol = strings.ToLower(healthChecker.Protocol) - default: - return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides only HTTP and TCP protocols") - } - - HealthDelay := int64(healthChecker.Interval) - if HealthDelay > 60 || HealthDelay < 2 { - return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an interval of between 2 and 60 seconds") - } - HealthMaxRetries := int64(healthChecker.Threshold) - if HealthMaxRetries > 10 || HealthMaxRetries < 1 { - return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an Threshold of between 1 and 10") - } - HealthTimeOut := int64(healthChecker.Timeout) - if HealthTimeOut > 59 || HealthTimeOut < 1 { - return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an Timeout of between 1 and 59 seconds") - } - HealthPort, err := strconv.Atoi(healthChecker.Port) - if err != nil { - return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, err - } - if HealthPort > 65535 || HealthPort < 1 { - return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an port of between 1 and 65535") - } - - HealthPort64 := int64(HealthPort) - opts := vpcv1.LoadBalancerPoolHealthMonitorPrototype{ - Type: core.StringPtr(HealthProtocol), - Delay: core.Int64Ptr(HealthDelay), - MaxRetries: core.Int64Ptr(HealthMaxRetries), - Timeout: core.Int64Ptr(HealthTimeOut), - Port: core.Int64Ptr(HealthPort64), - } - if HealthProtocol == "http" { - opts.URLPath = core.StringPtr("/") - } - return opts, nil -} - -func (nlbHandler *IbmNLBHandler) getMatchVMIIdAndFirstSubnetId(vmIIDs *[]irs.IID) ([]irs.IID, string, error) { - // nameId => systemID, NameId - if vmIIDs == nil || len(*vmIIDs) < 1 { - return nil, "", errors.New("vmIIDs is empty") - } - allVMS, err := nlbHandler.getRawVMList() - if err != nil { - return nil, "", err - } - subnetId := "" - vms := *vmIIDs - for i, vmIID := range vms { - errCheck := true - for _, rawVM := range *allVMS { - if strings.EqualFold(vmIID.NameId, *rawVM.Name) { - if subnetId == "" { - subnetId = *rawVM.PrimaryNetworkInterface.Subnet.ID - } - vms[i].SystemId = *rawVM.ID - errCheck = false - break - } - } - if errCheck { - return nil, "", errors.New("not found vm") - } - } - return vms, subnetId, nil -} - -func (nlbHandler *IbmNLBHandler) createNLB(nlbReqInfo irs.NLBInfo) (vpcv1.LoadBalancer, error) { - exist, err := nlbHandler.existNLBByName(nlbReqInfo.IId.NameId) - if err != nil { - return vpcv1.LoadBalancer{}, err - } - if exist { - return vpcv1.LoadBalancer{}, errors.New(fmt.Sprintf("already exist NLB : %s", nlbReqInfo.IId.NameId)) - } - - vms, subnetId, err := nlbHandler.getMatchVMIIdAndFirstSubnetId(nlbReqInfo.VMGroup.VMs) - - if err != nil { - return vpcv1.LoadBalancer{}, err - } - - nlbReqInfo.VMGroup.VMs = &vms - - // Set - BaseOption - createNLBOptions := vpcv1.CreateLoadBalancerOptions{} - createNLBOptions.SetIsPublic(true) - createNLBOptions.SetName(nlbReqInfo.IId.NameId) - LoadBalancerProfileName := "network-fixed" - createNLBOptions.SetProfile(&vpcv1.LoadBalancerProfileIdentity{ - Name: &LoadBalancerProfileName, - }) - - // Set - subnet - var subnetArray = []vpcv1.SubnetIdentityIntf{ - &vpcv1.SubnetIdentity{ - ID: &subnetId, - }, - } - - poolArray, err := nlbHandler.getCreatePoolOptions(nlbReqInfo) - if err != nil { - return vpcv1.LoadBalancer{}, err - } - poolName := poolArray[0].Name - - listenerArray, err := getCreateListenerOptions(nlbReqInfo, poolName) - if err != nil { - return vpcv1.LoadBalancer{}, err - } - - createNLBOptions.SetSubnets(subnetArray) - createNLBOptions.SetPools(poolArray) - createNLBOptions.SetListeners(listenerArray) - - nlb, _, err := nlbHandler.VpcService.CreateLoadBalancerWithContext(nlbHandler.Ctx, &createNLBOptions) - if err != nil { - return vpcv1.LoadBalancer{}, err - } - _, err = nlbHandler.checkUpdatableNLB(*nlb.ID) - if err != nil { - return vpcv1.LoadBalancer{}, err - } - return *nlb, nil -} - -func (nlbHandler *IbmNLBHandler) getVMGroup(nlb vpcv1.LoadBalancer) (irs.VMGroupInfo, error) { - vmGroup := irs.VMGroupInfo{} - if len(nlb.Pools) > 0 { - backendPools := nlb.Pools - getPoolOption := vpcv1.GetLoadBalancerPoolOptions{} - getPoolOption.SetID(*backendPools[0].ID) - getPoolOption.SetLoadBalancerID(*nlb.ID) - cbOnlyOneBackendPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &getPoolOption) - if err != nil { - return irs.VMGroupInfo{}, err - } - vmGroup.CspID = *cbOnlyOneBackendPool.ID - vmGroup.Protocol = strings.ToUpper(*cbOnlyOneBackendPool.Protocol) - - poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} - poolMemberListOptions.SetLoadBalancerID(*nlb.ID) - poolMemberListOptions.SetPoolID(*cbOnlyOneBackendPool.ID) - - poolAllMembers, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) - if err != nil { - return irs.VMGroupInfo{}, err - } - vmIIDs, err := nlbHandler.getAllVMIIDsByMembers(poolAllMembers.Members) - if err != nil { - return irs.VMGroupInfo{}, err - } - vmGroup.VMs = &vmIIDs - portInt, err := nlbHandler.getPoolPort(*nlb.ID, *cbOnlyOneBackendPool.ID) - if err != nil { - return irs.VMGroupInfo{}, err - } - vmGroup.Port = strconv.Itoa(portInt) - } - return vmGroup, nil -} - -func getMemberTarget(member vpcv1.LoadBalancerPoolMember) (vpcv1.LoadBalancerPoolMemberTarget, error) { - target := member.Target - - targetJsonBytes, err := json.Marshal(target) - if err != nil { - return vpcv1.LoadBalancerPoolMemberTarget{}, err - } - var targetMember vpcv1.LoadBalancerPoolMemberTarget - err = json.Unmarshal(targetJsonBytes, &targetMember) - if err != nil { - return vpcv1.LoadBalancerPoolMemberTarget{}, err - } - return targetMember, nil -} - -func (nlbHandler *IbmNLBHandler) existNLBByName(nlbName string) (bool, error) { - if nlbName == "" { - return false, errors.New("name cannot be an empty value") - } - allNLBList, err := nlbHandler.getRawNLBList() - if err != nil { - return false, err - } - for _, rawNLB := range *allNLBList { - if strings.EqualFold(nlbName, *rawNLB.Name) { - return true, nil - } - } - return false, nil -} - -func (nlbHandler *IbmNLBHandler) getRawNLBByName(nlbName string) (vpcv1.LoadBalancer, error) { - if nlbName == "" { - return vpcv1.LoadBalancer{}, errors.New("name cannot be an empty value") - } - allNLBList, err := nlbHandler.getRawNLBList() - if err != nil { - return vpcv1.LoadBalancer{}, err - } - for _, rawNLB := range *allNLBList { - if strings.EqualFold(nlbName, *rawNLB.Name) { - return rawNLB, nil - } - } - return vpcv1.LoadBalancer{}, errors.New(fmt.Sprintf("not found NLB : %s", nlbName)) -} - -func (nlbHandler *IbmNLBHandler) getRawVMList() (*[]vpcv1.Instance, error) { - options := &vpcv1.ListInstancesOptions{} - var list []vpcv1.Instance - res, _, err := nlbHandler.VpcService.ListInstancesWithContext(nlbHandler.Ctx, options) - if err != nil { - return nil, err - } - - for { - if len(res.Instances) > 0 { - list = append(list, res.Instances...) - } else { - break - } - nextStr := "" - if res.Next != nil && res.Next.Href != nil { - nextStr, _ = getNextHref(*res.Next.Href) - } - if nextStr != "" { - options2 := &vpcv1.ListInstancesOptions{ - Start: core.StringPtr(nextStr), - } - res, _, err = nlbHandler.VpcService.ListInstancesWithContext(nlbHandler.Ctx, options2) - if err != nil { - return nil, err - } - } else { - break - } - } - return &list, nil -} - -func (nlbHandler *IbmNLBHandler) checkUpdatableNLB(nlbId string) (vpcv1.LoadBalancer, error) { - if nlbId == "" { - return vpcv1.LoadBalancer{}, errors.New("") - } - updatableCheckNLBOptions := vpcv1.GetLoadBalancerOptions{} - updatableCheckNLBOptions.SetID(nlbId) - var updatableCheckNLB *vpcv1.LoadBalancer - var err error - - curRetryCnt := 0 - maxRetryCnt := 240 - for { - updatableCheckNLB, _, err = nlbHandler.VpcService.GetLoadBalancerWithContext(nlbHandler.Ctx, &updatableCheckNLBOptions) - if err == nil && *updatableCheckNLB.ProvisioningStatus == "active" { - return *updatableCheckNLB, nil - } - time.Sleep(2 * time.Second) - curRetryCnt++ - if curRetryCnt > maxRetryCnt { - return vpcv1.LoadBalancer{}, errors.New(fmt.Sprintf("Failed to Update NLB VMGroup. err = exceeded maximum retry count %d", maxRetryCnt)) - } - } -} - -func (nlbHandler *IbmNLBHandler) getRawNLBList() (*[]vpcv1.LoadBalancer, error) { - options := &vpcv1.ListLoadBalancersOptions{} - var list []vpcv1.LoadBalancer - res, _, err := nlbHandler.VpcService.ListLoadBalancersWithContext(nlbHandler.Ctx, options) - if err != nil { - return nil, err - } - - for { - if len(res.LoadBalancers) > 0 { - list = append(list, res.LoadBalancers...) - } else { - break - } - nextStr := "" - if res.Next != nil && res.Next.Href != nil { - nextStr, _ = getNextHref(*res.Next.Href) - } - if nextStr != "" { - listNLBOptions2 := &vpcv1.ListLoadBalancersOptions{ - Start: core.StringPtr(nextStr), - } - res, _, err = nlbHandler.VpcService.ListLoadBalancersWithContext(nlbHandler.Ctx, listNLBOptions2) - if err != nil { - return nil, err - } - } else { - break - } - } - return &list, nil -} - -func (nlbHandler *IbmNLBHandler) cleanerNLB(nlbIID irs.IID) (bool, error) { - // Exist? - exist, err := nlbHandler.existNLBByName(nlbIID.NameId) - if err != nil { - return false, err - } - if !exist { - return false, errors.New("not found nlb") - } - rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) - if err != nil { - return false, err - } - nlbId := *rawNLB.ID - nlbDeleteOption := vpcv1.DeleteLoadBalancerOptions{} - nlbDeleteOption.SetID(*rawNLB.ID) - _, err = nlbHandler.VpcService.DeleteLoadBalancerWithContext(nlbHandler.Ctx, &nlbDeleteOption) - if err != nil { - return false, err - } - _, err = nlbHandler.waitDeletedNLB(nlbId) - if err != nil { - return false, err - } - return true, nil -} - -func (nlbHandler *IbmNLBHandler) waitDeletedNLB(nlbId string) (bool, error) { - curRetryCnt := 0 - maxRetryCnt := 240 - for { - curRetryCnt++ - list, err := nlbHandler.getRawNLBList() - if err != nil { - return false, err - } - exist := false - for _, rawNLb := range *list { - if *rawNLb.ID == nlbId { - exist = true - } - } - if !exist { - return true, nil - } - time.Sleep(2 * time.Second) - if curRetryCnt > maxRetryCnt { - return false, errors.New(fmt.Sprintf("failed to create NLB, exceeded maximum retry count %d", maxRetryCnt)) - } - } -} - -func (nlbHandler *IbmNLBHandler) getHealthInfoByMembers(members []vpcv1.LoadBalancerPoolMember) (irs.HealthInfo, error) { - var allVMS *[]vpcv1.Instance - healthyVMs := make([]irs.IID, 0) - unHealthyVMs := make([]irs.IID, 0) - vmIIDs := make([]irs.IID, len(members)) - for i, member := range members { - memberTarget, err := getMemberTarget(member) - if err != nil { - return irs.HealthInfo{}, err - } - // targetMember.ID = instanceID - if memberTarget.ID != nil { - instanceOptions := &vpcv1.GetInstanceOptions{} - instanceOptions.SetID(*memberTarget.ID) - rawVM, _, err := nlbHandler.VpcService.GetInstance(instanceOptions) - if err != nil { - return irs.HealthInfo{}, err - } - vmIIDs[i] = irs.IID{ - NameId: *rawVM.Name, - SystemId: *rawVM.ID, - } - } else if memberTarget.Address != nil { - if allVMS == nil { - allVMS, err = nlbHandler.getRawVMList() - if err != nil { - return irs.HealthInfo{}, err - } - } - for _, rawVM := range *allVMS { - if strings.EqualFold(*rawVM.PrimaryNetworkInterface.PrimaryIpv4Address, *memberTarget.Address) { - vmIIDs[i] = irs.IID{ - NameId: *rawVM.Name, - SystemId: *rawVM.ID, - } - } - } - } - if checkVmGroupHealth(*member.Health) { - healthyVMs = append(healthyVMs, vmIIDs[i]) - } else { - unHealthyVMs = append(unHealthyVMs, vmIIDs[i]) - } - } - return irs.HealthInfo{ - AllVMs: &vmIIDs, - HealthyVMs: &healthyVMs, - UnHealthyVMs: &unHealthyVMs, - }, nil -} - -func (nlbHandler *IbmNLBHandler) getPoolPort(nlbId string, poolId string) (int, error) { - poolOption := vpcv1.GetLoadBalancerPoolOptions{} - poolOption.SetLoadBalancerID(nlbId) - poolOption.SetID(poolId) - - rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) - if err != nil { - return 0, err - } - vmGroupPort, err := getPoolPortByPoolName(*rawPool.Name) - if err != nil { - poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} - poolMemberListOptions.SetLoadBalancerID(nlbId) - poolMemberListOptions.SetPoolID(poolId) - poolAllMembers, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) - if err != nil { - return 0, err - } - if len(poolAllMembers.Members) > 0 { - vmGroupPort = int(*poolAllMembers.Members[0].Port) - } else { - return 0, err - } - } - return vmGroupPort, nil -} - -func (nlbHandler *IbmNLBHandler) getAllVMIIDsByMembers(members []vpcv1.LoadBalancerPoolMember) ([]irs.IID, error) { - var allVMS *[]vpcv1.Instance - vmIIDs := make([]irs.IID, len(members)) - for i, member := range members { - memberTarget, err := getMemberTarget(member) - if err != nil { - return nil, err - } - // targetMember.ID = instanceID - if memberTarget.ID != nil { - instanceOptions := &vpcv1.GetInstanceOptions{} - instanceOptions.SetID(*memberTarget.ID) - rawVM, _, err := nlbHandler.VpcService.GetInstance(instanceOptions) - if err != nil { - return nil, err - } - vmIIDs[i] = irs.IID{ - NameId: *rawVM.Name, - SystemId: *rawVM.ID, - } - } else if memberTarget.Address != nil { - if allVMS == nil { - allVMS, err = nlbHandler.getRawVMList() - if err != nil { - return nil, err - } - } - for _, rawVM := range *allVMS { - if strings.EqualFold(*rawVM.PrimaryNetworkInterface.PrimaryIpv4Address, *memberTarget.Address) { - vmIIDs[i] = irs.IID{ - NameId: *rawVM.Name, - SystemId: *rawVM.ID, - } - } - } - } - } - return vmIIDs, nil -} - -func getPoolPortByPoolName(poolName string) (int, error) { - splits := strings.Split(poolName, "-") - if len(splits) != 3 { - return 0, errors.New("unable to get port information for vmGroup") - } - return strconv.Atoi(splits[1]) -} - -func generatePoolName(port string) string { - prefix := fmt.Sprintf("backend-%s", port) - return generateRandName(prefix) -} - -func getNextHref(str string) (string, error) { - href := str - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - return "", errors.New("NOT NEXT") -} +package resources + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/vpc-go-sdk/vpcv1" + 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" + "net/url" + "reflect" + "strconv" + "strings" + "sync" + "time" +) + +type NLBType string +type NLBScope string +type NLBVMStatus string + +const ( + NLBPublicType NLBType = "PUBLIC" + NLBInternalType NLBType = "INTERNAL" + NLBGlobalType NLBScope = "GLOBAL" + NLBRegionType NLBScope = "REGION" + NLBVMStatusFault NLBVMStatus = "faulted" + NLBVMStatusOK NLBVMStatus = "ok" + NLBVMStatusUnknown NLBVMStatus = "unknown" +) + +type IbmNLBHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + VpcService *vpcv1.VpcV1 + Ctx context.Context +} + +// ------ NLB Management +func (nlbHandler *IbmNLBHandler) CreateNLB(nlbReqInfo irs.NLBInfo) (irs.NLBInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbReqInfo.IId.NameId, "CreateNLB()") + start := call.Start() + rawNLB, err := nlbHandler.createNLB(nlbReqInfo) + if err != nil { + nlbHandler.cleanerNLB(nlbReqInfo.IId) + createErr := errors.New(fmt.Sprintf("Failed to Create NLB. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.NLBInfo{}, createErr + } + info, err := nlbHandler.setterNLB(rawNLB) + if err != nil { + nlbHandler.cleanerNLB(nlbReqInfo.IId) + createErr := errors.New(fmt.Sprintf("Failed to Create NLB. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.NLBInfo{}, createErr + } + LoggingInfo(hiscallInfo, start) + + if nlbReqInfo.TagList != nil && len(nlbReqInfo.TagList) > 0 { + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range nlbReqInfo.TagList{ + _, err := tagHandler.AddTag("NLB", nlbReqInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on NLB err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + return *info, nil +} +func (nlbHandler *IbmNLBHandler) ListNLB() ([]*irs.NLBInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", "NLB", "ListNLB()") + start := call.Start() + + nlbList, err := nlbHandler.getRawNLBList() + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List NLB. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + + nlbInfoList := make([]*irs.NLBInfo, len(*nlbList)) + + var wait sync.WaitGroup + wait.Add(len(*nlbList)) + var errList []string + + for i, nlb := range *nlbList { + go func() { + defer wait.Done() + info, getErr := nlbHandler.setterNLB(nlb) + if getErr != nil { + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + errList = append(errList, getErr.Error()) + } + nlbInfoList[i] = info + }() + } + wait.Wait() + LoggingInfo(hiscallInfo, start) + + if len(errList) > 0 { + errList = append([]string{"Failed to List NLB. err = "}, errList...) + getErr := errors.New(fmt.Sprintf("Failed to List NLB. err = %s", strings.Join(errList, "\n\t"))) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + + return nlbInfoList, nil +} +func (nlbHandler *IbmNLBHandler) GetNLB(nlbIID irs.IID) (irs.NLBInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "GetNLB()") + start := call.Start() + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get NLB. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.NLBInfo{}, getErr + } + info, err := nlbHandler.setterNLB(rawNLB) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get NLB. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.NLBInfo{}, getErr + } + LoggingInfo(hiscallInfo, start) + return *info, err +} +func (nlbHandler *IbmNLBHandler) DeleteNLB(nlbIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "DeleteNLB()") + start := call.Start() + + _, err := nlbHandler.cleanerNLB(nlbIID) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete NLB. err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete NLB Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + return true, nil +} + +// ------ Frontend Control +func (nlbHandler *IbmNLBHandler) ChangeListener(nlbIID irs.IID, listener irs.ListenerInfo) (irs.ListenerInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "ChangeListener()") + start := call.Start() + + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + nlbId := *rawNLB.ID + if rawNLB.Listeners == nil || len(rawNLB.Listeners) < 1 { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = listener does not exist within that NLB")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + ListenerOption := vpcv1.GetLoadBalancerListenerOptions{} + ListenerOption.SetLoadBalancerID(*rawNLB.ID) + ListenerOption.SetID(*rawNLB.Listeners[0].ID) + rawListener, _, err := nlbHandler.VpcService.GetLoadBalancerListenerWithContext(nlbHandler.Ctx, &ListenerOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + if listener.Protocol != "" && !strings.EqualFold(strings.ToUpper(listener.Protocol), strings.ToUpper(*rawListener.Protocol)) { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = changing the protocol of the Listener is not supported.")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + oldListenerPort := int(*rawListener.Port) + listenerPort, err := strconv.Atoi(listener.Port) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + if oldListenerPort != listenerPort { + if listenerPort > 65535 || listenerPort < 1 { + return irs.ListenerInfo{}, errors.New("ibm-NLB Listener provides an port of between 1 and 65535") + } + + listenerPort64 := int64(listenerPort) + + updateMaps := make(map[string]interface{}) + updateMaps["port"] = core.Int64Ptr(listenerPort64) + + updateOption := vpcv1.UpdateLoadBalancerListenerOptions{} + updateOption.SetID(*rawListener.ID) + updateOption.SetLoadBalancerID(nlbId) + updateOption.SetLoadBalancerListenerPatch(updateMaps) + + _, _, err = nlbHandler.VpcService.UpdateLoadBalancerListenerWithContext(nlbHandler.Ctx, &updateOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + + } + updatedRawNLB, err := nlbHandler.checkUpdatableNLB(nlbId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + + info, err := nlbHandler.setterNLB(updatedRawNLB) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.ListenerInfo{}, changeErr + } + LoggingInfo(hiscallInfo, start) + return info.Listener, err +} + +// ------ Backend Control +func (nlbHandler *IbmNLBHandler) ChangeVMGroupInfo(nlbIID irs.IID, vmGroup irs.VMGroupInfo) (irs.VMGroupInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "ChangeVMGroupInfo()") + start := call.Start() + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = VMGroup does not exist within that NLB")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + updatePoolId := *rawNLB.Pools[0].ID + updateNLBId := *rawNLB.ID + + poolOption := vpcv1.GetLoadBalancerPoolOptions{} + poolOption.SetLoadBalancerID(updateNLBId) + poolOption.SetID(updatePoolId) + + rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + vmGroupPort, err := nlbHandler.getPoolPort(updateNLBId, updatePoolId) + + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + if vmGroup.Protocol != "" && !strings.EqualFold(strings.ToUpper(vmGroup.Protocol), strings.ToUpper(*rawPool.Protocol)) { + changeErr := errors.New(fmt.Sprintf("Failed to Change Listener. err = changing the protocol of the Listener is not supported.")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + // 변경시만 업데이트 하도록 + if !strings.EqualFold(vmGroup.Port, strconv.Itoa(vmGroupPort)) { + memberPort, err := strconv.Atoi(vmGroup.Port) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + if memberPort > 65535 || memberPort < 1 { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = ibm-NLB vmGroup Port provides an port of between 1 and 65535")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + updateMaps := make(map[string]interface{}) + updateMaps["name"] = generatePoolName(vmGroup.Port) + + updatePoolOption := vpcv1.UpdateLoadBalancerPoolOptions{} + updatePoolOption.SetID(updatePoolId) + updatePoolOption.SetLoadBalancerID(updateNLBId) + updatePoolOption.SetLoadBalancerPoolPatch(updateMaps) + + _, err = nlbHandler.checkUpdatableNLB(updateNLBId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + _, _, err = nlbHandler.VpcService.UpdateLoadBalancerPoolWithContext(nlbHandler.Ctx, &updatePoolOption) + + _, err = nlbHandler.checkUpdatableNLB(updateNLBId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} + poolMemberListOptions.SetLoadBalancerID(updateNLBId) + poolMemberListOptions.SetPoolID(updatePoolId) + + poolAllMembers, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + vmIIDs, err := nlbHandler.getAllVMIIDsByMembers(poolAllMembers.Members) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + vmGroup.VMs = &vmIIDs + + memberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(vmGroup) + updateMemberOption := vpcv1.ReplaceLoadBalancerPoolMembersOptions{} + updateMemberOption.SetPoolID(updatePoolId) + updateMemberOption.SetLoadBalancerID(updateNLBId) + updateMemberOption.SetMembers(memberArrayOption) + + _, _, err = nlbHandler.VpcService.ReplaceLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &updateMemberOption) + + _, err = nlbHandler.checkUpdatableNLB(updateNLBId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + } + rawNLB, err = nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + info, err := nlbHandler.setterNLB(rawNLB) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change VMGroupInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + LoggingInfo(hiscallInfo, start) + return info.VMGroup, nil +} + +func (nlbHandler *IbmNLBHandler) AddVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (irs.VMGroupInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "AddVMs()") + start := call.Start() + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = vmGroup does not exist within that NLB")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + updatePoolId := *rawNLB.Pools[0].ID + updateNLBId := *rawNLB.ID + + // Current vmGroup + vmGroup, err := nlbHandler.getVMGroup(rawNLB) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + currentVMIIDs := *vmGroup.VMs + addedVm := *vmIIDs + for _, addVMIId := range addedVm { + for _, currentIId := range currentVMIIDs { + if strings.EqualFold(addVMIId.NameId, currentIId.NameId) { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = can't add already exist vm")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + } + } + + addedVm = append(currentVMIIDs, addedVm...) + vmGroup.VMs = &addedVm + + memberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(vmGroup) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + + updateMemberOption := vpcv1.ReplaceLoadBalancerPoolMembersOptions{} + updateMemberOption.SetPoolID(updatePoolId) + updateMemberOption.SetLoadBalancerID(updateNLBId) + updateMemberOption.SetMembers(memberArrayOption) + + _, _, err = nlbHandler.VpcService.ReplaceLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &updateMemberOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + updatedNLB, err := nlbHandler.checkUpdatableNLB(updateNLBId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + info, err := nlbHandler.setterNLB(updatedNLB) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Add VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.VMGroupInfo{}, changeErr + } + LoggingInfo(hiscallInfo, start) + return info.VMGroup, nil +} +func (nlbHandler *IbmNLBHandler) RemoveVMs(nlbIID irs.IID, vmIIDs *[]irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "RemoveVMs()") + start := call.Start() + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { + changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = vmGroup does not exist within that NLB")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + + updatePoolId := *rawNLB.Pools[0].ID + updateNLBId := *rawNLB.ID + + // Current vmGroup + vmGroup, err := nlbHandler.getVMGroup(rawNLB) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + + currentVMIIDs := *vmGroup.VMs + + removedIIDs := *vmIIDs + for _, removedVMIId := range removedIIDs { + existCheck := false + for _, currentIId := range currentVMIIDs { + if strings.EqualFold(removedVMIId.NameId, currentIId.NameId) { + existCheck = true + break + } + } + if !existCheck { + changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = can't remove a vm that does not exist")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + + } + var updatevmIId []irs.IID + for _, currentIId := range currentVMIIDs { + removeCheck := false + for _, removedVMIId := range removedIIDs { + if strings.EqualFold(removedVMIId.NameId, currentIId.NameId) { + removeCheck = true + break + } + } + if !removeCheck { + updatevmIId = append(updatevmIId, currentIId) + } + } + + vmGroup.VMs = &updatevmIId + + updateMemberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(vmGroup) + + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + updateMemberOption := vpcv1.ReplaceLoadBalancerPoolMembersOptions{} + updateMemberOption.SetPoolID(updatePoolId) + updateMemberOption.SetLoadBalancerID(updateNLBId) + updateMemberOption.SetMembers(updateMemberArrayOption) + + _, _, err = nlbHandler.VpcService.ReplaceLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &updateMemberOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + _, err = nlbHandler.checkUpdatableNLB(updateNLBId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Remove VMs. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return false, changeErr + } + LoggingInfo(hiscallInfo, start) + return true, nil +} +func (nlbHandler *IbmNLBHandler) GetVMGroupHealthInfo(nlbIID irs.IID) (irs.HealthInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "GetVMGroupHealthInfo()") + start := call.Start() + + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthInfo{}, changeErr + } + if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { + changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = VMGroup does not exist within that NLB")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthInfo{}, changeErr + } + + updatePoolId := *rawNLB.Pools[0].ID + updateNLBId := *rawNLB.ID + + poolOption := vpcv1.GetLoadBalancerPoolOptions{} + poolOption.SetLoadBalancerID(updateNLBId) + poolOption.SetID(updatePoolId) + + rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthInfo{}, changeErr + } + if rawPool.Members == nil || len(rawPool.Members) < 1 { + // not exist + return irs.HealthInfo{}, nil + } + + poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} + poolMemberListOptions.SetLoadBalancerID(updateNLBId) + poolMemberListOptions.SetPoolID(updatePoolId) + + members, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthInfo{}, changeErr + } + info, err := nlbHandler.getHealthInfoByMembers(members.Members) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Get VMGroupHealthInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthInfo{}, changeErr + } + LoggingInfo(hiscallInfo, start) + return info, nil +} +func (nlbHandler *IbmNLBHandler) ChangeHealthCheckerInfo(nlbIID irs.IID, healthChecker irs.HealthCheckerInfo) (irs.HealthCheckerInfo, error) { + hiscallInfo := GetCallLogScheme(nlbHandler.Region, "NETWORKLOADBALANCE", nlbIID.NameId, "ChangeHealthCheckerInfo()") + start := call.Start() + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + if rawNLB.Pools == nil || len(rawNLB.Pools) < 1 { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = VMGroup does not exist within that NLB")) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + updatePoolId := *rawNLB.Pools[0].ID + updateNLBId := *rawNLB.ID + + poolOption := vpcv1.GetLoadBalancerPoolOptions{} + poolOption.SetLoadBalancerID(updateNLBId) + poolOption.SetID(updatePoolId) + + rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + + currentHealthCheckerInfo, err := convertHealthMonitorToHealthCheckerInfo(rawPool.HealthMonitor) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + if reflect.DeepEqual(healthChecker, currentHealthCheckerInfo) { + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + info, err := nlbHandler.setterNLB(rawNLB) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + // not Update + return info.HealthChecker, nil + } else { + poolHealthOption, err := convertCBHealthToIbmHealth(healthChecker) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + updateMaps := make(map[string]interface{}) + updateMaps["health_monitor"] = &poolHealthOption + + updatePoolOption := vpcv1.UpdateLoadBalancerPoolOptions{} + updatePoolOption.SetID(updatePoolId) + updatePoolOption.SetLoadBalancerID(updateNLBId) + updatePoolOption.SetLoadBalancerPoolPatch(updateMaps) + + _, err = nlbHandler.checkUpdatableNLB(updateNLBId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + _, _, err = nlbHandler.VpcService.UpdateLoadBalancerPoolWithContext(nlbHandler.Ctx, &updatePoolOption) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + _, err = nlbHandler.checkUpdatableNLB(updateNLBId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + } + rawNLB, err = nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + info, err := nlbHandler.setterNLB(rawNLB) + if err != nil { + changeErr := errors.New(fmt.Sprintf("Failed to Change HealthCheckerInfo. err = %s", err.Error())) + cblogger.Error(changeErr.Error()) + LoggingError(hiscallInfo, changeErr) + return irs.HealthCheckerInfo{}, changeErr + } + LoggingInfo(hiscallInfo, start) + return info.HealthChecker, nil +} + +func checkVmGroupHealth(health string) bool { + if health == "" { + return false + } + if NLBVMStatus(health) == NLBVMStatusOK { + return true + } + return false +} + +func (nlbHandler *IbmNLBHandler) setterNLB(nlb vpcv1.LoadBalancer) (*irs.NLBInfo, error) { + nlbInfo := irs.NLBInfo{ + IId: irs.IID{ + NameId: *nlb.Name, + SystemId: *nlb.ID, + }, + Scope: string(NLBRegionType), + Type: string(NLBPublicType), + } + + if !*nlb.IsPublic { + nlbInfo.Type = string(NLBInternalType) + } + + var apiCallFunctions []func(rawNlb vpcv1.LoadBalancer, irsNlb *irs.NLBInfo) error + // define and register get VPC IID + apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { + vpcIId, err := nlbHandler.getVPCIID(nlbInner) + if err != nil { + return err + } + nlbInfoInner.VpcIID = vpcIId + return nil + }) + // define and register get VM Group + apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { + vmGroup, err := nlbHandler.getVMGroup(nlb) + if err != nil { + return err + } + nlbInfo.VMGroup = vmGroup + return nil + }) + // define and register get Listener + apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { + listenerInfo, err := nlbHandler.getListenerInfo(nlb) + if err != nil { + return err + } + nlbInfo.Listener = listenerInfo + return nil + }) + // define and register get HealthChecker + apiCallFunctions = append(apiCallFunctions, func(nlbInner vpcv1.LoadBalancer, nlbInfoInner *irs.NLBInfo) error { + healthCheckerInfo, err := nlbHandler.getHealthCheckerInfo(nlb) + if err != nil { + return err + } + nlbInfo.HealthChecker = healthCheckerInfo + return nil + }) + + // prepare api call + var wait sync.WaitGroup + wait.Add(len(apiCallFunctions)) + var errList []string + + // define api call done behaviour + callAndWaitGroup := func(call func(rawNlb vpcv1.LoadBalancer, irsNlb *irs.NLBInfo) error) { + defer wait.Done() + if err := call(nlb, &nlbInfo); err != nil { + errList = append(errList, err.Error()) + } + } + + // asynchronously call registered apis + for _, apiCallFunction := range apiCallFunctions { + go callAndWaitGroup(apiCallFunction) + } + + // wait for all registered api call is done + wait.Wait() + + // return all errors if occurs + if len(errList) > 0 { + return &irs.NLBInfo{}, errors.New(strings.Join(errList, "\n\t")) + } + + nlbInfo.CreatedTime = time.Time(*nlb.CreatedAt) + + return &nlbInfo, nil +} + +func (nlbHandler *IbmNLBHandler) getRawNLBById(nlbID string) (vpcv1.LoadBalancer, error) { + if nlbID == "" { + return vpcv1.LoadBalancer{}, errors.New("id cannot be an empty value") + } + options := &vpcv1.GetLoadBalancerOptions{} + options.SetID(nlbID) + lb, _, err := nlbHandler.VpcService.GetLoadBalancer(options) + if err != nil { + return vpcv1.LoadBalancer{}, err + } + return *lb, nil +} +func (nlbHandler *IbmNLBHandler) getListenerInfo(nlb vpcv1.LoadBalancer) (irs.ListenerInfo, error) { + listenerInfo := irs.ListenerInfo{} + if len(nlb.PublicIps) > 0 { + listenerInfo.IP = *nlb.PublicIps[0].Address + } + if len(nlb.Listeners) > 0 { + listeners := nlb.Listeners + listenerOptions := vpcv1.GetLoadBalancerListenerOptions{} + listenerOptions.SetID(*listeners[0].ID) + listenerOptions.SetLoadBalancerID(*nlb.ID) + listener, _, err := nlbHandler.VpcService.GetLoadBalancerListenerWithContext(nlbHandler.Ctx, &listenerOptions) + if err != nil { + return irs.ListenerInfo{}, err + } + listenerInfo.CspID = *listener.ID + listenerInfo.Protocol = strings.ToUpper(*listener.Protocol) + listenerInfo.Port = strconv.Itoa(int(*listener.Port)) + } + return listenerInfo, nil +} +func (nlbHandler *IbmNLBHandler) getVPCIID(nlb vpcv1.LoadBalancer) (irs.IID, error) { + if len(nlb.Subnets) < 1 { + return irs.IID{}, errors.New("not found Subnets") + } + cbOnlyOneSubnet := nlb.Subnets[0] + + getSubnetOptions := vpcv1.GetSubnetOptions{} + getSubnetOptions.SetID(*cbOnlyOneSubnet.ID) + // TODO : VPC 정보 GET + rawSubnet, _, err := nlbHandler.VpcService.GetSubnetWithContext(nlbHandler.Ctx, &getSubnetOptions) + if err != nil { + return irs.IID{}, errors.New("not found Subnets") + } + if rawSubnet.VPC != nil { + return irs.IID{ + NameId: *rawSubnet.VPC.Name, + SystemId: *rawSubnet.VPC.ID, + }, nil + } + return irs.IID{}, errors.New("not found Subnets") +} + +func (nlbHandler *IbmNLBHandler) getHealthCheckerInfo(nlb vpcv1.LoadBalancer) (irs.HealthCheckerInfo, error) { + healthCheckerInfo := irs.HealthCheckerInfo{} + if len(nlb.Pools) > 0 { + backendPools := nlb.Pools + getPoolOption := vpcv1.GetLoadBalancerPoolOptions{} + getPoolOption.SetID(*backendPools[0].ID) + getPoolOption.SetLoadBalancerID(*nlb.ID) + cbOnlyOneBackendPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &getPoolOption) + if err != nil { + return irs.HealthCheckerInfo{}, err + } + healthCheckerInfo, err = convertHealthMonitorToHealthCheckerInfo(cbOnlyOneBackendPool.HealthMonitor) + if err != nil { + return irs.HealthCheckerInfo{}, err + } + } else { + return healthCheckerInfo, errors.New("VMGroup does not exist within that NLB") + } + return healthCheckerInfo, nil +} + +func convertHealthMonitorToHealthCheckerInfo(rawHealthMonitor *vpcv1.LoadBalancerPoolHealthMonitor) (irs.HealthCheckerInfo, error) { + healthCheckerInfo := irs.HealthCheckerInfo{} + if rawHealthMonitor != nil { + port := "-1" + if rawHealthMonitor.Port != nil { + port = strconv.Itoa(int(*rawHealthMonitor.Port)) + } + healthCheckerInfo.Port = port + healthCheckerInfo.Protocol = strings.ToUpper(*rawHealthMonitor.Type) + healthCheckerInfo.Interval = int(*rawHealthMonitor.Delay) + healthCheckerInfo.Threshold = int(*rawHealthMonitor.MaxRetries) + healthCheckerInfo.Timeout = int(*rawHealthMonitor.Timeout) + return healthCheckerInfo, nil + } + return healthCheckerInfo, errors.New("not exist HealthMonitor") +} + +func getCreateListenerOptions(nlbReqInfo irs.NLBInfo, poolName *string) ([]vpcv1.LoadBalancerListenerPrototypeLoadBalancerContext, error) { + if poolName == nil || *poolName == "" { + return nil, errors.New("invalid PoolName") + } + listenerDefaultPoolName := *poolName + listenerPort, err := strconv.Atoi(nlbReqInfo.Listener.Port) + if err != nil { + return nil, err + } + if listenerPort > 65535 || listenerPort < 1 { + return nil, errors.New("ibm-NLB Listener provides an port of between 1 and 65535") + } + + listenerPort64 := int64(listenerPort) + + listenerProtocol := "" + switch strings.ToLower(nlbReqInfo.Listener.Protocol) { + case "tcp", "udp": + listenerProtocol = strings.ToLower(nlbReqInfo.Listener.Protocol) + default: + return nil, errors.New("ibm-NLB Listener provides only TCP and UDP protocols") + } + + listener := vpcv1.LoadBalancerListenerPrototypeLoadBalancerContext{ + Port: &listenerPort64, + Protocol: &listenerProtocol, + DefaultPool: &vpcv1.LoadBalancerPoolIdentityByName{ + Name: &listenerDefaultPoolName, + }, + } + + var listenerArray = []vpcv1.LoadBalancerListenerPrototypeLoadBalancerContext{ + listener, + } + return listenerArray, nil +} + +func (nlbHandler *IbmNLBHandler) getCreatePoolOptions(nlbReqInfo irs.NLBInfo) ([]vpcv1.LoadBalancerPoolPrototype, error) { + // memberOption := vpcv1.LoadBalancerPoolMemberTargetPrototype{} + var poolArray []vpcv1.LoadBalancerPoolPrototype + + memberArrayOption, err := nlbHandler.convertCBVMGroupToIbmPoolMember(nlbReqInfo.VMGroup) + if err != nil { + return nil, err + } + + poolHealthOption, err := convertCBHealthToIbmHealth(nlbReqInfo.HealthChecker) + if err != nil { + return nil, err + } + + poolAlgorithm := "round_robin" + poolProtocol := "" + switch strings.ToLower(nlbReqInfo.VMGroup.Protocol) { + case "tcp", "udp": + poolProtocol = strings.ToLower(nlbReqInfo.VMGroup.Protocol) + default: + return nil, errors.New("ibm-NLB VMGroup provides only TCP and UDP protocols") + } + + poolName := generatePoolName(nlbReqInfo.VMGroup.Port) + + poolOption := vpcv1.LoadBalancerPoolPrototype{ + Algorithm: core.StringPtr(poolAlgorithm), + Protocol: core.StringPtr(poolProtocol), + Name: core.StringPtr(poolName), + HealthMonitor: &poolHealthOption, + Members: memberArrayOption, + } + poolArray = append(poolArray, poolOption) + return poolArray, nil +} + +func (nlbHandler *IbmNLBHandler) convertCBVMGroupToIbmPoolMember(vmGroup irs.VMGroupInfo) ([]vpcv1.LoadBalancerPoolMemberPrototype, error) { + vms := *vmGroup.VMs + memberPort, err := strconv.Atoi(vmGroup.Port) + if err != nil { + return nil, err + } + if memberPort > 65535 || memberPort < 1 { + return nil, errors.New("ibm-NLB vmGroup Port provides an port of between 1 and 65535") + } + memberArrayOption := make([]vpcv1.LoadBalancerPoolMemberPrototype, len(vms)) + memberPort64 := int64(memberPort) + var allVMS *[]vpcv1.Instance + for i, vmIID := range vms { + vmSystemId := vmIID.SystemId + if vmSystemId == "" { + if allVMS == nil { + allVMS, err = nlbHandler.getRawVMList() + if err != nil { + return nil, err + } + } + for _, rawVM := range *allVMS { + if strings.EqualFold(*rawVM.Name, vmIID.NameId) { + vmSystemId = *rawVM.ID + } + } + if vmSystemId == "" { + return nil, errors.New(fmt.Sprintf("not found VM %s", vmIID.NameId)) + } + } + memberArrayOption[i] = vpcv1.LoadBalancerPoolMemberPrototype{ + Port: core.Int64Ptr(memberPort64), + Target: &vpcv1.LoadBalancerPoolMemberTargetPrototype{ + ID: core.StringPtr(vmSystemId), + }, + } + } + return memberArrayOption, nil +} + +func convertCBHealthToIbmHealth(healthChecker irs.HealthCheckerInfo) (vpcv1.LoadBalancerPoolHealthMonitorPrototype, error) { + HealthProtocol := "" + switch strings.ToLower(healthChecker.Protocol) { + case "tcp", "http": + HealthProtocol = strings.ToLower(healthChecker.Protocol) + default: + return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides only HTTP and TCP protocols") + } + + HealthDelay := int64(healthChecker.Interval) + if HealthDelay > 60 || HealthDelay < 2 { + return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an interval of between 2 and 60 seconds") + } + HealthMaxRetries := int64(healthChecker.Threshold) + if HealthMaxRetries > 10 || HealthMaxRetries < 1 { + return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an Threshold of between 1 and 10") + } + HealthTimeOut := int64(healthChecker.Timeout) + if HealthTimeOut > 59 || HealthTimeOut < 1 { + return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an Timeout of between 1 and 59 seconds") + } + HealthPort, err := strconv.Atoi(healthChecker.Port) + if err != nil { + return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, err + } + if HealthPort > 65535 || HealthPort < 1 { + return vpcv1.LoadBalancerPoolHealthMonitorPrototype{}, errors.New("ibm-NLB healthCheck provides an port of between 1 and 65535") + } + + HealthPort64 := int64(HealthPort) + opts := vpcv1.LoadBalancerPoolHealthMonitorPrototype{ + Type: core.StringPtr(HealthProtocol), + Delay: core.Int64Ptr(HealthDelay), + MaxRetries: core.Int64Ptr(HealthMaxRetries), + Timeout: core.Int64Ptr(HealthTimeOut), + Port: core.Int64Ptr(HealthPort64), + } + if HealthProtocol == "http" { + opts.URLPath = core.StringPtr("/") + } + return opts, nil +} + +func (nlbHandler *IbmNLBHandler) getMatchVMIIdAndFirstSubnetId(vmIIDs *[]irs.IID) ([]irs.IID, string, error) { + // nameId => systemID, NameId + if vmIIDs == nil || len(*vmIIDs) < 1 { + return nil, "", errors.New("vmIIDs is empty") + } + allVMS, err := nlbHandler.getRawVMList() + if err != nil { + return nil, "", err + } + subnetId := "" + vms := *vmIIDs + for i, vmIID := range vms { + errCheck := true + for _, rawVM := range *allVMS { + if strings.EqualFold(vmIID.NameId, *rawVM.Name) { + if subnetId == "" { + subnetId = *rawVM.PrimaryNetworkInterface.Subnet.ID + } + vms[i].SystemId = *rawVM.ID + errCheck = false + break + } + } + if errCheck { + return nil, "", errors.New("not found vm") + } + } + return vms, subnetId, nil +} + +func (nlbHandler *IbmNLBHandler) createNLB(nlbReqInfo irs.NLBInfo) (vpcv1.LoadBalancer, error) { + exist, err := nlbHandler.existNLBByName(nlbReqInfo.IId.NameId) + if err != nil { + return vpcv1.LoadBalancer{}, err + } + if exist { + return vpcv1.LoadBalancer{}, errors.New(fmt.Sprintf("already exist NLB : %s", nlbReqInfo.IId.NameId)) + } + + vms, subnetId, err := nlbHandler.getMatchVMIIdAndFirstSubnetId(nlbReqInfo.VMGroup.VMs) + + if err != nil { + return vpcv1.LoadBalancer{}, err + } + + nlbReqInfo.VMGroup.VMs = &vms + + // Set - BaseOption + createNLBOptions := vpcv1.CreateLoadBalancerOptions{} + createNLBOptions.SetIsPublic(true) + createNLBOptions.SetName(nlbReqInfo.IId.NameId) + LoadBalancerProfileName := "network-fixed" + createNLBOptions.SetProfile(&vpcv1.LoadBalancerProfileIdentity{ + Name: &LoadBalancerProfileName, + }) + + // Set - subnet + var subnetArray = []vpcv1.SubnetIdentityIntf{ + &vpcv1.SubnetIdentity{ + ID: &subnetId, + }, + } + + poolArray, err := nlbHandler.getCreatePoolOptions(nlbReqInfo) + if err != nil { + return vpcv1.LoadBalancer{}, err + } + poolName := poolArray[0].Name + + listenerArray, err := getCreateListenerOptions(nlbReqInfo, poolName) + if err != nil { + return vpcv1.LoadBalancer{}, err + } + + createNLBOptions.SetSubnets(subnetArray) + createNLBOptions.SetPools(poolArray) + createNLBOptions.SetListeners(listenerArray) + + nlb, _, err := nlbHandler.VpcService.CreateLoadBalancerWithContext(nlbHandler.Ctx, &createNLBOptions) + if err != nil { + return vpcv1.LoadBalancer{}, err + } + _, err = nlbHandler.checkUpdatableNLB(*nlb.ID) + if err != nil { + return vpcv1.LoadBalancer{}, err + } + return *nlb, nil +} + +func (nlbHandler *IbmNLBHandler) getVMGroup(nlb vpcv1.LoadBalancer) (irs.VMGroupInfo, error) { + vmGroup := irs.VMGroupInfo{} + if len(nlb.Pools) > 0 { + backendPools := nlb.Pools + getPoolOption := vpcv1.GetLoadBalancerPoolOptions{} + getPoolOption.SetID(*backendPools[0].ID) + getPoolOption.SetLoadBalancerID(*nlb.ID) + cbOnlyOneBackendPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &getPoolOption) + if err != nil { + return irs.VMGroupInfo{}, err + } + vmGroup.CspID = *cbOnlyOneBackendPool.ID + vmGroup.Protocol = strings.ToUpper(*cbOnlyOneBackendPool.Protocol) + + poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} + poolMemberListOptions.SetLoadBalancerID(*nlb.ID) + poolMemberListOptions.SetPoolID(*cbOnlyOneBackendPool.ID) + + poolAllMembers, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) + if err != nil { + return irs.VMGroupInfo{}, err + } + vmIIDs, err := nlbHandler.getAllVMIIDsByMembers(poolAllMembers.Members) + if err != nil { + return irs.VMGroupInfo{}, err + } + vmGroup.VMs = &vmIIDs + portInt, err := nlbHandler.getPoolPort(*nlb.ID, *cbOnlyOneBackendPool.ID) + if err != nil { + return irs.VMGroupInfo{}, err + } + vmGroup.Port = strconv.Itoa(portInt) + } + return vmGroup, nil +} + +func getMemberTarget(member vpcv1.LoadBalancerPoolMember) (vpcv1.LoadBalancerPoolMemberTarget, error) { + target := member.Target + + targetJsonBytes, err := json.Marshal(target) + if err != nil { + return vpcv1.LoadBalancerPoolMemberTarget{}, err + } + var targetMember vpcv1.LoadBalancerPoolMemberTarget + err = json.Unmarshal(targetJsonBytes, &targetMember) + if err != nil { + return vpcv1.LoadBalancerPoolMemberTarget{}, err + } + return targetMember, nil +} + +func (nlbHandler *IbmNLBHandler) existNLBByName(nlbName string) (bool, error) { + if nlbName == "" { + return false, errors.New("name cannot be an empty value") + } + allNLBList, err := nlbHandler.getRawNLBList() + if err != nil { + return false, err + } + for _, rawNLB := range *allNLBList { + if strings.EqualFold(nlbName, *rawNLB.Name) { + return true, nil + } + } + return false, nil +} + +func (nlbHandler *IbmNLBHandler) getRawNLBByName(nlbName string) (vpcv1.LoadBalancer, error) { + if nlbName == "" { + return vpcv1.LoadBalancer{}, errors.New("name cannot be an empty value") + } + allNLBList, err := nlbHandler.getRawNLBList() + if err != nil { + return vpcv1.LoadBalancer{}, err + } + for _, rawNLB := range *allNLBList { + if strings.EqualFold(nlbName, *rawNLB.Name) { + return rawNLB, nil + } + } + return vpcv1.LoadBalancer{}, errors.New(fmt.Sprintf("not found NLB : %s", nlbName)) +} + +func (nlbHandler *IbmNLBHandler) getRawVMList() (*[]vpcv1.Instance, error) { + options := &vpcv1.ListInstancesOptions{} + var list []vpcv1.Instance + res, _, err := nlbHandler.VpcService.ListInstancesWithContext(nlbHandler.Ctx, options) + if err != nil { + return nil, err + } + + for { + if len(res.Instances) > 0 { + list = append(list, res.Instances...) + } else { + break + } + nextStr := "" + if res.Next != nil && res.Next.Href != nil { + nextStr, _ = getNextHref(*res.Next.Href) + } + if nextStr != "" { + options2 := &vpcv1.ListInstancesOptions{ + Start: core.StringPtr(nextStr), + } + res, _, err = nlbHandler.VpcService.ListInstancesWithContext(nlbHandler.Ctx, options2) + if err != nil { + return nil, err + } + } else { + break + } + } + return &list, nil +} + +func (nlbHandler *IbmNLBHandler) checkUpdatableNLB(nlbId string) (vpcv1.LoadBalancer, error) { + if nlbId == "" { + return vpcv1.LoadBalancer{}, errors.New("") + } + updatableCheckNLBOptions := vpcv1.GetLoadBalancerOptions{} + updatableCheckNLBOptions.SetID(nlbId) + var updatableCheckNLB *vpcv1.LoadBalancer + var err error + + curRetryCnt := 0 + maxRetryCnt := 240 + for { + updatableCheckNLB, _, err = nlbHandler.VpcService.GetLoadBalancerWithContext(nlbHandler.Ctx, &updatableCheckNLBOptions) + if err == nil && *updatableCheckNLB.ProvisioningStatus == "active" { + return *updatableCheckNLB, nil + } + time.Sleep(2 * time.Second) + curRetryCnt++ + if curRetryCnt > maxRetryCnt { + return vpcv1.LoadBalancer{}, errors.New(fmt.Sprintf("Failed to Update NLB VMGroup. err = exceeded maximum retry count %d", maxRetryCnt)) + } + } +} + +func (nlbHandler *IbmNLBHandler) getRawNLBList() (*[]vpcv1.LoadBalancer, error) { + options := &vpcv1.ListLoadBalancersOptions{} + var list []vpcv1.LoadBalancer + res, _, err := nlbHandler.VpcService.ListLoadBalancersWithContext(nlbHandler.Ctx, options) + if err != nil { + return nil, err + } + + for { + if len(res.LoadBalancers) > 0 { + list = append(list, res.LoadBalancers...) + } else { + break + } + nextStr := "" + if res.Next != nil && res.Next.Href != nil { + nextStr, _ = getNextHref(*res.Next.Href) + } + if nextStr != "" { + listNLBOptions2 := &vpcv1.ListLoadBalancersOptions{ + Start: core.StringPtr(nextStr), + } + res, _, err = nlbHandler.VpcService.ListLoadBalancersWithContext(nlbHandler.Ctx, listNLBOptions2) + if err != nil { + return nil, err + } + } else { + break + } + } + return &list, nil +} + +func (nlbHandler *IbmNLBHandler) cleanerNLB(nlbIID irs.IID) (bool, error) { + // Exist? + exist, err := nlbHandler.existNLBByName(nlbIID.NameId) + if err != nil { + return false, err + } + if !exist { + return false, errors.New("not found nlb") + } + rawNLB, err := nlbHandler.getRawNLBByName(nlbIID.NameId) + if err != nil { + return false, err + } + nlbId := *rawNLB.ID + nlbDeleteOption := vpcv1.DeleteLoadBalancerOptions{} + nlbDeleteOption.SetID(*rawNLB.ID) + _, err = nlbHandler.VpcService.DeleteLoadBalancerWithContext(nlbHandler.Ctx, &nlbDeleteOption) + if err != nil { + return false, err + } + _, err = nlbHandler.waitDeletedNLB(nlbId) + if err != nil { + return false, err + } + return true, nil +} + +func (nlbHandler *IbmNLBHandler) waitDeletedNLB(nlbId string) (bool, error) { + curRetryCnt := 0 + maxRetryCnt := 240 + for { + curRetryCnt++ + list, err := nlbHandler.getRawNLBList() + if err != nil { + return false, err + } + exist := false + for _, rawNLb := range *list { + if *rawNLb.ID == nlbId { + exist = true + } + } + if !exist { + return true, nil + } + time.Sleep(2 * time.Second) + if curRetryCnt > maxRetryCnt { + return false, errors.New(fmt.Sprintf("failed to create NLB, exceeded maximum retry count %d", maxRetryCnt)) + } + } +} + +func (nlbHandler *IbmNLBHandler) getHealthInfoByMembers(members []vpcv1.LoadBalancerPoolMember) (irs.HealthInfo, error) { + var allVMS *[]vpcv1.Instance + healthyVMs := make([]irs.IID, 0) + unHealthyVMs := make([]irs.IID, 0) + vmIIDs := make([]irs.IID, len(members)) + for i, member := range members { + memberTarget, err := getMemberTarget(member) + if err != nil { + return irs.HealthInfo{}, err + } + // targetMember.ID = instanceID + if memberTarget.ID != nil { + instanceOptions := &vpcv1.GetInstanceOptions{} + instanceOptions.SetID(*memberTarget.ID) + rawVM, _, err := nlbHandler.VpcService.GetInstance(instanceOptions) + if err != nil { + return irs.HealthInfo{}, err + } + vmIIDs[i] = irs.IID{ + NameId: *rawVM.Name, + SystemId: *rawVM.ID, + } + } else if memberTarget.Address != nil { + if allVMS == nil { + allVMS, err = nlbHandler.getRawVMList() + if err != nil { + return irs.HealthInfo{}, err + } + } + for _, rawVM := range *allVMS { + if strings.EqualFold(*rawVM.PrimaryNetworkInterface.PrimaryIpv4Address, *memberTarget.Address) { + vmIIDs[i] = irs.IID{ + NameId: *rawVM.Name, + SystemId: *rawVM.ID, + } + } + } + } + if checkVmGroupHealth(*member.Health) { + healthyVMs = append(healthyVMs, vmIIDs[i]) + } else { + unHealthyVMs = append(unHealthyVMs, vmIIDs[i]) + } + } + return irs.HealthInfo{ + AllVMs: &vmIIDs, + HealthyVMs: &healthyVMs, + UnHealthyVMs: &unHealthyVMs, + }, nil +} + +func (nlbHandler *IbmNLBHandler) getPoolPort(nlbId string, poolId string) (int, error) { + poolOption := vpcv1.GetLoadBalancerPoolOptions{} + poolOption.SetLoadBalancerID(nlbId) + poolOption.SetID(poolId) + + rawPool, _, err := nlbHandler.VpcService.GetLoadBalancerPoolWithContext(nlbHandler.Ctx, &poolOption) + if err != nil { + return 0, err + } + vmGroupPort, err := getPoolPortByPoolName(*rawPool.Name) + if err != nil { + poolMemberListOptions := vpcv1.ListLoadBalancerPoolMembersOptions{} + poolMemberListOptions.SetLoadBalancerID(nlbId) + poolMemberListOptions.SetPoolID(poolId) + poolAllMembers, _, err := nlbHandler.VpcService.ListLoadBalancerPoolMembersWithContext(nlbHandler.Ctx, &poolMemberListOptions) + if err != nil { + return 0, err + } + if len(poolAllMembers.Members) > 0 { + vmGroupPort = int(*poolAllMembers.Members[0].Port) + } else { + return 0, err + } + } + return vmGroupPort, nil +} + +func (nlbHandler *IbmNLBHandler) getAllVMIIDsByMembers(members []vpcv1.LoadBalancerPoolMember) ([]irs.IID, error) { + var allVMS *[]vpcv1.Instance + vmIIDs := make([]irs.IID, len(members)) + for i, member := range members { + memberTarget, err := getMemberTarget(member) + if err != nil { + return nil, err + } + // targetMember.ID = instanceID + if memberTarget.ID != nil { + instanceOptions := &vpcv1.GetInstanceOptions{} + instanceOptions.SetID(*memberTarget.ID) + rawVM, _, err := nlbHandler.VpcService.GetInstance(instanceOptions) + if err != nil { + return nil, err + } + vmIIDs[i] = irs.IID{ + NameId: *rawVM.Name, + SystemId: *rawVM.ID, + } + } else if memberTarget.Address != nil { + if allVMS == nil { + allVMS, err = nlbHandler.getRawVMList() + if err != nil { + return nil, err + } + } + for _, rawVM := range *allVMS { + if strings.EqualFold(*rawVM.PrimaryNetworkInterface.PrimaryIpv4Address, *memberTarget.Address) { + vmIIDs[i] = irs.IID{ + NameId: *rawVM.Name, + SystemId: *rawVM.ID, + } + } + } + } + } + return vmIIDs, nil +} + +func getPoolPortByPoolName(poolName string) (int, error) { + splits := strings.Split(poolName, "-") + if len(splits) != 3 { + return 0, errors.New("unable to get port information for vmGroup") + } + return strconv.Atoi(splits[1]) +} + +func generatePoolName(port string) string { + prefix := fmt.Sprintf("backend-%s", port) + return generateRandName(prefix) +} + +func getNextHref(str string) (string, error) { + href := str + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + return "", errors.New("NOT NEXT") +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/SecurityHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/SecurityHandler.go index aac18bca9..4e0bd2c93 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/SecurityHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/SecurityHandler.go @@ -1,754 +1,780 @@ -package resources - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - 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" - "net/url" - "strconv" - "strings" -) - -type IbmSecurityHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - VpcService *vpcv1.VpcV1 - Ctx context.Context -} - -func (securityHandler *IbmSecurityHandler) CreateSecurity(securityReqInfo irs.SecurityReqInfo) (irs.SecurityInfo, error) { - hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, securityReqInfo.IId.NameId, "CreateSecurity()") - start := call.Start() - - // req 체크 - err := checkSecurityReqInfo(securityReqInfo) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - exist, err := existSecurityGroup(securityReqInfo.IId, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } else if exist { - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = The Security name %s already exists", securityReqInfo.IId.NameId)) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - vpc, err := GetRawVPC(securityReqInfo.VpcIID, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - options := &vpcv1.CreateSecurityGroupOptions{} - options.SetVPC(&vpcv1.VPCIdentity{ - ID: vpc.ID, - }) - options.SetName(securityReqInfo.IId.NameId) - securityGroup, _, err := securityHandler.VpcService.CreateSecurityGroupWithContext(securityHandler.Ctx, options) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - securityGroupRulePrototypes, err := convertCBRuleInfoToIbmRule(*securityReqInfo.SecurityRules) - _ = addDefaultOutBoundRule(*securityReqInfo.SecurityRules, securityGroupRulePrototypes) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - for _, sgPrototype := range *securityGroupRulePrototypes { - ruleOptions := &vpcv1.CreateSecurityGroupRuleOptions{} - ruleOptions.SetSecurityGroupID(*securityGroup.ID) - ruleOptions.SetSecurityGroupRulePrototype(&sgPrototype) - _, _, err := securityHandler.VpcService.CreateSecurityGroupRuleWithContext(securityHandler.Ctx, ruleOptions) - if err != nil { - options := &vpcv1.DeleteSecurityGroupOptions{} - options.SetID(*securityGroup.ID) - _, deleteError := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) - if deleteError != nil { - err = errors.New(err.Error() + deleteError.Error()) - } - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - } - - rawSecurityGroup, err := getRawSecurityGroup(irs.IID{SystemId: *securityGroup.ID}, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - options := &vpcv1.DeleteSecurityGroupOptions{} - options.SetID(*securityGroup.ID) - _, deleteError := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) - if deleteError != nil { - err = errors.New(err.Error() + deleteError.Error()) - } - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - securityGroupInfo, err := setSecurityGroupInfo(rawSecurityGroup) - if err != nil { - options := &vpcv1.DeleteSecurityGroupOptions{} - options.SetID(*securityGroup.ID) - _, deleteError := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) - if deleteError != nil { - err = errors.New(err.Error() + deleteError.Error()) - } - createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - LoggingInfo(hiscallInfo, start) - return securityGroupInfo, nil -} - -func (securityHandler *IbmSecurityHandler) ListSecurity() ([]*irs.SecurityInfo, error) { - hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, "SECURITYGROUP", "ListSecurity()") - start := call.Start() - options := &vpcv1.ListSecurityGroupsOptions{} - securityGroups, _, err := securityHandler.VpcService.ListSecurityGroupsWithContext(securityHandler.Ctx, options) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List Security. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - var securityGroupList []*irs.SecurityInfo - for { - for _, securityGroup := range securityGroups.SecurityGroups { - securityInfo, err := setSecurityGroupInfo(securityGroup) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List Security. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - securityGroupList = append(securityGroupList, &securityInfo) - } - nextstr, _ := getSecurityGroupNextHref(securityGroups.Next) - if nextstr != "" { - options2 := &vpcv1.ListSecurityGroupsOptions{ - Start: core.StringPtr(nextstr), - } - securityGroups, _, err = securityHandler.VpcService.ListSecurityGroupsWithContext(securityHandler.Ctx, options2) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List Security. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - } else { - break - } - } - LoggingInfo(hiscallInfo, start) - return securityGroupList, nil -} - -func (securityHandler *IbmSecurityHandler) GetSecurity(securityIID irs.IID) (irs.SecurityInfo, error) { - hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, securityIID.NameId, "GetSecurity()") - start := call.Start() - - err := checkSecurityGroupIID(securityIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get Security. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - securityGroup, err := getRawSecurityGroup(securityIID, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get Security. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - securityGroupInfo, err := setSecurityGroupInfo(securityGroup) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get Security. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - LoggingInfo(hiscallInfo, start) - return securityGroupInfo, nil -} - -func (securityHandler *IbmSecurityHandler) DeleteSecurity(securityIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, securityIID.NameId, "DeleteSecurity()") - start := call.Start() - - err := checkSecurityGroupIID(securityIID) - - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - securityGroup, err := getRawSecurityGroup(securityIID, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - options := &vpcv1.DeleteSecurityGroupOptions{} - options.SetID(*securityGroup.ID) - res, err := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - if res.StatusCode == 204 { - LoggingInfo(hiscallInfo, start) - return true, nil - } else { - delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } -} - -func existSecurityGroup(securityIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { - if securityIID.NameId != "" { - options := &vpcv1.ListSecurityGroupsOptions{} - securityGroups, _, err := vpcService.ListSecurityGroupsWithContext(ctx, options) - if err != nil { - return false, err - } - for { - for _, securityGroup := range securityGroups.SecurityGroups { - if *securityGroup.Name == securityIID.NameId { - return true, nil - } - } - nextstr, _ := getSecurityGroupNextHref(securityGroups.Next) - if nextstr != "" { - options2 := &vpcv1.ListSecurityGroupsOptions{ - Start: core.StringPtr(nextstr), - } - securityGroups, _, err = vpcService.ListSecurityGroupsWithContext(ctx, options2) - if err != nil { - return false, err - } - } else { - break - } - } - return false, nil - } else { - err := errors.New("invalid securityIID") - return false, err - } -} - -func getRawSecurityGroup(securityIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.SecurityGroup, error) { - if securityIID.SystemId == "" { - options := &vpcv1.ListSecurityGroupsOptions{} - securityGroups, _, err := vpcService.ListSecurityGroupsWithContext(ctx, options) - if err != nil { - return vpcv1.SecurityGroup{}, err - } - for { - for _, securityGroup := range securityGroups.SecurityGroups { - if *securityGroup.Name == securityIID.NameId { - return securityGroup, nil - } - } - nextstr, _ := getSecurityGroupNextHref(securityGroups.Next) - if nextstr != "" { - options2 := &vpcv1.ListSecurityGroupsOptions{ - Start: core.StringPtr(nextstr), - } - securityGroups, _, err = vpcService.ListSecurityGroupsWithContext(ctx, options2) - if err != nil { - return vpcv1.SecurityGroup{}, err - } - } else { - break - } - } - return vpcv1.SecurityGroup{}, errors.New(fmt.Sprintf("not found SecurityGroup %s", securityIID.NameId)) - } else { - options := &vpcv1.GetSecurityGroupOptions{} - options.SetID(securityIID.SystemId) - sg, _, err := vpcService.GetSecurityGroupWithContext(ctx, options) - if err != nil { - return vpcv1.SecurityGroup{}, err - } - return *sg, nil - } -} - -func setSecurityGroupInfo(securityGroup vpcv1.SecurityGroup) (irs.SecurityInfo, error) { - securityInfo := irs.SecurityInfo{ - IId: irs.IID{ - NameId: *securityGroup.Name, - SystemId: *securityGroup.ID, - }, - VpcIID: irs.IID{ - NameId: *securityGroup.VPC.Name, - SystemId: *securityGroup.VPC.ID, - }, - } - ruleList, err := setRule(securityGroup) - if err != nil { - return irs.SecurityInfo{}, err - } - securityInfo.SecurityRules = &ruleList - return securityInfo, nil -} - -func setRule(securityGroup vpcv1.SecurityGroup) ([]irs.SecurityRuleInfo, error) { - var ruleList []irs.SecurityRuleInfo - for _, rule := range securityGroup.Rules { - ruleInfo, err := ConvertIbmRuleToCBRuleInfo(rule) - if err != nil { - return nil, err - } - ruleList = append(ruleList, *ruleInfo) - } - return ruleList, nil -} - -func getSecurityGroupNextHref(next *vpcv1.SecurityGroupCollectionNext) (string, error) { - if next != nil { - href := *next.Href - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - } - return "", errors.New("NOT NEXT") -} - -func checkSecurityGroupIID(securityIID irs.IID) error { - if securityIID.SystemId == "" && securityIID.NameId == "" { - err := errors.New("invalid IID") - return err - } - return nil -} - -func checkSecurityReqInfo(securityReqInfo irs.SecurityReqInfo) error { - if securityReqInfo.IId.NameId == "" { - return errors.New("invalid securityReqInfo IID") - } - if securityReqInfo.VpcIID.NameId == "" && securityReqInfo.VpcIID.SystemId == "" { - return errors.New("invalid securityReqInfo VpcIID") - } - return nil -} - -func (securityHandler *IbmSecurityHandler) AddRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (irs.SecurityInfo, error) { - hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, sgIID.NameId, "GetSecurity()") - start := call.Start() - - err := checkSecurityGroupIID(sgIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - securityGroup, err := getRawSecurityGroup(sgIID, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - securityGroupInfo, err := setSecurityGroupInfo(securityGroup) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - var updateRules []irs.SecurityRuleInfo - // 추가될 Rule 판단 - for _, newRule := range *securityRules { - existCheck := false - for _, baseRule := range *securityGroupInfo.SecurityRules { - if equalsRule(newRule, baseRule) { - existCheck = true - break - } - } - if existCheck { - b, err := json.Marshal(newRule) - err = errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err already Exist Rule : %s", string(b))) - cblogger.Error(err.Error()) - LoggingError(hiscallInfo, err) - return irs.SecurityInfo{}, err - } - updateRules = append(updateRules, newRule) - } - securityGroupRulePrototypes, err := convertCBRuleInfoToIbmRule(updateRules) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - for _, sgPrototype := range *securityGroupRulePrototypes { - ruleOptions := &vpcv1.CreateSecurityGroupRuleOptions{} - ruleOptions.SetSecurityGroupID(*securityGroup.ID) - ruleOptions.SetSecurityGroupRulePrototype(&sgPrototype) - _, _, err := securityHandler.VpcService.CreateSecurityGroupRuleWithContext(securityHandler.Ctx, ruleOptions) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.SecurityInfo{}, createErr - } - } - - newSecurityGroup, err := getRawSecurityGroup(sgIID, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - newSecurityGroupInfo, err := setSecurityGroupInfo(newSecurityGroup) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.SecurityInfo{}, getErr - } - LoggingInfo(hiscallInfo, start) - return newSecurityGroupInfo, nil -} - -func (securityHandler *IbmSecurityHandler) RemoveRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (bool, error) { - hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, sgIID.NameId, "RemoveRules()") - start := call.Start() - - err := checkSecurityGroupIID(sgIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return false, getErr - } - securityGroup, err := getRawSecurityGroup(sgIID, securityHandler.VpcService, securityHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return false, getErr - } - - ruleWithIds, err := getRuleInfoWithId(&securityGroup.Rules) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return false, getErr - } - var deleteRuleIds []string - - for _, delRule := range *securityRules { - existCheck := false - for _, baseRuleWithId := range *ruleWithIds { - if equalsRule(baseRuleWithId.RuleInfo, delRule) { - existCheck = true - deleteRuleIds = append(deleteRuleIds, baseRuleWithId.Id) - break - } - } - if !existCheck { - b, err := json.Marshal(delRule) - err = errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = not Exist Rule : %s", string(b))) - cblogger.Error(err.Error()) - LoggingError(hiscallInfo, err) - return false, err - } - } - - for _, deleteRuleId := range deleteRuleIds { - options := &vpcv1.DeleteSecurityGroupRuleOptions{} - options.SetSecurityGroupID(*securityGroup.ID) - options.SetID(deleteRuleId) - _, err := securityHandler.VpcService.DeleteSecurityGroupRuleWithContext(securityHandler.Ctx, options) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return false, getErr - } - } - LoggingInfo(hiscallInfo, start) - return true, nil -} - -type securityRuleInfoWithId struct { - Id string - RuleInfo irs.SecurityRuleInfo -} - -func equalsRule(pre irs.SecurityRuleInfo, post irs.SecurityRuleInfo) bool { - if pre.ToPort == "-1" || pre.FromPort == "-1" { - pre.FromPort = "1" - pre.ToPort = "65535" - } - if post.ToPort == "-1" || post.FromPort == "-1" { - post.FromPort = "1" - post.ToPort = "65535" - } - return strings.ToLower(fmt.Sprintf("%#v", pre)) == strings.ToLower(fmt.Sprintf("%#v", post)) -} - -func getRuleInfoWithId(rawRules *[]vpcv1.SecurityGroupRuleIntf) (*[]securityRuleInfoWithId, error) { - var arr []securityRuleInfoWithId - for _, rule := range *rawRules { - jsonRuleBytes, err := json.Marshal(rule) - if err != nil { - return nil, err - } - var ru vpcv1.SecurityGroupRule - _ = json.Unmarshal(jsonRuleBytes, &ru) - if ru.ID == nil { - return nil, errors.New("securityGroup Rule marshal failed") - } - ruleInfo, err := ConvertIbmRuleToCBRuleInfo(rule) - if err != nil { - return nil, err - } - arr = append(arr, securityRuleInfoWithId{Id: *ru.ID, RuleInfo: *ruleInfo}) - } - return &arr, nil -} - -func ConvertIbmRuleToCBRuleInfo(rule vpcv1.SecurityGroupRuleIntf) (*irs.SecurityRuleInfo, error) { - jsonRuleBytes, err := json.Marshal(rule) - if err != nil { - return nil, err - } - jsonRuleMap := make(map[string]json.RawMessage) - unmarshalErr := json.Unmarshal(jsonRuleBytes, &jsonRuleMap) - if unmarshalErr != nil { - return nil, err - } - remoteJson := jsonRuleMap["remote"] - - var remote vpcv1.SecurityGroupRuleRemote - unmarshalErr = json.Unmarshal(remoteJson, &remote) - if unmarshalErr != nil { - return nil, err - } - var ruleProtocolAll vpcv1.SecurityGroupRulePrototypeSecurityGroupRuleProtocolAll - _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolAll) - protocol := convertRuleProtocolIBMToCB(*ruleProtocolAll.Protocol) - cidr := "0.0.0.0/0" - if remote.CIDRBlock != nil { - cidr = *remote.CIDRBlock - } - if protocol == "tcp" || protocol == "udp" { - var ruleProtocolTcpUdp vpcv1.SecurityGroupRulePrototypeSecurityGroupRuleProtocolTcpudp - _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolTcpUdp) - from, to := convertRulePortRangeIBMToCB(*ruleProtocolTcpUdp.PortMin, *ruleProtocolTcpUdp.PortMax) - ruleInfo := irs.SecurityRuleInfo{ - IPProtocol: protocol, - Direction: *ruleProtocolTcpUdp.Direction, - FromPort: from, - ToPort: to, - CIDR: cidr, - } - return &ruleInfo, nil - } else if protocol == "icmp" { - var ruleProtocolIcmp vpcv1.SecurityGroupRulePrototypeSecurityGroupRuleProtocolIcmp - _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolIcmp) - ruleInfo := irs.SecurityRuleInfo{ - IPProtocol: protocol, - Direction: *ruleProtocolIcmp.Direction, - CIDR: cidr, - FromPort: "-1", - ToPort: "-1", - } - return &ruleInfo, nil - } else { - ruleInfo := irs.SecurityRuleInfo{ - IPProtocol: protocol, - Direction: *ruleProtocolAll.Direction, - CIDR: cidr, - FromPort: "-1", - ToPort: "-1", - } - return &ruleInfo, nil - } -} - -func ModifyVPCDefaultRule(rules []vpcv1.SecurityGroupRuleIntf, sgIId irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) error { - for _, rule := range rules { - jsonRuleBytes, err := json.Marshal(rule) - if err != nil { - return err - } - jsonRuleMap := make(map[string]json.RawMessage) - unmarshalErr := json.Unmarshal(jsonRuleBytes, &jsonRuleMap) - if unmarshalErr != nil { - return err - } - remoteJson := jsonRuleMap["remote"] - - var remote vpcv1.SecurityGroupRuleRemote - unmarshalErr = json.Unmarshal(remoteJson, &remote) - if unmarshalErr != nil { - return err - } - if remote.Name != nil && *remote.Name == sgIId.NameId { - continue - } - var ruleProtocolAll vpcv1.SecurityGroupRule - _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolAll) - if ruleProtocolAll.ID != nil && *ruleProtocolAll.ID != "" { - options := &vpcv1.DeleteSecurityGroupRuleOptions{} - options.SetSecurityGroupID(sgIId.SystemId) - options.SetID(*ruleProtocolAll.ID) - _, err = vpcService.DeleteSecurityGroupRuleWithContext(ctx, options) - if err != nil { - return err - } - } - } - return nil -} - -func convertRuleProtocolIBMToCB(protocol string) string { - return strings.ToLower(protocol) -} - -func convertRuleProtocolCBToIBM(protocol string) (string, error) { - switch strings.ToUpper(protocol) { - case "ALL": - return strings.ToLower(protocol), nil - case "ICMP", "TCP", "UDP": - return strings.ToLower(protocol), nil - } - return "", errors.New("invalid Rule Protocol") -} - -func convertRulePortRangeIBMToCB(min int64, max int64) (from string, to string) { - return strconv.FormatInt(min, 10), strconv.FormatInt(max, 10) -} - -func convertRulePortRangeCBToIBM(from string, to string) (min int64, max int64, err error) { - if from == "" || to == "" { - return 0, 0, errors.New("invalid Rule PortRange") - } - fromInt, err := strconv.ParseInt(from, 10, 64) - if err != nil { - return 0, 0, errors.New("invalid Rule PortRange") - } - toInt, err := strconv.ParseInt(to, 10, 64) - if err != nil { - return 0, 0, errors.New("invalid Rule PortRange") - } - if fromInt == -1 || toInt == -1 { - return int64(1), int64(65535), nil - } - if fromInt > 65535 || fromInt < -1 || toInt > 65535 || toInt < -1 { - return 0, 0, errors.New("invalid Rule PortRange") - } - if fromInt == toInt { - return fromInt, fromInt, nil - } else { - return fromInt, toInt, nil - } -} - -func convertCBRuleInfoToIbmRule(rules []irs.SecurityRuleInfo) (*[]vpcv1.SecurityGroupRulePrototype, error) { - var IbmSGRuleList []vpcv1.SecurityGroupRulePrototype - for _, securityRule := range rules { - protocol, err := convertRuleProtocolCBToIBM(securityRule.IPProtocol) - if err != nil { - return nil, err - } - if protocol == "tcp" || protocol == "udp" { - portMin, portMax, err := convertRulePortRangeCBToIBM(securityRule.FromPort, securityRule.ToPort) - if err != nil { - return nil, err - } - IbmSGRuleList = append(IbmSGRuleList, vpcv1.SecurityGroupRulePrototype{ - Direction: core.StringPtr(strings.ToLower(securityRule.Direction)), - Protocol: core.StringPtr(protocol), - PortMax: core.Int64Ptr(portMax), - PortMin: core.Int64Ptr(portMin), - IPVersion: core.StringPtr("ipv4"), - Remote: &vpcv1.SecurityGroupRuleRemotePrototype{ - CIDRBlock: &securityRule.CIDR, - }, - }) - } else { - IbmSGRuleList = append(IbmSGRuleList, vpcv1.SecurityGroupRulePrototype{ - Direction: core.StringPtr(strings.ToLower(securityRule.Direction)), - Protocol: core.StringPtr(protocol), - IPVersion: core.StringPtr("ipv4"), - Remote: &vpcv1.SecurityGroupRuleRemotePrototype{ - CIDRBlock: &securityRule.CIDR, - }, - }) - } - } - return &IbmSGRuleList, nil -} -func addDefaultOutBoundRule(baseRuleInfos []irs.SecurityRuleInfo, addRules *[]vpcv1.SecurityGroupRulePrototype) error { - defaultRuleInfo := irs.SecurityRuleInfo{ - CIDR: "0.0.0.0/0", - IPProtocol: "all", - FromPort: "-1", - ToPort: "-1", - Direction: "outbound", - } - addCheck := true - for _, rule := range baseRuleInfos { - if equalsRule(rule, defaultRuleInfo) { - addCheck = false - } - } - if addCheck { - *addRules = append(*addRules, vpcv1.SecurityGroupRulePrototype{ - Direction: core.StringPtr(strings.ToLower(defaultRuleInfo.Direction)), - Protocol: core.StringPtr(defaultRuleInfo.IPProtocol), - IPVersion: core.StringPtr("ipv4"), - Remote: &vpcv1.SecurityGroupRuleRemotePrototype{ - CIDRBlock: &defaultRuleInfo.CIDR, - }, - }) - } - return nil -} +package resources + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/vpc-go-sdk/vpcv1" + 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" + "net/url" + "strconv" + "strings" +) + +type IbmSecurityHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + VpcService *vpcv1.VpcV1 + Ctx context.Context +} + +func (securityHandler *IbmSecurityHandler) CreateSecurity(securityReqInfo irs.SecurityReqInfo) (irs.SecurityInfo, error) { + hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, securityReqInfo.IId.NameId, "CreateSecurity()") + start := call.Start() + + // req 체크 + err := checkSecurityReqInfo(securityReqInfo) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + exist, err := existSecurityGroup(securityReqInfo.IId, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } else if exist { + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = The Security name %s already exists", securityReqInfo.IId.NameId)) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + vpc, err := GetRawVPC(securityReqInfo.VpcIID, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + options := &vpcv1.CreateSecurityGroupOptions{} + options.SetVPC(&vpcv1.VPCIdentity{ + ID: vpc.ID, + }) + options.SetName(securityReqInfo.IId.NameId) + securityGroup, _, err := securityHandler.VpcService.CreateSecurityGroupWithContext(securityHandler.Ctx, options) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + securityGroupRulePrototypes, err := convertCBRuleInfoToIbmRule(*securityReqInfo.SecurityRules) + _ = addDefaultOutBoundRule(*securityReqInfo.SecurityRules, securityGroupRulePrototypes) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + for _, sgPrototype := range *securityGroupRulePrototypes { + ruleOptions := &vpcv1.CreateSecurityGroupRuleOptions{} + ruleOptions.SetSecurityGroupID(*securityGroup.ID) + ruleOptions.SetSecurityGroupRulePrototype(&sgPrototype) + _, _, err := securityHandler.VpcService.CreateSecurityGroupRuleWithContext(securityHandler.Ctx, ruleOptions) + if err != nil { + options := &vpcv1.DeleteSecurityGroupOptions{} + options.SetID(*securityGroup.ID) + _, deleteError := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) + if deleteError != nil { + err = errors.New(err.Error() + deleteError.Error()) + } + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + } + + rawSecurityGroup, err := getRawSecurityGroup(irs.IID{SystemId: *securityGroup.ID}, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + options := &vpcv1.DeleteSecurityGroupOptions{} + options.SetID(*securityGroup.ID) + _, deleteError := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) + if deleteError != nil { + err = errors.New(err.Error() + deleteError.Error()) + } + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + securityGroupInfo, err := setSecurityGroupInfo(rawSecurityGroup) + if err != nil { + options := &vpcv1.DeleteSecurityGroupOptions{} + options.SetID(*securityGroup.ID) + _, deleteError := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) + if deleteError != nil { + err = errors.New(err.Error() + deleteError.Error()) + } + createErr := errors.New(fmt.Sprintf("Failed to Create Security. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + LoggingInfo(hiscallInfo, start) + + // Attach Tag + if securityReqInfo.TagList != nil && len(securityReqInfo.TagList) > 0{ + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range securityReqInfo.TagList{ + _, err := tagHandler.AddTag("SG", securityReqInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on SG err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + return securityGroupInfo, nil +} + +func (securityHandler *IbmSecurityHandler) ListSecurity() ([]*irs.SecurityInfo, error) { + hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, "SECURITYGROUP", "ListSecurity()") + start := call.Start() + options := &vpcv1.ListSecurityGroupsOptions{} + securityGroups, _, err := securityHandler.VpcService.ListSecurityGroupsWithContext(securityHandler.Ctx, options) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List Security. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + var securityGroupList []*irs.SecurityInfo + for { + for _, securityGroup := range securityGroups.SecurityGroups { + securityInfo, err := setSecurityGroupInfo(securityGroup) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List Security. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + securityGroupList = append(securityGroupList, &securityInfo) + } + nextstr, _ := getSecurityGroupNextHref(securityGroups.Next) + if nextstr != "" { + options2 := &vpcv1.ListSecurityGroupsOptions{ + Start: core.StringPtr(nextstr), + } + securityGroups, _, err = securityHandler.VpcService.ListSecurityGroupsWithContext(securityHandler.Ctx, options2) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List Security. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + } else { + break + } + } + LoggingInfo(hiscallInfo, start) + return securityGroupList, nil +} + +func (securityHandler *IbmSecurityHandler) GetSecurity(securityIID irs.IID) (irs.SecurityInfo, error) { + hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, securityIID.NameId, "GetSecurity()") + start := call.Start() + + err := checkSecurityGroupIID(securityIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get Security. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + securityGroup, err := getRawSecurityGroup(securityIID, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get Security. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + securityGroupInfo, err := setSecurityGroupInfo(securityGroup) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get Security. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + LoggingInfo(hiscallInfo, start) + return securityGroupInfo, nil +} + +func (securityHandler *IbmSecurityHandler) DeleteSecurity(securityIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, securityIID.NameId, "DeleteSecurity()") + start := call.Start() + + err := checkSecurityGroupIID(securityIID) + + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + securityGroup, err := getRawSecurityGroup(securityIID, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + options := &vpcv1.DeleteSecurityGroupOptions{} + options.SetID(*securityGroup.ID) + res, err := securityHandler.VpcService.DeleteSecurityGroupWithContext(securityHandler.Ctx, options) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + if res.StatusCode == 204 { + LoggingInfo(hiscallInfo, start) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete SG Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + return true, nil + } else { + delErr := errors.New(fmt.Sprintf("Failed to Delete Security. err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } +} + +func existSecurityGroup(securityIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { + if securityIID.NameId != "" { + options := &vpcv1.ListSecurityGroupsOptions{} + securityGroups, _, err := vpcService.ListSecurityGroupsWithContext(ctx, options) + if err != nil { + return false, err + } + for { + for _, securityGroup := range securityGroups.SecurityGroups { + if *securityGroup.Name == securityIID.NameId { + return true, nil + } + } + nextstr, _ := getSecurityGroupNextHref(securityGroups.Next) + if nextstr != "" { + options2 := &vpcv1.ListSecurityGroupsOptions{ + Start: core.StringPtr(nextstr), + } + securityGroups, _, err = vpcService.ListSecurityGroupsWithContext(ctx, options2) + if err != nil { + return false, err + } + } else { + break + } + } + return false, nil + } else { + err := errors.New("invalid securityIID") + return false, err + } +} + +func getRawSecurityGroup(securityIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.SecurityGroup, error) { + if securityIID.SystemId == "" { + options := &vpcv1.ListSecurityGroupsOptions{} + securityGroups, _, err := vpcService.ListSecurityGroupsWithContext(ctx, options) + if err != nil { + return vpcv1.SecurityGroup{}, err + } + for { + for _, securityGroup := range securityGroups.SecurityGroups { + if *securityGroup.Name == securityIID.NameId { + return securityGroup, nil + } + } + nextstr, _ := getSecurityGroupNextHref(securityGroups.Next) + if nextstr != "" { + options2 := &vpcv1.ListSecurityGroupsOptions{ + Start: core.StringPtr(nextstr), + } + securityGroups, _, err = vpcService.ListSecurityGroupsWithContext(ctx, options2) + if err != nil { + return vpcv1.SecurityGroup{}, err + } + } else { + break + } + } + return vpcv1.SecurityGroup{}, errors.New(fmt.Sprintf("not found SecurityGroup %s", securityIID.NameId)) + } else { + options := &vpcv1.GetSecurityGroupOptions{} + options.SetID(securityIID.SystemId) + sg, _, err := vpcService.GetSecurityGroupWithContext(ctx, options) + if err != nil { + return vpcv1.SecurityGroup{}, err + } + return *sg, nil + } +} + +func setSecurityGroupInfo(securityGroup vpcv1.SecurityGroup) (irs.SecurityInfo, error) { + securityInfo := irs.SecurityInfo{ + IId: irs.IID{ + NameId: *securityGroup.Name, + SystemId: *securityGroup.ID, + }, + VpcIID: irs.IID{ + NameId: *securityGroup.VPC.Name, + SystemId: *securityGroup.VPC.ID, + }, + } + ruleList, err := setRule(securityGroup) + if err != nil { + return irs.SecurityInfo{}, err + } + securityInfo.SecurityRules = &ruleList + return securityInfo, nil +} + +func setRule(securityGroup vpcv1.SecurityGroup) ([]irs.SecurityRuleInfo, error) { + var ruleList []irs.SecurityRuleInfo + for _, rule := range securityGroup.Rules { + ruleInfo, err := ConvertIbmRuleToCBRuleInfo(rule) + if err != nil { + return nil, err + } + ruleList = append(ruleList, *ruleInfo) + } + return ruleList, nil +} + +func getSecurityGroupNextHref(next *vpcv1.SecurityGroupCollectionNext) (string, error) { + if next != nil { + href := *next.Href + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + } + return "", errors.New("NOT NEXT") +} + +func checkSecurityGroupIID(securityIID irs.IID) error { + if securityIID.SystemId == "" && securityIID.NameId == "" { + err := errors.New("invalid IID") + return err + } + return nil +} + +func checkSecurityReqInfo(securityReqInfo irs.SecurityReqInfo) error { + if securityReqInfo.IId.NameId == "" { + return errors.New("invalid securityReqInfo IID") + } + if securityReqInfo.VpcIID.NameId == "" && securityReqInfo.VpcIID.SystemId == "" { + return errors.New("invalid securityReqInfo VpcIID") + } + return nil +} + +func (securityHandler *IbmSecurityHandler) AddRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (irs.SecurityInfo, error) { + hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, sgIID.NameId, "GetSecurity()") + start := call.Start() + + err := checkSecurityGroupIID(sgIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + securityGroup, err := getRawSecurityGroup(sgIID, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + securityGroupInfo, err := setSecurityGroupInfo(securityGroup) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + var updateRules []irs.SecurityRuleInfo + // 추가될 Rule 판단 + for _, newRule := range *securityRules { + existCheck := false + for _, baseRule := range *securityGroupInfo.SecurityRules { + if equalsRule(newRule, baseRule) { + existCheck = true + break + } + } + if existCheck { + b, err := json.Marshal(newRule) + err = errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err already Exist Rule : %s", string(b))) + cblogger.Error(err.Error()) + LoggingError(hiscallInfo, err) + return irs.SecurityInfo{}, err + } + updateRules = append(updateRules, newRule) + } + securityGroupRulePrototypes, err := convertCBRuleInfoToIbmRule(updateRules) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + for _, sgPrototype := range *securityGroupRulePrototypes { + ruleOptions := &vpcv1.CreateSecurityGroupRuleOptions{} + ruleOptions.SetSecurityGroupID(*securityGroup.ID) + ruleOptions.SetSecurityGroupRulePrototype(&sgPrototype) + _, _, err := securityHandler.VpcService.CreateSecurityGroupRuleWithContext(securityHandler.Ctx, ruleOptions) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.SecurityInfo{}, createErr + } + } + + newSecurityGroup, err := getRawSecurityGroup(sgIID, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + newSecurityGroupInfo, err := setSecurityGroupInfo(newSecurityGroup) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Add SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.SecurityInfo{}, getErr + } + LoggingInfo(hiscallInfo, start) + return newSecurityGroupInfo, nil +} + +func (securityHandler *IbmSecurityHandler) RemoveRules(sgIID irs.IID, securityRules *[]irs.SecurityRuleInfo) (bool, error) { + hiscallInfo := GetCallLogScheme(securityHandler.Region, call.SECURITYGROUP, sgIID.NameId, "RemoveRules()") + start := call.Start() + + err := checkSecurityGroupIID(sgIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return false, getErr + } + securityGroup, err := getRawSecurityGroup(sgIID, securityHandler.VpcService, securityHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return false, getErr + } + + ruleWithIds, err := getRuleInfoWithId(&securityGroup.Rules) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return false, getErr + } + var deleteRuleIds []string + + for _, delRule := range *securityRules { + existCheck := false + for _, baseRuleWithId := range *ruleWithIds { + if equalsRule(baseRuleWithId.RuleInfo, delRule) { + existCheck = true + deleteRuleIds = append(deleteRuleIds, baseRuleWithId.Id) + break + } + } + if !existCheck { + b, err := json.Marshal(delRule) + err = errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = not Exist Rule : %s", string(b))) + cblogger.Error(err.Error()) + LoggingError(hiscallInfo, err) + return false, err + } + } + + for _, deleteRuleId := range deleteRuleIds { + options := &vpcv1.DeleteSecurityGroupRuleOptions{} + options.SetSecurityGroupID(*securityGroup.ID) + options.SetID(deleteRuleId) + _, err := securityHandler.VpcService.DeleteSecurityGroupRuleWithContext(securityHandler.Ctx, options) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Remove SecurityGroup Rules. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return false, getErr + } + } + LoggingInfo(hiscallInfo, start) + return true, nil +} + +type securityRuleInfoWithId struct { + Id string + RuleInfo irs.SecurityRuleInfo +} + +func equalsRule(pre irs.SecurityRuleInfo, post irs.SecurityRuleInfo) bool { + if pre.ToPort == "-1" || pre.FromPort == "-1" { + pre.FromPort = "1" + pre.ToPort = "65535" + } + if post.ToPort == "-1" || post.FromPort == "-1" { + post.FromPort = "1" + post.ToPort = "65535" + } + return strings.ToLower(fmt.Sprintf("%#v", pre)) == strings.ToLower(fmt.Sprintf("%#v", post)) +} + +func getRuleInfoWithId(rawRules *[]vpcv1.SecurityGroupRuleIntf) (*[]securityRuleInfoWithId, error) { + var arr []securityRuleInfoWithId + for _, rule := range *rawRules { + jsonRuleBytes, err := json.Marshal(rule) + if err != nil { + return nil, err + } + var ru vpcv1.SecurityGroupRule + _ = json.Unmarshal(jsonRuleBytes, &ru) + if ru.ID == nil { + return nil, errors.New("securityGroup Rule marshal failed") + } + ruleInfo, err := ConvertIbmRuleToCBRuleInfo(rule) + if err != nil { + return nil, err + } + arr = append(arr, securityRuleInfoWithId{Id: *ru.ID, RuleInfo: *ruleInfo}) + } + return &arr, nil +} + +func ConvertIbmRuleToCBRuleInfo(rule vpcv1.SecurityGroupRuleIntf) (*irs.SecurityRuleInfo, error) { + jsonRuleBytes, err := json.Marshal(rule) + if err != nil { + return nil, err + } + jsonRuleMap := make(map[string]json.RawMessage) + unmarshalErr := json.Unmarshal(jsonRuleBytes, &jsonRuleMap) + if unmarshalErr != nil { + return nil, err + } + remoteJson := jsonRuleMap["remote"] + + var remote vpcv1.SecurityGroupRuleRemote + unmarshalErr = json.Unmarshal(remoteJson, &remote) + if unmarshalErr != nil { + return nil, err + } + var ruleProtocolAll vpcv1.SecurityGroupRulePrototypeSecurityGroupRuleProtocolAll + _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolAll) + protocol := convertRuleProtocolIBMToCB(*ruleProtocolAll.Protocol) + cidr := "0.0.0.0/0" + if remote.CIDRBlock != nil { + cidr = *remote.CIDRBlock + } + if protocol == "tcp" || protocol == "udp" { + var ruleProtocolTcpUdp vpcv1.SecurityGroupRulePrototypeSecurityGroupRuleProtocolTcpudp + _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolTcpUdp) + from, to := convertRulePortRangeIBMToCB(*ruleProtocolTcpUdp.PortMin, *ruleProtocolTcpUdp.PortMax) + ruleInfo := irs.SecurityRuleInfo{ + IPProtocol: protocol, + Direction: *ruleProtocolTcpUdp.Direction, + FromPort: from, + ToPort: to, + CIDR: cidr, + } + return &ruleInfo, nil + } else if protocol == "icmp" { + var ruleProtocolIcmp vpcv1.SecurityGroupRulePrototypeSecurityGroupRuleProtocolIcmp + _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolIcmp) + ruleInfo := irs.SecurityRuleInfo{ + IPProtocol: protocol, + Direction: *ruleProtocolIcmp.Direction, + CIDR: cidr, + FromPort: "-1", + ToPort: "-1", + } + return &ruleInfo, nil + } else { + ruleInfo := irs.SecurityRuleInfo{ + IPProtocol: protocol, + Direction: *ruleProtocolAll.Direction, + CIDR: cidr, + FromPort: "-1", + ToPort: "-1", + } + return &ruleInfo, nil + } +} + +func ModifyVPCDefaultRule(rules []vpcv1.SecurityGroupRuleIntf, sgIId irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) error { + for _, rule := range rules { + jsonRuleBytes, err := json.Marshal(rule) + if err != nil { + return err + } + jsonRuleMap := make(map[string]json.RawMessage) + unmarshalErr := json.Unmarshal(jsonRuleBytes, &jsonRuleMap) + if unmarshalErr != nil { + return err + } + remoteJson := jsonRuleMap["remote"] + + var remote vpcv1.SecurityGroupRuleRemote + unmarshalErr = json.Unmarshal(remoteJson, &remote) + if unmarshalErr != nil { + return err + } + if remote.Name != nil && *remote.Name == sgIId.NameId { + continue + } + var ruleProtocolAll vpcv1.SecurityGroupRule + _ = json.Unmarshal(jsonRuleBytes, &ruleProtocolAll) + if ruleProtocolAll.ID != nil && *ruleProtocolAll.ID != "" { + options := &vpcv1.DeleteSecurityGroupRuleOptions{} + options.SetSecurityGroupID(sgIId.SystemId) + options.SetID(*ruleProtocolAll.ID) + _, err = vpcService.DeleteSecurityGroupRuleWithContext(ctx, options) + if err != nil { + return err + } + } + } + return nil +} + +func convertRuleProtocolIBMToCB(protocol string) string { + return strings.ToLower(protocol) +} + +func convertRuleProtocolCBToIBM(protocol string) (string, error) { + switch strings.ToUpper(protocol) { + case "ALL": + return strings.ToLower(protocol), nil + case "ICMP", "TCP", "UDP": + return strings.ToLower(protocol), nil + } + return "", errors.New("invalid Rule Protocol") +} + +func convertRulePortRangeIBMToCB(min int64, max int64) (from string, to string) { + return strconv.FormatInt(min, 10), strconv.FormatInt(max, 10) +} + +func convertRulePortRangeCBToIBM(from string, to string) (min int64, max int64, err error) { + if from == "" || to == "" { + return 0, 0, errors.New("invalid Rule PortRange") + } + fromInt, err := strconv.ParseInt(from, 10, 64) + if err != nil { + return 0, 0, errors.New("invalid Rule PortRange") + } + toInt, err := strconv.ParseInt(to, 10, 64) + if err != nil { + return 0, 0, errors.New("invalid Rule PortRange") + } + if fromInt == -1 || toInt == -1 { + return int64(1), int64(65535), nil + } + if fromInt > 65535 || fromInt < -1 || toInt > 65535 || toInt < -1 { + return 0, 0, errors.New("invalid Rule PortRange") + } + if fromInt == toInt { + return fromInt, fromInt, nil + } else { + return fromInt, toInt, nil + } +} + +func convertCBRuleInfoToIbmRule(rules []irs.SecurityRuleInfo) (*[]vpcv1.SecurityGroupRulePrototype, error) { + var IbmSGRuleList []vpcv1.SecurityGroupRulePrototype + for _, securityRule := range rules { + protocol, err := convertRuleProtocolCBToIBM(securityRule.IPProtocol) + if err != nil { + return nil, err + } + if protocol == "tcp" || protocol == "udp" { + portMin, portMax, err := convertRulePortRangeCBToIBM(securityRule.FromPort, securityRule.ToPort) + if err != nil { + return nil, err + } + IbmSGRuleList = append(IbmSGRuleList, vpcv1.SecurityGroupRulePrototype{ + Direction: core.StringPtr(strings.ToLower(securityRule.Direction)), + Protocol: core.StringPtr(protocol), + PortMax: core.Int64Ptr(portMax), + PortMin: core.Int64Ptr(portMin), + IPVersion: core.StringPtr("ipv4"), + Remote: &vpcv1.SecurityGroupRuleRemotePrototype{ + CIDRBlock: &securityRule.CIDR, + }, + }) + } else { + IbmSGRuleList = append(IbmSGRuleList, vpcv1.SecurityGroupRulePrototype{ + Direction: core.StringPtr(strings.ToLower(securityRule.Direction)), + Protocol: core.StringPtr(protocol), + IPVersion: core.StringPtr("ipv4"), + Remote: &vpcv1.SecurityGroupRuleRemotePrototype{ + CIDRBlock: &securityRule.CIDR, + }, + }) + } + } + return &IbmSGRuleList, nil +} +func addDefaultOutBoundRule(baseRuleInfos []irs.SecurityRuleInfo, addRules *[]vpcv1.SecurityGroupRulePrototype) error { + defaultRuleInfo := irs.SecurityRuleInfo{ + CIDR: "0.0.0.0/0", + IPProtocol: "all", + FromPort: "-1", + ToPort: "-1", + Direction: "outbound", + } + addCheck := true + for _, rule := range baseRuleInfos { + if equalsRule(rule, defaultRuleInfo) { + addCheck = false + } + } + if addCheck { + *addRules = append(*addRules, vpcv1.SecurityGroupRulePrototype{ + Direction: core.StringPtr(strings.ToLower(defaultRuleInfo.Direction)), + Protocol: core.StringPtr(defaultRuleInfo.IPProtocol), + IPVersion: core.StringPtr("ipv4"), + Remote: &vpcv1.SecurityGroupRuleRemotePrototype{ + CIDRBlock: &defaultRuleInfo.CIDR, + }, + }) + } + return nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/TagHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/TagHandler.go index 90316d23d..676b4a054 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/TagHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/TagHandler.go @@ -1,574 +1,585 @@ -package resources - -import ( - "context" - "errors" - "fmt" - call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" - "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/utils/kubernetesserviceapiv1" - "strings" - - "github.com/IBM/platform-services-go-sdk/globalsearchv2" - "github.com/IBM/platform-services-go-sdk/globaltaggingv1" - "github.com/IBM/vpc-go-sdk/vpcv1" - 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 IbmTagHandler struct { - Region idrv.RegionInfo - CredentialInfo idrv.CredentialInfo - VpcService *vpcv1.VpcV1 - ClusterService *kubernetesserviceapiv1.KubernetesServiceApiV1 - Ctx context.Context - TaggingService *globaltaggingv1.GlobalTaggingV1 - SearchService *globalsearchv2.GlobalSearchV2 -} - -type TagList struct { - TotalCount *int64 `json:"total_count"` - Offset *int64 `json:"offset"` - Limit *int64 `json:"limit"` - Items []Tag `json:"items"` -} - -type Tag struct { - Name *string `json:"name" validate:"required"` -} - -type TagResults struct { - Results []TagResultsItem `json:"results"` -} - -type TagResultsItem struct { - ResourceID *string `json:"resource_id" validate:"required"` - IsError *bool `json:"is_error"` -} - -type Item struct { - CRN string - Name string - Tags []interface{} - Type string -} - -func rsTypeToIBMType(resType irs.RSType) string { - switch resType { - case irs.ALL: - return "*" - case irs.IMAGE: - return "image" - case irs.VPC: - return "vpc" - case irs.SUBNET: - return "subnet" - case irs.SG: - return "security-group" - case irs.KEY: - return "key" - case irs.VM: - return "instance" - case irs.NLB: - return "load-balancer" - case irs.DISK: - return "volume" - case irs.MYIMAGE: - return "snapshot" - case irs.CLUSTER: - return "k8-cluster" - case irs.NODEGROUP: - return "instance-group" - default: - return "" - } -} - -func ibmTypeToRSType(ibmType string) (irs.RSType, error) { - switch ibmType { - case "image": - return irs.IMAGE, nil - case "vpc": - return irs.VPC, nil - case "subnet": - return irs.SUBNET, nil - case "security-group": - return irs.SG, nil - case "key": - return irs.KEY, nil - case "instance": - return irs.VM, nil - case "load-balancer": - return irs.NLB, nil - case "volume": - return irs.DISK, nil - case "snapshot": - return irs.MYIMAGE, nil - case "k8-cluster": - return irs.CLUSTER, nil - case "instance-group": - return irs.NODEGROUP, nil - default: - return "", errors.New(fmt.Sprintf("unsupport type %s", ibmType)) - } -} - -func getTagFromResource(searchService *globalsearchv2.GlobalSearchV2, - resType irs.RSType, resIID irs.IID, key string) (irs.KeyValue, error) { - searchOptions := searchService.NewSearchOptions() - - var query string - - ibmType := rsTypeToIBMType(resType) - if ibmType == "" { - return irs.KeyValue{}, errors.New("invalid resource type") - } - - if resIID.NameId != "" { - query = fmt.Sprintf("type:%s AND name:%s", ibmType, resIID.NameId) - } else { - query = fmt.Sprintf("type:%s AND id:%s", ibmType, resIID.SystemId) - } - - searchOptions.SetQuery(query) - searchOptions.SearchCursor = nil - searchOptions.SetFields([]string{"name", "type", "crn", "tags"}) - searchOptions.SetLimit(100) - - for { - scanResult, _, err := searchService.Search(searchOptions) - if err != nil { - return irs.KeyValue{}, err - } - - if len(scanResult.Items) == 0 { - break - } - - searchOptions.SearchCursor = scanResult.SearchCursor - - for _, item := range scanResult.Items { - tags, ok := item.GetProperty("tags").([]interface{}) - if !ok { - cblogger.Error("Tags are not in expected format") - continue - } - for _, tag := range tags { - tagStr, ok := tag.(string) - if !ok { - cblogger.Errorf("Tag is not a string (%v)", tag) - continue - } - - parts := strings.SplitN(tagStr, ":", 2) - if parts[0] == key { - return irs.KeyValue{Key: parts[0], Value: parts[1]}, nil - } - } - } - } - - return irs.KeyValue{}, errors.New("tag not found") -} - -func attachOrDetachTag(tagService *globaltaggingv1.GlobalTaggingV1, tag irs.KeyValue, CRN string, action string) error { - resourceModel := globaltaggingv1.Resource{ - ResourceID: &CRN, - } - - var tagName string - if tag.Value == "" { - tagName = tag.Key - } else { - tagName = tag.Key + ":" + tag.Value - } - - switch action { - case "add": - attachTagOptions := tagService.NewAttachTagOptions( - []globaltaggingv1.Resource{resourceModel}, - ) - - attachTagOptions.SetTagNames([]string{tagName}) - attachTagOptions.SetTagType("user") - - _, _, err := tagService.AttachTag(attachTagOptions) - if err != nil { - return err - } - case "remove": - detachTagOptions := tagService.NewDetachTagOptions( - []globaltaggingv1.Resource{resourceModel}, - ) - - detachTagOptions.SetTagNames([]string{tagName}) - detachTagOptions.SetTagType("user") - - _, _, err := tagService.DetachTag(detachTagOptions) - if err != nil { - return err - } - - deleteTagAllOptions := tagService.NewDeleteTagAllOptions() - deleteTagAllOptions.SetTagType("user") - - _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) - if err != nil { - return err - } - } - - return nil -} - -func handleTagAddOrRemove(tagHandler *IbmTagHandler, resType irs.RSType, resIID irs.IID, - tag irs.KeyValue, action string) error { - var err2 error - - if action == "remove" { - tag, err2 = getTagFromResource(tagHandler.SearchService, resType, resIID, tag.Key) - if err2 != nil { - return err2 - } - } - - ibmType := rsTypeToIBMType(resType) - if ibmType == "" { - return errors.New("invalid resource type") - } else if ibmType == "all" { - return errors.New("all is not supported for getting tag from the resource") - } - - switch resType { - case irs.VPC: - vpc, err := GetRawVPC(resIID, tagHandler.VpcService, tagHandler.Ctx) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *vpc.CRN, action) - case irs.SUBNET: - subnet, err := getRawSubnet(resIID, tagHandler.VpcService, tagHandler.Ctx) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *subnet.CRN, action) - case irs.SG: - securityGroup, err := getRawSecurityGroup(resIID, tagHandler.VpcService, tagHandler.Ctx) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *securityGroup.CRN, action) - case irs.KEY: - vmKeyPair, err := getRawKey(resIID, tagHandler.VpcService, tagHandler.Ctx) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *vmKeyPair.CRN, action) - case irs.VM: - vm, err := getRawInstance(resIID, tagHandler.VpcService, tagHandler.Ctx) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *vm.CRN, action) - case irs.DISK: - disk, err := getRawVolume(resIID, tagHandler.VpcService, tagHandler.Ctx) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *disk.CRN, action) - // case irs.MYIMAGE: - // imageHandler := &IbmMyImageHandler{} - // rawMyimage, err := imageHandler.GetMyImage(resIID) - // if err != nil { - // err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - // break - // } - // err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *rawMyimage.CRN, action - case irs.NLB: - nlbHandler := &IbmNLBHandler{} // or however you initialize IbmNLBHandler - rawNLB, err := nlbHandler.getRawNLBByName(resIID.NameId) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *rawNLB.CRN, action) - case irs.CLUSTER: - clusterHandler := &IbmClusterHandler{ - CredentialInfo: tagHandler.CredentialInfo, - Region: tagHandler.Region, - Ctx: tagHandler.Ctx, - VpcService: tagHandler.VpcService, - ClusterService: tagHandler.ClusterService, - TaggingService: tagHandler.TaggingService, - } - rawCluster, err := clusterHandler.getRawCluster(resIID) - if err != nil { - err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) - break - } - - err2 = attachOrDetachTag(tagHandler.TaggingService, tag, rawCluster.Crn, action) - default: - return errors.New("invalid resource type") - } - - return err2 -} - -func (tagHandler *IbmTagHandler) AddTag(resType irs.RSType, resIID irs.IID, tag irs.KeyValue) (irs.KeyValue, error) { - hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "AddTag()") - start := call.Start() - - tagFound, _ := getTagFromResource(tagHandler.SearchService, resType, resIID, tag.Key) - if tagFound.Key == tag.Key { - return tagFound, errors.New("tag with provided key is already exists") - } - - err := handleTagAddOrRemove(tagHandler, resType, resIID, tag, "add") - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to add a tag. err = %s", err)) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.KeyValue{}, getErr - } - - LoggingInfo(hiscallInfo, start) - - return irs.KeyValue{Key: tag.Key, Value: tag.Value}, nil -} - -func (tagHandler *IbmTagHandler) ListTag(resType irs.RSType, resIID irs.IID) ([]irs.KeyValue, error) { - hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "ListTag()") - start := call.Start() - - ibmType := rsTypeToIBMType(resType) - if ibmType == "" { - return []irs.KeyValue{}, errors.New("invalid resource type") - } - - searchOptions := tagHandler.SearchService.NewSearchOptions() - - var query string - - if resIID.NameId != "" { - query = fmt.Sprintf("type:%s AND name:%s", ibmType, resIID.NameId) - } else { - query = fmt.Sprintf("type:%s AND id:%s", ibmType, resIID.SystemId) - } - - searchOptions.SetQuery(query) - searchOptions.SearchCursor = nil - searchOptions.SetFields([]string{"name", "type", "crn", "tags"}) - searchOptions.SetLimit(100) - - var tagList []irs.KeyValue - - for { - scanResult, _, err := tagHandler.SearchService.Search(searchOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to list tag. err = %s", err)) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return tagList, err - } - - if len(scanResult.Items) == 0 { - break - } - - searchOptions.SearchCursor = scanResult.SearchCursor - - for _, item := range scanResult.Items { - tags, ok := item.GetProperty("tags").([]interface{}) - if !ok { - cblogger.Error("Tags are not in expected format") - continue - } - for _, tag := range tags { - tagStr, ok := tag.(string) - if !ok { - cblogger.Error("Tag is not a string") - continue - } - - parts := strings.SplitN(tagStr, ":", 2) - tagList = append(tagList, irs.KeyValue{ - Key: parts[0], - Value: parts[1], - }) - } - } - } - - LoggingInfo(hiscallInfo, start) - - return tagList, nil -} - -func (tagHandler *IbmTagHandler) GetTag(resType irs.RSType, resIID irs.IID, key string) (irs.KeyValue, error) { - hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "GetTag()") - start := call.Start() - - tag, err := getTagFromResource(tagHandler.SearchService, resType, resIID, key) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to get tag. err = %s", err)) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.KeyValue{}, err - } - - LoggingInfo(hiscallInfo, start) - - return tag, nil -} - -func (tagHandler *IbmTagHandler) RemoveTag(resType irs.RSType, resIID irs.IID, key string) (bool, error) { - hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "RemoveTag()") - start := call.Start() - - err := handleTagAddOrRemove(tagHandler, resType, resIID, irs.KeyValue{Key: key}, "remove") - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to remove a tag. err = %s", err)) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return false, getErr - } - - LoggingInfo(hiscallInfo, start) - - return true, nil -} - -func (tagHandler *IbmTagHandler) FindTag(resType irs.RSType, keyword string) ([]*irs.TagInfo, error) { - hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, keyword, "FindTag()") - start := call.Start() - - ibmType := rsTypeToIBMType(resType) - if ibmType == "" { - return []*irs.TagInfo{}, errors.New("invalid resource type") - } - - searchOptions := tagHandler.SearchService.NewSearchOptions() - - query := fmt.Sprintf("type:%s", ibmType) - searchOptions.SetQuery(query) - searchOptions.SearchCursor = nil - searchOptions.SetFields([]string{"name", "resource_id", "type", "crn", "tags"}) - searchOptions.SetLimit(100) - - var tagInfo []*irs.TagInfo - - for { - scanResult, _, err := tagHandler.SearchService.Search(searchOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to list tag. err = %s", err)) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return tagInfo, err - } - - if len(scanResult.Items) == 0 { - break - } - - searchOptions.SearchCursor = scanResult.SearchCursor - - for _, item := range scanResult.Items { - var tagFound bool - - tags, ok := item.GetProperty("tags").([]interface{}) - if !ok { - cblogger.Error("Tags are not in expected format") - continue - } - for _, tag := range tags { - tagStr, ok := tag.(string) - if !ok { - cblogger.Errorf("Tag is not a string (%v)", tag) - continue - } - if strings.Contains(tagStr, keyword) { - tagFound = true - break - } - } - - if tagFound { - var tagKeyValue []irs.KeyValue - for _, tag := range tags { - tagStr, ok := tag.(string) - if !ok { - cblogger.Errorf("Tag is not a string (%v)", tag) - continue - } - parts := strings.SplitN(tagStr, ":", 2) - tagKeyValue = append(tagKeyValue, irs.KeyValue{ - Key: parts[0], - Value: parts[1], - }) - } - - rType, ok := item.GetProperty("type").(string) - if !ok { - cblogger.Error("type is not a string") - continue - } - rsType, err := ibmTypeToRSType(rType) - if err != nil { - cblogger.Error(err) - continue - } - - name, ok := item.GetProperty("name").(string) - if !ok { - cblogger.Error("name is not a string") - continue - } - resourceId, ok := item.GetProperty("resource_id").(string) - if !ok { - cblogger.Error("resource_id is not a string") - continue - } - - if rsType == irs.CLUSTER { - clusterHandler := &IbmClusterHandler{ - CredentialInfo: tagHandler.CredentialInfo, - Region: tagHandler.Region, - Ctx: tagHandler.Ctx, - VpcService: tagHandler.VpcService, - ClusterService: tagHandler.ClusterService, - TaggingService: tagHandler.TaggingService, - } - rawCluster, err := clusterHandler.getRawCluster(irs.IID{NameId: name}) - if err != nil { - cblogger.Error(err) - continue - } - resourceId = rawCluster.Id - } - - tagInfo = append(tagInfo, &irs.TagInfo{ - ResType: rsType, - ResIId: irs.IID{NameId: name, SystemId: resourceId}, - TagList: tagKeyValue, - KeyValueList: []irs.KeyValue{}, // reserved for optional usage - }) - } - } - } - - LoggingInfo(hiscallInfo, start) - - return tagInfo, nil -} +package resources + +import ( + "context" + "errors" + "fmt" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" + "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/utils/kubernetesserviceapiv1" + "strings" + + "github.com/IBM/platform-services-go-sdk/globalsearchv2" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/vpc-go-sdk/vpcv1" + 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 IbmTagHandler struct { + Region idrv.RegionInfo + CredentialInfo idrv.CredentialInfo + VpcService *vpcv1.VpcV1 + ClusterService *kubernetesserviceapiv1.KubernetesServiceApiV1 + Ctx context.Context + TaggingService *globaltaggingv1.GlobalTaggingV1 + SearchService *globalsearchv2.GlobalSearchV2 +} + +type TagList struct { + TotalCount *int64 `json:"total_count"` + Offset *int64 `json:"offset"` + Limit *int64 `json:"limit"` + Items []Tag `json:"items"` +} + +type Tag struct { + Name *string `json:"name" validate:"required"` +} + +type TagResults struct { + Results []TagResultsItem `json:"results"` +} + +type TagResultsItem struct { + ResourceID *string `json:"resource_id" validate:"required"` + IsError *bool `json:"is_error"` +} + +type Item struct { + CRN string + Name string + Tags []interface{} + Type string +} + +func rsTypeToIBMType(resType irs.RSType) string { + switch resType { + case irs.ALL: + return "*" + case irs.IMAGE: + return "image" + case irs.VPC: + return "vpc" + case irs.SUBNET: + return "subnet" + case irs.SG: + return "security-group" + case irs.KEY: + return "key" + case irs.VM: + return "instance" + case irs.NLB: + return "load-balancer" + case irs.DISK: + return "volume" + case irs.MYIMAGE: + return "snapshot" + case irs.CLUSTER: + return "k8-cluster" + // NODEGROUP's Not Support + // case irs.NODEGROUP: + // return "instance-group" + default: + return "" + } +} + +func ibmTypeToRSType(ibmType string) (irs.RSType, error) { + switch ibmType { + case "image": + return irs.IMAGE, nil + case "vpc": + return irs.VPC, nil + case "subnet": + return irs.SUBNET, nil + case "security-group": + return irs.SG, nil + case "key": + return irs.KEY, nil + case "instance": + return irs.VM, nil + case "load-balancer": + return irs.NLB, nil + case "volume": + return irs.DISK, nil + case "snapshot": + return irs.MYIMAGE, nil + case "k8-cluster": + return irs.CLUSTER, nil + case "instance-group": + return irs.NODEGROUP, nil + default: + return "", errors.New(fmt.Sprintf("unsupport type %s", ibmType)) + } +} + +func getTagFromResource(searchService *globalsearchv2.GlobalSearchV2, + resType irs.RSType, resIID irs.IID, key string) (irs.KeyValue, error) { + searchOptions := searchService.NewSearchOptions() + + var query string + + ibmType := rsTypeToIBMType(resType) + if ibmType == "" { + return irs.KeyValue{}, errors.New("invalid resource type") + } + + if resIID.NameId != "" { + query = fmt.Sprintf("type:%s AND name:%s", ibmType, resIID.NameId) + } else { + query = fmt.Sprintf("type:%s AND id:%s", ibmType, resIID.SystemId) + } + + searchOptions.SetQuery(query) + searchOptions.SearchCursor = nil + searchOptions.SetFields([]string{"name", "type", "crn", "tags"}) + searchOptions.SetLimit(100) + + for { + scanResult, _, err := searchService.Search(searchOptions) + if err != nil { + return irs.KeyValue{}, err + } + + if len(scanResult.Items) == 0 { + break + } + + searchOptions.SearchCursor = scanResult.SearchCursor + + for _, item := range scanResult.Items { + tags, ok := item.GetProperty("tags").([]interface{}) + if !ok { + cblogger.Error("Tags are not in expected format") + continue + } + for _, tag := range tags { + tagStr, ok := tag.(string) + if !ok { + cblogger.Errorf("Tag is not a string (%v)", tag) + continue + } + + parts := strings.SplitN(tagStr, ":", 2) + if parts[0] == key { + return irs.KeyValue{Key: parts[0], Value: parts[1]}, nil + } + } + } + } + + return irs.KeyValue{}, errors.New("tag not found") +} + +func attachOrDetachTag(tagService *globaltaggingv1.GlobalTaggingV1, tag irs.KeyValue, CRN string, action string) error { + resourceModel := globaltaggingv1.Resource{ + ResourceID: &CRN, + } + + var tagName string + if tag.Value == "" { + tagName = tag.Key + } else { + tagName = tag.Key + ":" + tag.Value + } + + switch action { + case "add": + attachTagOptions := tagService.NewAttachTagOptions( + []globaltaggingv1.Resource{resourceModel}, + ) + + attachTagOptions.SetTagNames([]string{tagName}) + attachTagOptions.SetTagType("user") + + _, _, err := tagService.AttachTag(attachTagOptions) + if err != nil { + return err + } + case "remove": + detachTagOptions := tagService.NewDetachTagOptions( + []globaltaggingv1.Resource{resourceModel}, + ) + + detachTagOptions.SetTagNames([]string{tagName}) + detachTagOptions.SetTagType("user") + + _, _, err := tagService.DetachTag(detachTagOptions) + if err != nil { + return err + } + + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + return err + } + } + + return nil +} + +func handleTagAddOrRemove(tagHandler *IbmTagHandler, resType irs.RSType, resIID irs.IID, + tag irs.KeyValue, action string) error { + var err2 error + + if action == "remove" { + tag, err2 = getTagFromResource(tagHandler.SearchService, resType, resIID, tag.Key) + if err2 != nil { + return err2 + } + } + + ibmType := rsTypeToIBMType(resType) + if ibmType == "" { + return errors.New("invalid resource type") + } else if ibmType == "all" { + return errors.New("all is not supported for getting tag from the resource") + } + + switch resType { + case irs.VPC: + vpc, err := GetRawVPC(resIID, tagHandler.VpcService, tagHandler.Ctx) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *vpc.CRN, action) + case irs.SUBNET: + subnet, err := getRawSubnet(resIID, tagHandler.VpcService, tagHandler.Ctx) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *subnet.CRN, action) + case irs.SG: + securityGroup, err := getRawSecurityGroup(resIID, tagHandler.VpcService, tagHandler.Ctx) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *securityGroup.CRN, action) + case irs.KEY: + vmKeyPair, err := getRawKey(resIID, tagHandler.VpcService, tagHandler.Ctx) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *vmKeyPair.CRN, action) + case irs.VM: + vm, err := getRawInstance(resIID, tagHandler.VpcService, tagHandler.Ctx) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *vm.CRN, action) + case irs.DISK: + disk, err := getRawVolume(resIID, tagHandler.VpcService, tagHandler.Ctx) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *disk.CRN, action) + case irs.MYIMAGE: + imageHandler := &IbmMyImageHandler{ + CredentialInfo: tagHandler.CredentialInfo, + Region: tagHandler.Region, + VpcService: tagHandler.VpcService, + Ctx: tagHandler.Ctx, + } + rawMyimage, err := imageHandler.GetRawMyImage(resIID) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *rawMyimage.CRN, action) + case irs.NLB: + nlbHandler := &IbmNLBHandler{ + CredentialInfo: tagHandler.CredentialInfo, + Region: tagHandler.Region, + VpcService: tagHandler.VpcService, + Ctx: tagHandler.Ctx, + } + rawNLB, err := nlbHandler.getRawNLBByName(resIID.NameId) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, *rawNLB.CRN, action) + case irs.CLUSTER: + clusterHandler := &IbmClusterHandler{ + CredentialInfo: tagHandler.CredentialInfo, + Region: tagHandler.Region, + Ctx: tagHandler.Ctx, + VpcService: tagHandler.VpcService, + ClusterService: tagHandler.ClusterService, + TaggingService: tagHandler.TaggingService, + } + rawCluster, err := clusterHandler.getRawCluster(resIID) + if err != nil { + err2 = errors.New(fmt.Sprintf("Failed to add tag. err = %s", err)) + break + } + + err2 = attachOrDetachTag(tagHandler.TaggingService, tag, rawCluster.Crn, action) + default: + return errors.New("invalid resource type") + } + + return err2 +} + +func (tagHandler *IbmTagHandler) AddTag(resType irs.RSType, resIID irs.IID, tag irs.KeyValue) (irs.KeyValue, error) { + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "AddTag()") + start := call.Start() + + tagFound, _ := getTagFromResource(tagHandler.SearchService, resType, resIID, tag.Key) + if tagFound.Key == tag.Key { + return tagFound, errors.New("tag with provided key is already exists") + } + + err := handleTagAddOrRemove(tagHandler, resType, resIID, tag, "add") + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to add a tag. err = %s", err)) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.KeyValue{}, getErr + } + + LoggingInfo(hiscallInfo, start) + + return irs.KeyValue{Key: tag.Key, Value: tag.Value}, nil +} + +func (tagHandler *IbmTagHandler) ListTag(resType irs.RSType, resIID irs.IID) ([]irs.KeyValue, error) { + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "ListTag()") + start := call.Start() + + ibmType := rsTypeToIBMType(resType) + if ibmType == "" { + return []irs.KeyValue{}, errors.New("invalid resource type") + } + + searchOptions := tagHandler.SearchService.NewSearchOptions() + + var query string + + if resIID.NameId != "" { + query = fmt.Sprintf("type:%s AND name:%s", ibmType, resIID.NameId) + } else { + query = fmt.Sprintf("type:%s AND id:%s", ibmType, resIID.SystemId) + } + + searchOptions.SetQuery(query) + searchOptions.SearchCursor = nil + searchOptions.SetFields([]string{"name", "type", "crn", "tags"}) + searchOptions.SetLimit(100) + + var tagList []irs.KeyValue + + for { + scanResult, _, err := tagHandler.SearchService.Search(searchOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to list tag. err = %s", err)) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return tagList, err + } + + if len(scanResult.Items) == 0 { + break + } + + searchOptions.SearchCursor = scanResult.SearchCursor + + for _, item := range scanResult.Items { + tags, ok := item.GetProperty("tags").([]interface{}) + if !ok { + cblogger.Error("Tags are not in expected format") + continue + } + for _, tag := range tags { + tagStr, ok := tag.(string) + if !ok { + cblogger.Error("Tag is not a string") + continue + } + + parts := strings.SplitN(tagStr, ":", 2) + tagList = append(tagList, irs.KeyValue{ + Key: parts[0], + Value: parts[1], + }) + } + } + } + + LoggingInfo(hiscallInfo, start) + + return tagList, nil +} + +func (tagHandler *IbmTagHandler) GetTag(resType irs.RSType, resIID irs.IID, key string) (irs.KeyValue, error) { + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "GetTag()") + start := call.Start() + + tag, err := getTagFromResource(tagHandler.SearchService, resType, resIID, key) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to get tag. err = %s", err)) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.KeyValue{}, err + } + + LoggingInfo(hiscallInfo, start) + + return tag, nil +} + +func (tagHandler *IbmTagHandler) RemoveTag(resType irs.RSType, resIID irs.IID, key string) (bool, error) { + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, resIID.NameId, "RemoveTag()") + start := call.Start() + + err := handleTagAddOrRemove(tagHandler, resType, resIID, irs.KeyValue{Key: key}, "remove") + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to remove a tag. err = %s", err)) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return false, getErr + } + + LoggingInfo(hiscallInfo, start) + + return true, nil +} + +func (tagHandler *IbmTagHandler) FindTag(resType irs.RSType, keyword string) ([]*irs.TagInfo, error) { + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, keyword, "FindTag()") + start := call.Start() + + ibmType := rsTypeToIBMType(resType) + if ibmType == "" { + return []*irs.TagInfo{}, errors.New("invalid resource type") + } + + searchOptions := tagHandler.SearchService.NewSearchOptions() + + query := fmt.Sprintf("type:%s", ibmType) + searchOptions.SetQuery(query) + searchOptions.SearchCursor = nil + searchOptions.SetFields([]string{"name", "resource_id", "type", "crn", "tags"}) + searchOptions.SetLimit(100) + + var tagInfo []*irs.TagInfo + + for { + scanResult, _, err := tagHandler.SearchService.Search(searchOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to list tag. err = %s", err)) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return tagInfo, err + } + + if len(scanResult.Items) == 0 { + break + } + + searchOptions.SearchCursor = scanResult.SearchCursor + + for _, item := range scanResult.Items { + var tagFound bool + + tags, ok := item.GetProperty("tags").([]interface{}) + if !ok { + cblogger.Error("Tags are not in expected format") + continue + } + for _, tag := range tags { + tagStr, ok := tag.(string) + if !ok { + cblogger.Errorf("Tag is not a string (%v)", tag) + continue + } + if strings.Contains(tagStr, keyword) { + tagFound = true + break + } + } + + if tagFound { + var tagKeyValue []irs.KeyValue + for _, tag := range tags { + tagStr, ok := tag.(string) + if !ok { + cblogger.Errorf("Tag is not a string (%v)", tag) + continue + } + parts := strings.SplitN(tagStr, ":", 2) + tagKeyValue = append(tagKeyValue, irs.KeyValue{ + Key: parts[0], + Value: parts[1], + }) + } + + rType, ok := item.GetProperty("type").(string) + if !ok { + cblogger.Error("type is not a string") + continue + } + rsType, err := ibmTypeToRSType(rType) + if err != nil { + cblogger.Error(err) + continue + } + + name, ok := item.GetProperty("name").(string) + if !ok { + cblogger.Error("name is not a string") + continue + } + resourceId, ok := item.GetProperty("resource_id").(string) + if !ok { + cblogger.Error("resource_id is not a string") + continue + } + + if rsType == irs.CLUSTER { + clusterHandler := &IbmClusterHandler{ + CredentialInfo: tagHandler.CredentialInfo, + Region: tagHandler.Region, + Ctx: tagHandler.Ctx, + VpcService: tagHandler.VpcService, + ClusterService: tagHandler.ClusterService, + TaggingService: tagHandler.TaggingService, + } + rawCluster, err := clusterHandler.getRawCluster(irs.IID{NameId: name}) + if err != nil { + cblogger.Error(err) + continue + } + resourceId = rawCluster.Id + } + + tagInfo = append(tagInfo, &irs.TagInfo{ + ResType: rsType, + ResIId: irs.IID{NameId: name, SystemId: resourceId}, + TagList: tagKeyValue, + KeyValueList: []irs.KeyValue{}, // reserved for optional usage + }) + } + } + } + + LoggingInfo(hiscallInfo, start) + + return tagInfo, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VMHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VMHandler.go index e131422ae..256767de8 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VMHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VMHandler.go @@ -1,1427 +1,1452 @@ -package resources - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "github.com/IBM/go-sdk-core/v5/core" - vpcv0230 "github.com/IBM/vpc-go-sdk/0.23.0/vpcv1" - "github.com/IBM/vpc-go-sdk/vpcv1" - call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" - cdcom "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/common" - idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" - irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" - "io/ioutil" - "math/rand" - "net/url" - "os" - "sort" - "strconv" - "strings" - "sync" - "time" -) - -type IbmVMHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - VpcService *vpcv1.VpcV1 - VpcService0230 *vpcv0230.VpcV1 - Ctx context.Context -} - -func (vmHandler *IbmVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmReqInfo.IId.NameId, "StartVM()") - start := call.Start() - - // 1.Check VMReqInfo - err := checkVMReqInfo(vmReqInfo) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - - // 1-1 Exist Check - exist, err := existInstance(vmReqInfo.IId, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } else if exist { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = The VM name %s already exists", vmReqInfo.IId.NameId)) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - // 1-2. Setup Req Resource IID - var image vpcv1.Image - var myImage irs.MyImageInfo - var isWindows bool - if vmReqInfo.ImageType == irs.MyImage { - myImageHandler := IbmMyImageHandler{ - CredentialInfo: vmHandler.CredentialInfo, - Region: vmHandler.Region, - VpcService: vmHandler.VpcService, - Ctx: vmHandler.Ctx, - } - var getMyImageErr error - myImage, getMyImageErr = myImageHandler.GetMyImage(vmReqInfo.ImageIID) - if getMyImageErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", getMyImageErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - if myImage.Status != irs.MyImageAvailable { - createErr := errors.New("Failed to Create VM. err = Source Image status is not Available") - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - rawSnapshot, _, getRawSnapshotErr := myImageHandler.VpcService.GetSnapshotWithContext(myImageHandler.Ctx, &vpcv1.GetSnapshotOptions{ID: &myImage.IId.SystemId}) - if getRawSnapshotErr != nil { - createErr := errors.New("Failed to Create VM. err = Cannot get Snapshot Detail of Source MyImage") - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - - isWindows = strings.Contains(strings.ToLower(*rawSnapshot.OperatingSystem.Name), "windows") - } else { - var getImageErr error - image, getImageErr = getRawImage(vmReqInfo.ImageIID, vmHandler.VpcService, vmHandler.Ctx) - if getImageErr != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", getImageErr.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - - isWindows = strings.Contains(strings.ToLower(*image.OperatingSystem.Name), "windows") - } - - vpc, err := GetRawVPC(vmReqInfo.VpcIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - vpcSubnet, err := getVPCRawSubnet(vpc, vmReqInfo.SubnetIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - key, err := getRawKey(vmReqInfo.KeyPairIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - spec, err := getRawSpec(vmReqInfo.VMSpecName, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - var securityGroups []vpcv1.SecurityGroup - if vmReqInfo.SecurityGroupIIDs != nil { - for _, SecurityGroupIID := range vmReqInfo.SecurityGroupIIDs { - err := checkSecurityGroupIID(SecurityGroupIID) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - securityGroup, err := getRawSecurityGroup(SecurityGroupIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - securityGroups = append(securityGroups, securityGroup) - } - } - - // 1-3. cloud-init data set - var userData string - if isWindows { - userId := vmReqInfo.VMUserId - if userId == "" { - userId = "Administrator" - } - - pwValidErr := cdcom.ValidateWindowsPassword(vmReqInfo.VMUserPasswd) - if pwValidErr != nil { - return irs.VMInfo{}, pwValidErr - } - - userData = fmt.Sprintf("#ps1_sysnative\nnet user \"%s\" \"%s\"", userId, vmReqInfo.VMUserPasswd) - } else { - rootPath := os.Getenv("CBSPIDER_ROOT") - fileDataCloudInit, err := ioutil.ReadFile(rootPath + CBCloudInitFilePath) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - userData = string(fileDataCloudInit) - userData = strings.ReplaceAll(userData, "{{username}}", CBDefaultVmUserName) - } - - // 2.Create VM - // TODO : UserData cloudInit - createInstanceOptions := &vpcv0230.CreateInstanceOptions{} - - var existingDataVolumeAttachments []vpcv0230.VolumeAttachmentPrototypeInstanceContext - for _, dataVolumeIID := range vmReqInfo.DataDiskIIDs { - rawDisk, getRawDiskErr := getRawDisk(vmHandler.VpcService, vmHandler.Ctx, dataVolumeIID) - if getRawDiskErr == nil { - existingDataVolumeAttachments = append(existingDataVolumeAttachments, vpcv0230.VolumeAttachmentPrototypeInstanceContext{ - Volume: &vpcv0230.VolumeAttachmentVolumePrototypeInstanceContextVolumeIdentity{ID: rawDisk.ID}, - }) - } - } - - if vmReqInfo.ImageType == irs.MyImage { - snapshotList, _, listSnapshotErr := vmHandler.VpcService.ListSnapshotsWithContext(vmHandler.Ctx, &vpcv1.ListSnapshotsOptions{}) - if listSnapshotErr != nil { - return irs.VMInfo{}, errors.New(fmt.Sprintf("Failed to Get MyImage. err = %s", listSnapshotErr.Error())) - } - - var associatedSnapshots []vpcv1.Snapshot - for _, snapshot := range snapshotList.Snapshots { - if strings.Split(*snapshot.Name, DEV)[0] == myImage.IId.NameId { - associatedSnapshots = append(associatedSnapshots, snapshot) - } - } - - sort.Slice(associatedSnapshots, func(i, j int) bool { - return *associatedSnapshots[i].Name < *associatedSnapshots[j].Name - }) - - var dataVolumeAttachments []vpcv0230.VolumeAttachmentPrototypeInstanceContext - var bootVolumeAttachment vpcv0230.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext - for _, snapshot := range associatedSnapshots { - sourceVolume, _, getSourceVolumeErr := vmHandler.VpcService0230.GetVolumeWithContext(vmHandler.Ctx, &vpcv0230.GetVolumeOptions{ID: snapshot.SourceVolume.ID}) - if getSourceVolumeErr != nil { - return irs.VMInfo{}, errors.New(fmt.Sprintf("Failed to Get Source Volume. err = %s", getSourceVolumeErr.Error())) - } - - volumeName := fmt.Sprintf("%s%s%s", vmReqInfo.IId.NameId, DEV, strings.Split(*snapshot.Name, DEV)[1]) - if *snapshot.Bootable { - bootVolumeAttachment = vpcv0230.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext{ - Volume: &vpcv0230.VolumePrototypeInstanceBySourceSnapshotContext{ - Name: core.StringPtr(volumeName), - Profile: &vpcv0230.VolumeProfileIdentityByName{Name: sourceVolume.Profile.Name}, - Capacity: sourceVolume.Capacity, - SourceSnapshot: &vpcv0230.SnapshotIdentityByID{ID: snapshot.ID}, - }, - } - } else { - model := vpcv0230.VolumeAttachmentPrototypeInstanceContext{ - Volume: &vpcv0230.VolumeAttachmentVolumePrototypeInstanceContextVolumePrototypeInstanceContextVolumePrototypeInstanceContextVolumeBySourceSnapshot{ - Name: core.StringPtr(volumeName), - Profile: &vpcv0230.VolumeProfileIdentityByName{Name: sourceVolume.Profile.Name}, - Capacity: sourceVolume.Capacity, - SourceSnapshot: &vpcv0230.SnapshotIdentityByID{ID: snapshot.ID}, - }, - } - - dataVolumeAttachments = append(dataVolumeAttachments, model) - } - } - - dataVolumeAttachments = append(dataVolumeAttachments, existingDataVolumeAttachments...) - - createInstanceOptions.SetInstancePrototype(&vpcv0230.InstancePrototypeInstanceBySourceSnapshot{ - Name: &vmReqInfo.IId.NameId, - BootVolumeAttachment: &bootVolumeAttachment, - VolumeAttachments: dataVolumeAttachments, - Profile: &vpcv0230.InstanceProfileIdentity{ - Name: spec.Name, - }, - Zone: &vpcv0230.ZoneIdentity{ - Name: &vmHandler.Region.Zone, - }, - PrimaryNetworkInterface: &vpcv0230.NetworkInterfacePrototype{ - Subnet: &vpcv0230.SubnetIdentity{ - ID: vpcSubnet.ID, - }, - }, - Keys: []vpcv0230.KeyIdentityIntf{ - &vpcv0230.KeyIdentity{ - ID: key.ID, - }, - }, - VPC: &vpcv0230.VPCIdentity{ - ID: vpc.ID, - }, - UserData: &userData, - }) - } else { - createInstanceOptions.SetInstancePrototype(&vpcv0230.InstancePrototype{ - Name: &vmReqInfo.IId.NameId, - Image: &vpcv0230.ImageIdentity{ - ID: image.ID, - }, - Profile: &vpcv0230.InstanceProfileIdentity{ - Name: spec.Name, - }, - Zone: &vpcv0230.ZoneIdentity{ - Name: &vmHandler.Region.Zone, - }, - PrimaryNetworkInterface: &vpcv0230.NetworkInterfacePrototype{ - Subnet: &vpcv0230.SubnetIdentity{ - ID: vpcSubnet.ID, - }, - }, - Keys: []vpcv0230.KeyIdentityIntf{ - &vpcv0230.KeyIdentity{ - ID: key.ID, - }, - }, - VPC: &vpcv0230.VPCIdentity{ - ID: vpc.ID, - }, - UserData: &userData, - VolumeAttachments: existingDataVolumeAttachments, - }) - } - - createInstance, _, err := vmHandler.VpcService0230.CreateInstanceWithContext(vmHandler.Ctx, createInstanceOptions) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - - // 3.Attach SecurityGroup - if securityGroups != nil && len(securityGroups) > 0 { - for _, securityGroup := range securityGroups { - options := &vpcv1.AddSecurityGroupNetworkInterfaceOptions{} - options.SetSecurityGroupID(*securityGroup.ID) - options.SetID(*createInstance.PrimaryNetworkInterface.ID) - _, _, err = vmHandler.VpcService.AddSecurityGroupNetworkInterfaceWithContext(vmHandler.Ctx, options) - if err != nil { - //TODO DELETE - deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - if deleteErr != nil { - newErrText := err.Error() + deleteErr.Error() - err = errors.New(newErrText) - } - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - } - } - } - - // 4.Attach FloatingIP - - // 4-1. Create FloatingIP - rand.Seed(time.Now().UnixNano()) - floatingIPName := *createInstance.Zone.Name + "-floatingip-" + strconv.FormatInt(rand.Int63n(10000000), 10) - floatingIPExist, err := vmHandler.checkFloatingIPName(floatingIPName) - if err != nil || floatingIPExist { - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = Faild Generator FloatingIP Name")) - deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) - if deleteErr != nil { - createErr = errors.New(fmt.Sprintf("%s, %s ", createErr.Error(), deleteErr.Error())) - } - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - createFloatingIPOptions := &vpcv1.CreateFloatingIPOptions{} - createFloatingIPOptions.SetFloatingIPPrototype(&vpcv1.FloatingIPPrototype{ - Name: &floatingIPName, - Zone: &vpcv1.ZoneIdentity{ - Name: createInstance.Zone.Name, - }, - }) - - floatingIP, _, err := vmHandler.VpcService.CreateFloatingIPWithContext(vmHandler.Ctx, createFloatingIPOptions) - - if err != nil { - deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - if deleteErr != nil { - newErrText := err.Error() + deleteErr.Error() - err = errors.New(newErrText) - } - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - - // 4-2. Bind FloatingIP - ipBindInfo := IBMIPBindReqInfo{ - vmID: *createInstance.ID, - floatingIPID: *floatingIP.ID, - NetworkInterfaceID: *createInstance.PrimaryNetworkInterface.ID, - } - - _, err = floatingIPBind(ipBindInfo, vmHandler.VpcService, vmHandler.Ctx) - - if err != nil { - deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - if deleteErr != nil { - newErrText := err.Error() + deleteErr.Error() - err = errors.New(newErrText) - } - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - } - createInstanceIId := irs.IID{ - NameId: *createInstance.Name, - SystemId: *createInstance.ID, - } - // TODO : runnigCheck - curRetryCnt := 0 - maxRetryCnt := 120 - for { - finalInstance, err := getRawInstance(createInstanceIId, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - removeFloatingIpsErr := removeFloatingIps(finalInstance, vmHandler.VpcService, vmHandler.Ctx) - // 생성 완료후 running 기다리는중 에러. - // 제거 로직을 위해 removeFloatingIp - if removeFloatingIpsErr != nil { - // 제거 로직을 위해 removeFloatingIp Error => instance에 대한 에러 + removeError + delete error - newErrText := err.Error() + removeFloatingIpsErr.Error() + "and failed delete VM" - err = errors.New(newErrText) - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - // 제거 로직을 위해 deleteInstance - deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) - if deleteErr != nil { - newErrText := err.Error() + deleteErr.Error() - err = errors.New(newErrText) - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - err = errors.New("failed to create VM") - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - if *finalInstance.Status == "running" { - finalInstanceInfo, err := vmHandler.setVmInfo(finalInstance) - if err != nil { - removeFloatingIpsErr := removeFloatingIps(finalInstance, vmHandler.VpcService, vmHandler.Ctx) - // 생성 완료후 running 기다리는중 에러. - // 제거 로직을 위해 removeFloatingIp - if removeFloatingIpsErr != nil { - // 제거 로직을 위해 removeFloatingIp Error => instance에 대한 에러 + removeError + delete error - newErrText := err.Error() + removeFloatingIpsErr.Error() + "and failed delete VM" - err = errors.New(newErrText) - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - // 제거 로직을 위해 deleteInstance - deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) - if deleteErr != nil { - newErrText := err.Error() + deleteErr.Error() - err = errors.New(newErrText) - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - err = errors.New("failed to create VM") - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - LoggingInfo(hiscallInfo, start) - if isWindows { - finalInstanceInfo.VMUserPasswd = vmReqInfo.VMUserPasswd - } - return finalInstanceInfo, nil - } - curRetryCnt++ - time.Sleep(1 * time.Second) - if curRetryCnt > maxRetryCnt { - err = errors.New(fmt.Sprintf("failed to create VM, exceeded maximum retry count %d", maxRetryCnt)) - removeFloatingIpsErr := removeFloatingIps(finalInstance, vmHandler.VpcService, vmHandler.Ctx) - // 생성 완료후 running 기다리는중 에러. - // 제거 로직을 위해 removeFloatingIp - if removeFloatingIpsErr != nil { - // 제거 로직을 위해 removeFloatingIp Error => instance에 대한 에러 + removeError + delete error - newErrText := err.Error() + removeFloatingIpsErr.Error() + "and failed delete VM" - err = errors.New(newErrText) - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - // 제거 로직을 위해 deleteInstance - deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) - if deleteErr != nil { - newErrText := err.Error() + deleteErr.Error() - err = errors.New(newErrText) - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - err = errors.New("failed to create VM") - createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VMInfo{}, createErr - } - } -} -func (vmHandler *IbmVMHandler) SuspendVM(vmIID irs.IID) (irs.VMStatus, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "SuspendVM()") - start := call.Start() - err := checkVmIID(vmIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - err = getSuspendVMCheck(*instance.Status) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - instanceActionOptions := &vpcv1.CreateInstanceActionOptions{} - instanceActionOptions.SetInstanceID(*instance.ID) - instanceActionOptions.SetType("stop") - _, _, err = vmHandler.VpcService.CreateInstanceActionWithContext(vmHandler.Ctx, instanceActionOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - LoggingInfo(hiscallInfo, start) - return irs.Suspending, nil -} -func (vmHandler *IbmVMHandler) ResumeVM(vmIID irs.IID) (irs.VMStatus, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "ResumeVM()") - start := call.Start() - err := checkVmIID(vmIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - err = getResumeVMCheck(*instance.Status) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - instanceActionOptions := &vpcv1.CreateInstanceActionOptions{} - instanceActionOptions.SetInstanceID(*instance.ID) - instanceActionOptions.SetType("start") - instanceActionOptions.SetForce(true) - _, _, err = vmHandler.VpcService.CreateInstanceActionWithContext(vmHandler.Ctx, instanceActionOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - LoggingInfo(hiscallInfo, start) - return irs.Resuming, nil -} -func (vmHandler *IbmVMHandler) RebootVM(vmIID irs.IID) (irs.VMStatus, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "RebootVM()") - start := call.Start() - err := checkVmIID(vmIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - err = getRebootCheck(*instance.Status) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - instanceActionOptions := &vpcv1.CreateInstanceActionOptions{} - instanceActionOptions.SetInstanceID(*instance.ID) - instanceActionOptions.SetType("reboot") - instanceActionOptions.SetForce(true) - _, _, err = vmHandler.VpcService.CreateInstanceActionWithContext(vmHandler.Ctx, instanceActionOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.Failed, getErr - } - LoggingInfo(hiscallInfo, start) - return irs.Rebooting, nil -} -func (vmHandler *IbmVMHandler) TerminateVM(vmIID irs.IID) (irs.VMStatus, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "TerminateVM()") - start := call.Start() - err := checkVmIID(vmIID) - if err != nil { - TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) - cblogger.Error(TerminateErr.Error()) - LoggingError(hiscallInfo, TerminateErr) - return irs.Failed, TerminateErr - } - instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) - cblogger.Error(TerminateErr.Error()) - LoggingError(hiscallInfo, TerminateErr) - return irs.Failed, TerminateErr - } - err = removeFloatingIps(instance, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) - cblogger.Error(TerminateErr.Error()) - LoggingError(hiscallInfo, TerminateErr) - return irs.Failed, TerminateErr - } - err = deleteInstance(*instance.ID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) - cblogger.Error(TerminateErr.Error()) - LoggingError(hiscallInfo, TerminateErr) - return irs.Failed, TerminateErr - } - LoggingInfo(hiscallInfo, start) - return irs.Terminating, nil -} - -func (vmHandler *IbmVMHandler) ListVMStatus() ([]*irs.VMStatusInfo, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, "VMStatus", "ListVMStatus()") - start := call.Start() - options := &vpcv1.ListInstancesOptions{} - instances, _, err := vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, options) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VMStatus. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - var vmStatusList []*irs.VMStatusInfo - for { - for _, instance := range instances.Instances { - vmStatusString, _ := convertInstanceStatus(*instance.Status) - VMStatusInfo := irs.VMStatusInfo{ - IId: irs.IID{ - NameId: *instance.Name, - SystemId: *instance.ID, - }, - VmStatus: vmStatusString, - } - - vmStatusList = append(vmStatusList, &VMStatusInfo) - } - nextstr, _ := getVMNextHref(instances.Next) - if nextstr != "" { - listVpcsOptions2 := &vpcv1.ListInstancesOptions{ - Start: core.StringPtr(nextstr), - } - instances, _, err = vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, listVpcsOptions2) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VMStatus. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - } else { - break - } - } - LoggingInfo(hiscallInfo, start) - return vmStatusList, nil -} -func (vmHandler *IbmVMHandler) GetVMStatus(vmIID irs.IID) (irs.VMStatus, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "GetVMStatus()") - start := call.Start() - err := checkVmIID(vmIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VMStatus. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return "", getErr - } - instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VMStatus. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return "", getErr - } - LoggingInfo(hiscallInfo, start) - return convertInstanceStatus(*instance.Status) -} - -func (vmHandler *IbmVMHandler) ListVM() ([]*irs.VMInfo, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, "VM", "ListVM()") - start := call.Start() - options := &vpcv1.ListInstancesOptions{} - instances, _, err := vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, options) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - - var vmInstanceList []vpcv1.Instance - - for { - vmInstanceList = append(vmInstanceList, instances.Instances...) - nextstr, _ := getVMNextHref(instances.Next) - if nextstr != "" { - listVpcsOptions2 := &vpcv1.ListInstancesOptions{ - Start: core.StringPtr(nextstr), - } - instances, _, err = vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, listVpcsOptions2) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - //break - } - } else { - break - } - } - - vmList, err := vmHandler.setVMList(vmInstanceList) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - LoggingInfo(hiscallInfo, start) - return vmList, nil -} - -func (vmHandler *IbmVMHandler) GetVM(vmIID irs.IID) (irs.VMInfo, error) { - hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "GetVM()") - start := call.Start() - err := checkVmIID(vmIID) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.VMInfo{}, getErr - } - instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.VMInfo{}, getErr - } - - vmInfo, err := vmHandler.setVmInfo(instance) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VM. err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.VMInfo{}, getErr - } - LoggingInfo(hiscallInfo, start) - return vmInfo, nil -} - -type IBMIPBindReqInfo struct { - vmID string - floatingIPID string - NetworkInterfaceID string -} - -func floatingIPBind(IPBindReqInfo IBMIPBindReqInfo, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.FloatingIP, error) { - if IPBindReqInfo.vmID == "" || IPBindReqInfo.floatingIPID == "" || IPBindReqInfo.NetworkInterfaceID == "" { - return vpcv1.FloatingIP{}, errors.New("invalid IDs") - } - addInstanceNetworkInterfaceFloatingIPOptions := &vpcv1.AddInstanceNetworkInterfaceFloatingIPOptions{} - addInstanceNetworkInterfaceFloatingIPOptions.SetID(IPBindReqInfo.floatingIPID) - addInstanceNetworkInterfaceFloatingIPOptions.SetInstanceID(IPBindReqInfo.vmID) - addInstanceNetworkInterfaceFloatingIPOptions.SetNetworkInterfaceID(IPBindReqInfo.NetworkInterfaceID) - floatingIP, _, err := vpcService.AddInstanceNetworkInterfaceFloatingIPWithContext(ctx, addInstanceNetworkInterfaceFloatingIPOptions) - if err != nil { - return vpcv1.FloatingIP{}, err - } - return *floatingIP, nil -} - -func floatingIPUnBind(IPBindReqInfo IBMIPBindReqInfo, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { - if IPBindReqInfo.vmID == "" || IPBindReqInfo.floatingIPID == "" || IPBindReqInfo.NetworkInterfaceID == "" { - return false, errors.New("invalid IDs") - } - removeInstanceNetworkInterfaceFloatingIPOptions := &vpcv1.RemoveInstanceNetworkInterfaceFloatingIPOptions{} - removeInstanceNetworkInterfaceFloatingIPOptions.SetID(IPBindReqInfo.floatingIPID) - removeInstanceNetworkInterfaceFloatingIPOptions.SetInstanceID(IPBindReqInfo.vmID) - removeInstanceNetworkInterfaceFloatingIPOptions.SetNetworkInterfaceID(IPBindReqInfo.NetworkInterfaceID) - _, err := vpcService.RemoveInstanceNetworkInterfaceFloatingIPWithContext(ctx, removeInstanceNetworkInterfaceFloatingIPOptions) - if err != nil { - return false, err - } - deleteFloatingIPOptions := vpcService.NewDeleteFloatingIPOptions(IPBindReqInfo.floatingIPID) - _, err = vpcService.DeleteFloatingIPWithContext(ctx, deleteFloatingIPOptions) - if err != nil { - return false, err - } - return true, nil -} - -func getFloatIPsNextHref(next *vpcv1.FloatingIPCollectionNext) (string, error) { - if next != nil { - href := *next.Href - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - } - return "", errors.New("NOT NEXT") -} - -func getVMNextHref(next *vpcv1.InstanceCollectionNext) (string, error) { - if next != nil { - href := *next.Href - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - } - return "", errors.New("NOT NEXT") -} -func getVolumeNextHref(next *vpcv1.VolumeCollectionNext) (string, error) { - if next != nil { - href := *next.Href - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - } - return "", errors.New("NOT NEXT") -} -func checkVmIID(vmIID irs.IID) error { - if vmIID.SystemId == "" && vmIID.NameId == "" { - return errors.New("invalid IID") - } - return nil -} - -func checkVMReqInfo(vmReqInfo irs.VMReqInfo) error { - err := notSupportRootDiskCustom(vmReqInfo) - if err != nil { - return err - } - if vmReqInfo.IId.NameId == "" { - return errors.New("invalid VM IID") - } - if vmReqInfo.ImageIID.NameId == "" && vmReqInfo.ImageIID.SystemId == "" { - return errors.New("invalid VM ImageIID") - } - if vmReqInfo.VpcIID.NameId == "" && vmReqInfo.VpcIID.SystemId == "" { - return errors.New("invalid VM VpcIID") - } - if vmReqInfo.SubnetIID.NameId == "" && vmReqInfo.SubnetIID.SystemId == "" { - return errors.New("invalid VM SubnetIID") - } - if vmReqInfo.KeyPairIID.NameId == "" && vmReqInfo.KeyPairIID.SystemId == "" { - return errors.New("invalid VM KeyPairIID") - } - if vmReqInfo.VMSpecName == "" { - return errors.New("invalid VM VMSpecName") - } - return nil -} -func existInstance(vmIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { - options := &vpcv1.ListInstancesOptions{} - instances, _, err := vpcService.ListInstancesWithContext(ctx, options) - if err != nil { - return false, err - } - for { - for _, instance := range instances.Instances { - if *instance.Name == vmIID.NameId { - return true, nil - } - } - nextstr, _ := getVMNextHref(instances.Next) - if nextstr != "" { - listInstanceOptionsNext := &vpcv1.ListInstancesOptions{ - Start: core.StringPtr(nextstr), - } - instances, _, err = vpcService.ListInstancesWithContext(ctx, listInstanceOptionsNext) - if err != nil { - return false, err - } - } else { - break - } - } - return false, nil -} - -func getRawVolume(volumeIId irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Volume, error) { - if volumeIId.SystemId == "" { - options := &vpcv1.ListVolumesOptions{} - volumes, _, err := vpcService.ListVolumesWithContext(ctx, options) - if err != nil { - return vpcv1.Volume{}, err - } - for { - for _, volume := range volumes.Volumes { - if *volume.Name == volumeIId.NameId { - return volume, nil - } - } - nextstr, _ := getVolumeNextHref(volumes.Next) - if nextstr != "" { - listVolumeOptionsNext := &vpcv1.ListVolumesOptions{ - Start: core.StringPtr(nextstr), - } - volumes, _, err = vpcService.ListVolumesWithContext(ctx, listVolumeOptionsNext) - if err != nil { - return vpcv1.Volume{}, err - } - } else { - break - } - } - err = errors.New(fmt.Sprintf("not found Volume %s", volumeIId.NameId)) - return vpcv1.Volume{}, err - } else { - options := &vpcv1.GetVolumeOptions{} - options.SetID(volumeIId.SystemId) - volume, _, err := vpcService.GetVolumeWithContext(ctx, options) - if err != nil { - return vpcv1.Volume{}, err - } - return *volume, err - } -} - -func getRawInstance(vmIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Instance, error) { - if vmIID.SystemId == "" { - options := &vpcv1.ListInstancesOptions{} - instances, _, err := vpcService.ListInstancesWithContext(ctx, options) - if err != nil { - return vpcv1.Instance{}, err - } - for { - for _, instance := range instances.Instances { - if *instance.Name == vmIID.NameId { - return instance, nil - } - } - nextstr, _ := getVMNextHref(instances.Next) - if nextstr != "" { - listInstanceOptionsNext := &vpcv1.ListInstancesOptions{ - Start: core.StringPtr(nextstr), - } - instances, _, err = vpcService.ListInstancesWithContext(ctx, listInstanceOptionsNext) - if err != nil { - // LoggingError(hiscallInfo, err) - return vpcv1.Instance{}, err - //break - } - } else { - break - } - } - err = errors.New(fmt.Sprintf("not found VM %s", vmIID.NameId)) - return vpcv1.Instance{}, err - } else { - instanceOptions := &vpcv1.GetInstanceOptions{} - instanceOptions.SetID(vmIID.SystemId) - instance, _, err := vpcService.GetInstanceWithContext(ctx, instanceOptions) - if err != nil { - return vpcv1.Instance{}, err - } - return *instance, nil - } -} -func getSuspendVMCheck(status string) error { - switch status { - case "running": - return nil - case "pausing", "pending", "stopping", "resuming", "restarting", "failed", "stopped", "paused", "starting": - status, _ := convertInstanceStatus(status) - return errors.New(fmt.Sprintf("can't ReBoot VM when your VM Status is %s", status)) - case "deleting": - return errors.New("can't ReBoot VM when your VM Status is Terminating") - //case "starting": - // return errors.New("can't ReBoot VM when your VM Status is Creating ") - case "": - return errors.New("can't ReBoot VM when your VM Status is NotExist") - default: - return errors.New("UnKnown STATUS") - } -} - -func getResumeVMCheck(status string) error { - switch status { - case "stopped", "paused": - return nil - case "pausing", "pending", "stopping", "running", "resuming", "restarting", "failed", "starting": - status, _ := convertInstanceStatus(status) - return errors.New(fmt.Sprintf("can't ReBoot VM when your VM Status is %s", status)) - case "deleting": - return errors.New("can't ReBoot VM when your VM Status is Terminating") - //case "starting": - // return errors.New("can't ReBoot VM when your VM Status is Creating ") - case "": - return errors.New("can't ReBoot VM when your VM Status is NotExist") - default: - return errors.New("UnKnown STATUS") - } -} -func getRebootCheck(status string) error { - switch status { - case "pausing", "pending", "stopping", "running", "resuming", "restarting", "failed", "stopped", "paused", "starting": - return nil - case "deleting": - return errors.New("can't ReBoot VM when your VM Status is Terminating") - //case "starting": - // return errors.New("can't ReBoot VM when your VM Status is Creating") - case "": - return errors.New("can't ReBoot VM when your VM Status is NotExist") - default: - return errors.New("UnKnown STATUS") - } -} - -func convertInstanceStatus(status string) (irs.VMStatus, error) { - switch status { - case "pausing", "pending", "stopping": - return irs.Suspending, nil - case "stopped", "paused": - return irs.Suspended, nil - case "failed": - return irs.Failed, nil - case "restarting": - return irs.Rebooting, nil - case "resuming": - return irs.Resuming, nil - case "deleting": - return irs.Terminating, nil - case "running": - return irs.Running, nil - // TODO: starting and Creating 구분 못함. - case "starting": - return irs.Resuming, nil - case "": - return irs.NotExist, nil - default: - return "", errors.New("UnKnown STATUS") - } -} - -func deleteInstance(instanceId string, vpcService *vpcv1.VpcV1, ctx context.Context) error { - deleteInstanceOptions := &vpcv1.DeleteInstanceOptions{} - deleteInstanceOptions.SetID(instanceId) - _, err := vpcService.DeleteInstanceWithContext(ctx, deleteInstanceOptions) - return err -} - -func removeFloatingIps(instance vpcv1.Instance, vpcService *vpcv1.VpcV1, ctx context.Context) error { - instanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} - instanceNetworkInterfaceOptions.SetID(*instance.PrimaryNetworkInterface.ID) - instanceNetworkInterfaceOptions.SetInstanceID(*instance.ID) - networkInterface, _, err := vpcService.GetInstanceNetworkInterfaceWithContext(ctx, instanceNetworkInterfaceOptions) - if err != nil { - return err - } - if networkInterface.FloatingIps != nil { - for _, floatingIp := range networkInterface.FloatingIps { - ipBindInfo := IBMIPBindReqInfo{ - vmID: *instance.ID, - floatingIPID: *floatingIp.ID, - NetworkInterfaceID: *instance.PrimaryNetworkInterface.ID, - } - _, err := floatingIPUnBind(ipBindInfo, vpcService, ctx) - if err != nil { - return err - } - } - } - return nil -} - -func (vmHandler *IbmVMHandler) getKeyIId(instance vpcv1.Instance) irs.IID { - // KeyGet - var instanceId = "" - if instance.ID != nil { - instanceId = *instance.ID - } else { - return irs.IID{} - } - instanceInitializationOptions := &vpcv1.GetInstanceInitializationOptions{} - instanceInitializationOptions.SetID(instanceId) - initData, _, err := vmHandler.VpcService.GetInstanceInitializationWithContext(vmHandler.Ctx, instanceInitializationOptions) - if err == nil && initData.Keys != nil && len(initData.Keys) > 0 { - jsonInitDataBytes, err := json.Marshal(initData.Keys[0]) - if err == nil { - var keyRef vpcv1.KeyReferenceInstanceInitializationContextKeyReference - err = json.Unmarshal(jsonInitDataBytes, &keyRef) - if err == nil && keyRef.ID != nil && keyRef.Name != nil { - return irs.IID{ - NameId: *keyRef.Name, - SystemId: *keyRef.ID, - } - } - } - } - return irs.IID{} -} - -type vmNetworkInfo struct { - NetworkInterface string - PublicIP string - AccessPoint string - SecurityGroupIIds []irs.IID -} - -func (vmHandler *IbmVMHandler) getBootVolumeInfo(instance vpcv1.Instance) (rootDiskSize string) { - var bootVolumeId = "" - if instance.BootVolumeAttachment != nil && instance.BootVolumeAttachment.Volume.ID != nil { - bootVolumeId = *instance.BootVolumeAttachment.Volume.ID - } else { - return "" - } - volumeIId := irs.IID{SystemId: bootVolumeId} - rawVolume, err := getRawVolume(volumeIId, vmHandler.VpcService, vmHandler.Ctx) - - if err == nil { - return strconv.Itoa(int(*rawVolume.Capacity)) - } - return "" -} - -// networkDone <- vmHandler.getNetworkInfo(*instance.ID, *instance.PrimaryNetworkInterface.ID, *instance.VPC.ID) -func (vmHandler *IbmVMHandler) getNetworkInfo(instance vpcv1.Instance) vmNetworkInfo { - // Network Get - var instanceId = "" - var instancePrimaryNIId = "" - var vpcId = "" - if instance.ID != nil { - instanceId = *instance.ID - } - if instance.PrimaryNetworkInterface != nil && instance.PrimaryNetworkInterface.ID != nil { - instancePrimaryNIId = *instance.PrimaryNetworkInterface.ID - } - if instance.VPC != nil && instance.VPC.ID != nil { - vpcId = *instance.VPC.ID - } - if instanceId == "" || instancePrimaryNIId == "" { - return vmNetworkInfo{} - } - info := vmNetworkInfo{} - instanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} - instanceNetworkInterfaceOptions.SetID(instancePrimaryNIId) - instanceNetworkInterfaceOptions.SetInstanceID(instanceId) - networkInterface, _, err := vmHandler.VpcService.GetInstanceNetworkInterfaceWithContext(vmHandler.Ctx, instanceNetworkInterfaceOptions) - if err == nil { - // SET IP - info.NetworkInterface = *networkInterface.Name - if networkInterface.FloatingIps != nil && len(networkInterface.FloatingIps) > 0 { - info.PublicIP = *networkInterface.FloatingIps[0].Address - info.AccessPoint = info.PublicIP - } - if vpcId == "" { - info.SecurityGroupIIds = []irs.IID{} - return info - } - // SET SG - getVpcOptions := &vpcv1.GetVPCOptions{} - getVpcOptions.SetID(vpcId) - vpc, _, _ := vmHandler.VpcService.GetVPCWithContext(vmHandler.Ctx, getVpcOptions) - var sgIIds []irs.IID - if vpc != nil && vpc.DefaultSecurityGroup != nil { - defaultSGId := *vpc.DefaultSecurityGroup.ID - vmSecurityGroups := networkInterface.SecurityGroups - for _, seg := range vmSecurityGroups { - if defaultSGId != *seg.ID { - sgIIds = append(sgIIds, irs.IID{NameId: *seg.Name, SystemId: *seg.ID}) - } - } - } - info.SecurityGroupIIds = sgIIds - } - return info -} - -func (vmHandler *IbmVMHandler) setVmInfo(instance vpcv1.Instance) (irs.VMInfo, error) { - var dataDiskIIDs []irs.IID - for _, rawDataDisk := range instance.VolumeAttachments { - if *rawDataDisk.Volume.ID != *instance.BootVolumeAttachment.Volume.ID { - dataDiskIIDs = append(dataDiskIIDs, irs.IID{ - NameId: *rawDataDisk.Volume.Name, - SystemId: *rawDataDisk.Volume.ID, - }) - } - } - vmInfo := irs.VMInfo{ - IId: irs.IID{ - NameId: *instance.Name, - SystemId: *instance.ID, - }, - StartTime: time.Time(*instance.CreatedAt).Local(), - Region: irs.RegionInfo{ - Region: vmHandler.Region.Region, - Zone: *instance.Zone.Name, - }, - VMSpecName: *instance.Profile.Name, - VpcIID: irs.IID{ - NameId: *instance.VPC.Name, - SystemId: *instance.VPC.ID, - }, - SubnetIID: irs.IID{ - NameId: *instance.PrimaryNetworkInterface.Subnet.Name, - SystemId: *instance.PrimaryNetworkInterface.Subnet.ID, - }, - PrivateIP: *instance.PrimaryNetworkInterface.PrimaryIpv4Address, - VMUserId: CBDefaultVmUserName, - RootDeviceName: "Not visible in IBMCloud-VPC", - VMBlockDisk: "Not visible in IBMCloud-VPC", - DataDiskIIDs: dataDiskIIDs, - } - chanCount := 0 - // KeyGet - keyDone := make(chan irs.IID) - chanCount++ - go func() { - keyDone <- vmHandler.getKeyIId(instance) - }() - - networkDone := make(chan vmNetworkInfo) - chanCount++ - go func() { - networkDone <- vmHandler.getNetworkInfo(instance) - }() - - volumeDone := make(chan string) - chanCount++ - go func() { - volumeDone <- vmHandler.getBootVolumeInfo(instance) - }() - - for i := 0; i < chanCount; i++ { - select { - case keyIID := <-keyDone: - vmInfo.KeyPairIId = keyIID - case netInfo := <-networkDone: - vmInfo.NetworkInterface = netInfo.NetworkInterface - vmInfo.PublicIP = netInfo.PublicIP - vmInfo.AccessPoint = netInfo.AccessPoint - vmInfo.SecurityGroupIIds = netInfo.SecurityGroupIIds - case volumeRootDiskSize := <-volumeDone: - vmInfo.RootDiskSize = volumeRootDiskSize - } - } - - vmInfo.RootDiskType = "general-purpose" - - vmInfo.VMBootDisk = *instance.BootVolumeAttachment.Volume.ID - rawBootDisk, getRawBootDiskErr := getRawDisk(vmHandler.VpcService, vmHandler.Ctx, irs.IID{SystemId: vmInfo.VMBootDisk}) - if getRawBootDiskErr == nil { - isWindows := strings.Contains(strings.ToLower(*rawBootDisk.OperatingSystem.Name), "windows") - if isWindows { - vmInfo.Platform = irs.WINDOWS - vmInfo.VMUserId = "Administrator" - vmInfo.AccessPoint = vmInfo.AccessPoint + ":3389" - } else { - vmInfo.Platform = irs.LINUX_UNIX - vmInfo.VMUserId = "cb-user" - vmInfo.AccessPoint = vmInfo.AccessPoint + ":22" - } - } - - return vmInfo, nil -} - -func (vmHandler *IbmVMHandler) checkFloatingIPName(floatingIPName string) (exist bool, err error) { - options := &vpcv1.ListFloatingIpsOptions{} - floatingIPs, _, err := vmHandler.VpcService.ListFloatingIpsWithContext(vmHandler.Ctx, options) - if err != nil { - return false, err - } - for { - for _, floatingIP := range floatingIPs.FloatingIps { - if *floatingIP.Name == floatingIPName { - return true, nil - } - } - nextstr, _ := getFloatIPsNextHref(floatingIPs.Next) - if nextstr != "" { - listFloatingNext := &vpcv1.ListFloatingIpsOptions{ - Start: core.StringPtr(nextstr), - } - floatingIPs, _, err = vmHandler.VpcService.ListFloatingIpsWithContext(vmHandler.Ctx, listFloatingNext) - if err != nil { - return false, err - } - } else { - break - } - } - return false, nil -} - -func notSupportRootDiskCustom(vmReqInfo irs.VMReqInfo) error { - if vmReqInfo.RootDiskType != "" && strings.ToLower(vmReqInfo.RootDiskType) != "default" { - return errors.New("IBM-VPC_CANNOT_CHANGE_ROOTDISKTYPE") - } - if vmReqInfo.RootDiskSize != "" && strings.ToLower(vmReqInfo.RootDiskSize) != "default" { - return errors.New("IBM-VPC_CANNOT_CHANGE_ROOTDISKSIZE") - } - return nil -} - -type vmInfoWithError struct { - VMInfo irs.VMInfo - err error -} - -func (vmHandler *IbmVMHandler) setVmInfoWithContext(ctx context.Context, instance vpcv1.Instance) (irs.VMInfo, error) { - done := make(chan vmInfoWithError) - - go func() { - vmInfo, err := vmHandler.setVmInfo(instance) - done <- vmInfoWithError{ - VMInfo: vmInfo, - err: err, - } - }() - select { - case vmInfoWithErrorDone := <-done: - return vmInfoWithErrorDone.VMInfo, vmInfoWithErrorDone.err - case <-ctx.Done(): - return irs.VMInfo{}, nil - } -} - -func (vmHandler *IbmVMHandler) setVMList(instanceList []vpcv1.Instance) ([]*irs.VMInfo, error) { - vmListCount := len(instanceList) - vmList := make([]*irs.VMInfo, len(instanceList)) - - if vmListCount == 0 { - return vmList, nil - } - var wg sync.WaitGroup - - ctx, cancel := context.WithCancel(context.Background()) - - defer cancel() - - var globalErr error - - for i, vmInstance := range instanceList { - wg.Add(1) - index := i - dumpInstance := vmInstance - go func() { - defer wg.Done() - vmInfo, err := vmHandler.setVmInfoWithContext(ctx, dumpInstance) - if err != nil { - cancel() - if globalErr == nil { - globalErr = err - } - } - vmList[index] = &vmInfo - }() - } - wg.Wait() - - if globalErr != nil { - return nil, globalErr - } - - return vmList, nil -} +package resources + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + vpcv0230 "github.com/IBM/vpc-go-sdk/0.23.0/vpcv1" + "github.com/IBM/vpc-go-sdk/vpcv1" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" + cdcom "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/common" + idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" + irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" + "io/ioutil" + "math/rand" + "net/url" + "os" + "sort" + "strconv" + "strings" + "sync" + "time" +) + +type IbmVMHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + VpcService *vpcv1.VpcV1 + VpcService0230 *vpcv0230.VpcV1 + Ctx context.Context +} + +func (vmHandler *IbmVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmReqInfo.IId.NameId, "StartVM()") + start := call.Start() + + // 1.Check VMReqInfo + err := checkVMReqInfo(vmReqInfo) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + + // 1-1 Exist Check + exist, err := existInstance(vmReqInfo.IId, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } else if exist { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = The VM name %s already exists", vmReqInfo.IId.NameId)) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + // 1-2. Setup Req Resource IID + var image vpcv1.Image + var myImage irs.MyImageInfo + var isWindows bool + if vmReqInfo.ImageType == irs.MyImage { + myImageHandler := IbmMyImageHandler{ + CredentialInfo: vmHandler.CredentialInfo, + Region: vmHandler.Region, + VpcService: vmHandler.VpcService, + Ctx: vmHandler.Ctx, + } + var getMyImageErr error + myImage, getMyImageErr = myImageHandler.GetMyImage(vmReqInfo.ImageIID) + if getMyImageErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", getMyImageErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + if myImage.Status != irs.MyImageAvailable { + createErr := errors.New("Failed to Create VM. err = Source Image status is not Available") + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + rawSnapshot, _, getRawSnapshotErr := myImageHandler.VpcService.GetSnapshotWithContext(myImageHandler.Ctx, &vpcv1.GetSnapshotOptions{ID: &myImage.IId.SystemId}) + if getRawSnapshotErr != nil { + createErr := errors.New("Failed to Create VM. err = Cannot get Snapshot Detail of Source MyImage") + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + + isWindows = strings.Contains(strings.ToLower(*rawSnapshot.OperatingSystem.Name), "windows") + } else { + var getImageErr error + image, getImageErr = getRawImage(vmReqInfo.ImageIID, vmHandler.VpcService, vmHandler.Ctx) + if getImageErr != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", getImageErr.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + + isWindows = strings.Contains(strings.ToLower(*image.OperatingSystem.Name), "windows") + } + + vpc, err := GetRawVPC(vmReqInfo.VpcIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + vpcSubnet, err := getVPCRawSubnet(vpc, vmReqInfo.SubnetIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + key, err := getRawKey(vmReqInfo.KeyPairIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + spec, err := getRawSpec(vmReqInfo.VMSpecName, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + var securityGroups []vpcv1.SecurityGroup + if vmReqInfo.SecurityGroupIIDs != nil { + for _, SecurityGroupIID := range vmReqInfo.SecurityGroupIIDs { + err := checkSecurityGroupIID(SecurityGroupIID) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + securityGroup, err := getRawSecurityGroup(SecurityGroupIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + securityGroups = append(securityGroups, securityGroup) + } + } + + // 1-3. cloud-init data set + var userData string + if isWindows { + userId := vmReqInfo.VMUserId + if userId == "" { + userId = "Administrator" + } + + pwValidErr := cdcom.ValidateWindowsPassword(vmReqInfo.VMUserPasswd) + if pwValidErr != nil { + return irs.VMInfo{}, pwValidErr + } + + userData = fmt.Sprintf("#ps1_sysnative\nnet user \"%s\" \"%s\"", userId, vmReqInfo.VMUserPasswd) + } else { + rootPath := os.Getenv("CBSPIDER_ROOT") + fileDataCloudInit, err := ioutil.ReadFile(rootPath + CBCloudInitFilePath) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + userData = string(fileDataCloudInit) + userData = strings.ReplaceAll(userData, "{{username}}", CBDefaultVmUserName) + } + + // 2.Create VM + // TODO : UserData cloudInit + createInstanceOptions := &vpcv0230.CreateInstanceOptions{} + + var existingDataVolumeAttachments []vpcv0230.VolumeAttachmentPrototypeInstanceContext + for _, dataVolumeIID := range vmReqInfo.DataDiskIIDs { + rawDisk, getRawDiskErr := getRawDisk(vmHandler.VpcService, vmHandler.Ctx, dataVolumeIID) + if getRawDiskErr == nil { + existingDataVolumeAttachments = append(existingDataVolumeAttachments, vpcv0230.VolumeAttachmentPrototypeInstanceContext{ + Volume: &vpcv0230.VolumeAttachmentVolumePrototypeInstanceContextVolumeIdentity{ID: rawDisk.ID}, + }) + } + } + + if vmReqInfo.ImageType == irs.MyImage { + snapshotList, _, listSnapshotErr := vmHandler.VpcService.ListSnapshotsWithContext(vmHandler.Ctx, &vpcv1.ListSnapshotsOptions{}) + if listSnapshotErr != nil { + return irs.VMInfo{}, errors.New(fmt.Sprintf("Failed to Get MyImage. err = %s", listSnapshotErr.Error())) + } + + var associatedSnapshots []vpcv1.Snapshot + for _, snapshot := range snapshotList.Snapshots { + if strings.Split(*snapshot.Name, DEV)[0] == myImage.IId.NameId { + associatedSnapshots = append(associatedSnapshots, snapshot) + } + } + + sort.Slice(associatedSnapshots, func(i, j int) bool { + return *associatedSnapshots[i].Name < *associatedSnapshots[j].Name + }) + + var dataVolumeAttachments []vpcv0230.VolumeAttachmentPrototypeInstanceContext + var bootVolumeAttachment vpcv0230.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext + for _, snapshot := range associatedSnapshots { + sourceVolume, _, getSourceVolumeErr := vmHandler.VpcService0230.GetVolumeWithContext(vmHandler.Ctx, &vpcv0230.GetVolumeOptions{ID: snapshot.SourceVolume.ID}) + if getSourceVolumeErr != nil { + return irs.VMInfo{}, errors.New(fmt.Sprintf("Failed to Get Source Volume. err = %s", getSourceVolumeErr.Error())) + } + + volumeName := fmt.Sprintf("%s%s%s", vmReqInfo.IId.NameId, DEV, strings.Split(*snapshot.Name, DEV)[1]) + if *snapshot.Bootable { + bootVolumeAttachment = vpcv0230.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext{ + Volume: &vpcv0230.VolumePrototypeInstanceBySourceSnapshotContext{ + Name: core.StringPtr(volumeName), + Profile: &vpcv0230.VolumeProfileIdentityByName{Name: sourceVolume.Profile.Name}, + Capacity: sourceVolume.Capacity, + SourceSnapshot: &vpcv0230.SnapshotIdentityByID{ID: snapshot.ID}, + }, + } + } else { + model := vpcv0230.VolumeAttachmentPrototypeInstanceContext{ + Volume: &vpcv0230.VolumeAttachmentVolumePrototypeInstanceContextVolumePrototypeInstanceContextVolumePrototypeInstanceContextVolumeBySourceSnapshot{ + Name: core.StringPtr(volumeName), + Profile: &vpcv0230.VolumeProfileIdentityByName{Name: sourceVolume.Profile.Name}, + Capacity: sourceVolume.Capacity, + SourceSnapshot: &vpcv0230.SnapshotIdentityByID{ID: snapshot.ID}, + }, + } + + dataVolumeAttachments = append(dataVolumeAttachments, model) + } + } + + dataVolumeAttachments = append(dataVolumeAttachments, existingDataVolumeAttachments...) + + createInstanceOptions.SetInstancePrototype(&vpcv0230.InstancePrototypeInstanceBySourceSnapshot{ + Name: &vmReqInfo.IId.NameId, + BootVolumeAttachment: &bootVolumeAttachment, + VolumeAttachments: dataVolumeAttachments, + Profile: &vpcv0230.InstanceProfileIdentity{ + Name: spec.Name, + }, + Zone: &vpcv0230.ZoneIdentity{ + Name: &vmHandler.Region.Zone, + }, + PrimaryNetworkInterface: &vpcv0230.NetworkInterfacePrototype{ + Subnet: &vpcv0230.SubnetIdentity{ + ID: vpcSubnet.ID, + }, + }, + Keys: []vpcv0230.KeyIdentityIntf{ + &vpcv0230.KeyIdentity{ + ID: key.ID, + }, + }, + VPC: &vpcv0230.VPCIdentity{ + ID: vpc.ID, + }, + UserData: &userData, + }) + } else { + createInstanceOptions.SetInstancePrototype(&vpcv0230.InstancePrototype{ + Name: &vmReqInfo.IId.NameId, + Image: &vpcv0230.ImageIdentity{ + ID: image.ID, + }, + Profile: &vpcv0230.InstanceProfileIdentity{ + Name: spec.Name, + }, + Zone: &vpcv0230.ZoneIdentity{ + Name: &vmHandler.Region.Zone, + }, + PrimaryNetworkInterface: &vpcv0230.NetworkInterfacePrototype{ + Subnet: &vpcv0230.SubnetIdentity{ + ID: vpcSubnet.ID, + }, + }, + Keys: []vpcv0230.KeyIdentityIntf{ + &vpcv0230.KeyIdentity{ + ID: key.ID, + }, + }, + VPC: &vpcv0230.VPCIdentity{ + ID: vpc.ID, + }, + UserData: &userData, + VolumeAttachments: existingDataVolumeAttachments, + }) + } + + createInstance, _, err := vmHandler.VpcService0230.CreateInstanceWithContext(vmHandler.Ctx, createInstanceOptions) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + + // 2-1. Attach Tag + if vmReqInfo.TagList != nil && len(vmReqInfo.TagList) > 0 { + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range vmReqInfo.TagList{ + _, err := tagHandler.AddTag("VM", vmReqInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on VM err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + // 3.Attach SecurityGroup + if securityGroups != nil && len(securityGroups) > 0 { + for _, securityGroup := range securityGroups { + options := &vpcv1.AddSecurityGroupNetworkInterfaceOptions{} + options.SetSecurityGroupID(*securityGroup.ID) + options.SetID(*createInstance.PrimaryNetworkInterface.ID) + _, _, err = vmHandler.VpcService.AddSecurityGroupNetworkInterfaceWithContext(vmHandler.Ctx, options) + if err != nil { + //TODO DELETE + deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + if deleteErr != nil { + newErrText := err.Error() + deleteErr.Error() + err = errors.New(newErrText) + } + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + } + } + } + + // 4.Attach FloatingIP + + // 4-1. Create FloatingIP + rand.Seed(time.Now().UnixNano()) + floatingIPName := *createInstance.Zone.Name + "-floatingip-" + strconv.FormatInt(rand.Int63n(10000000), 10) + floatingIPExist, err := vmHandler.checkFloatingIPName(floatingIPName) + if err != nil || floatingIPExist { + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = Faild Generator FloatingIP Name")) + deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) + if deleteErr != nil { + createErr = errors.New(fmt.Sprintf("%s, %s ", createErr.Error(), deleteErr.Error())) + } + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + createFloatingIPOptions := &vpcv1.CreateFloatingIPOptions{} + createFloatingIPOptions.SetFloatingIPPrototype(&vpcv1.FloatingIPPrototype{ + Name: &floatingIPName, + Zone: &vpcv1.ZoneIdentity{ + Name: createInstance.Zone.Name, + }, + }) + + floatingIP, _, err := vmHandler.VpcService.CreateFloatingIPWithContext(vmHandler.Ctx, createFloatingIPOptions) + + if err != nil { + deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + if deleteErr != nil { + newErrText := err.Error() + deleteErr.Error() + err = errors.New(newErrText) + } + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + + // 4-2. Bind FloatingIP + ipBindInfo := IBMIPBindReqInfo{ + vmID: *createInstance.ID, + floatingIPID: *floatingIP.ID, + NetworkInterfaceID: *createInstance.PrimaryNetworkInterface.ID, + } + + _, err = floatingIPBind(ipBindInfo, vmHandler.VpcService, vmHandler.Ctx) + + if err != nil { + deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + if deleteErr != nil { + newErrText := err.Error() + deleteErr.Error() + err = errors.New(newErrText) + } + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + } + createInstanceIId := irs.IID{ + NameId: *createInstance.Name, + SystemId: *createInstance.ID, + } + // TODO : runnigCheck + curRetryCnt := 0 + maxRetryCnt := 120 + for { + finalInstance, err := getRawInstance(createInstanceIId, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + removeFloatingIpsErr := removeFloatingIps(finalInstance, vmHandler.VpcService, vmHandler.Ctx) + // 생성 완료후 running 기다리는중 에러. + // 제거 로직을 위해 removeFloatingIp + if removeFloatingIpsErr != nil { + // 제거 로직을 위해 removeFloatingIp Error => instance에 대한 에러 + removeError + delete error + newErrText := err.Error() + removeFloatingIpsErr.Error() + "and failed delete VM" + err = errors.New(newErrText) + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + // 제거 로직을 위해 deleteInstance + deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) + if deleteErr != nil { + newErrText := err.Error() + deleteErr.Error() + err = errors.New(newErrText) + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + err = errors.New("failed to create VM") + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + if *finalInstance.Status == "running" { + finalInstanceInfo, err := vmHandler.setVmInfo(finalInstance) + if err != nil { + removeFloatingIpsErr := removeFloatingIps(finalInstance, vmHandler.VpcService, vmHandler.Ctx) + // 생성 완료후 running 기다리는중 에러. + // 제거 로직을 위해 removeFloatingIp + if removeFloatingIpsErr != nil { + // 제거 로직을 위해 removeFloatingIp Error => instance에 대한 에러 + removeError + delete error + newErrText := err.Error() + removeFloatingIpsErr.Error() + "and failed delete VM" + err = errors.New(newErrText) + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + // 제거 로직을 위해 deleteInstance + deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) + if deleteErr != nil { + newErrText := err.Error() + deleteErr.Error() + err = errors.New(newErrText) + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + err = errors.New("failed to create VM") + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + LoggingInfo(hiscallInfo, start) + if isWindows { + finalInstanceInfo.VMUserPasswd = vmReqInfo.VMUserPasswd + } + return finalInstanceInfo, nil + } + curRetryCnt++ + time.Sleep(1 * time.Second) + if curRetryCnt > maxRetryCnt { + err = errors.New(fmt.Sprintf("failed to create VM, exceeded maximum retry count %d", maxRetryCnt)) + removeFloatingIpsErr := removeFloatingIps(finalInstance, vmHandler.VpcService, vmHandler.Ctx) + // 생성 완료후 running 기다리는중 에러. + // 제거 로직을 위해 removeFloatingIp + if removeFloatingIpsErr != nil { + // 제거 로직을 위해 removeFloatingIp Error => instance에 대한 에러 + removeError + delete error + newErrText := err.Error() + removeFloatingIpsErr.Error() + "and failed delete VM" + err = errors.New(newErrText) + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + // 제거 로직을 위해 deleteInstance + deleteErr := deleteInstance(*createInstance.ID, vmHandler.VpcService, vmHandler.Ctx) + if deleteErr != nil { + newErrText := err.Error() + deleteErr.Error() + err = errors.New(newErrText) + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + err = errors.New("failed to create VM") + createErr := errors.New(fmt.Sprintf("Failed to Create VM. err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VMInfo{}, createErr + } + } +} +func (vmHandler *IbmVMHandler) SuspendVM(vmIID irs.IID) (irs.VMStatus, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "SuspendVM()") + start := call.Start() + err := checkVmIID(vmIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + err = getSuspendVMCheck(*instance.Status) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + instanceActionOptions := &vpcv1.CreateInstanceActionOptions{} + instanceActionOptions.SetInstanceID(*instance.ID) + instanceActionOptions.SetType("stop") + _, _, err = vmHandler.VpcService.CreateInstanceActionWithContext(vmHandler.Ctx, instanceActionOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to SuspendVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + LoggingInfo(hiscallInfo, start) + return irs.Suspending, nil +} +func (vmHandler *IbmVMHandler) ResumeVM(vmIID irs.IID) (irs.VMStatus, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "ResumeVM()") + start := call.Start() + err := checkVmIID(vmIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + err = getResumeVMCheck(*instance.Status) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + instanceActionOptions := &vpcv1.CreateInstanceActionOptions{} + instanceActionOptions.SetInstanceID(*instance.ID) + instanceActionOptions.SetType("start") + instanceActionOptions.SetForce(true) + _, _, err = vmHandler.VpcService.CreateInstanceActionWithContext(vmHandler.Ctx, instanceActionOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to ResumeVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + LoggingInfo(hiscallInfo, start) + return irs.Resuming, nil +} +func (vmHandler *IbmVMHandler) RebootVM(vmIID irs.IID) (irs.VMStatus, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "RebootVM()") + start := call.Start() + err := checkVmIID(vmIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + err = getRebootCheck(*instance.Status) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + instanceActionOptions := &vpcv1.CreateInstanceActionOptions{} + instanceActionOptions.SetInstanceID(*instance.ID) + instanceActionOptions.SetType("reboot") + instanceActionOptions.SetForce(true) + _, _, err = vmHandler.VpcService.CreateInstanceActionWithContext(vmHandler.Ctx, instanceActionOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to RebootVM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.Failed, getErr + } + LoggingInfo(hiscallInfo, start) + return irs.Rebooting, nil +} +func (vmHandler *IbmVMHandler) TerminateVM(vmIID irs.IID) (irs.VMStatus, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "TerminateVM()") + start := call.Start() + err := checkVmIID(vmIID) + if err != nil { + TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) + cblogger.Error(TerminateErr.Error()) + LoggingError(hiscallInfo, TerminateErr) + return irs.Failed, TerminateErr + } + instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) + cblogger.Error(TerminateErr.Error()) + LoggingError(hiscallInfo, TerminateErr) + return irs.Failed, TerminateErr + } + err = removeFloatingIps(instance, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) + cblogger.Error(TerminateErr.Error()) + LoggingError(hiscallInfo, TerminateErr) + return irs.Failed, TerminateErr + } + err = deleteInstance(*instance.ID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + TerminateErr := errors.New(fmt.Sprintf("Failed to Terminate VM err = %s", err.Error())) + cblogger.Error(TerminateErr.Error()) + LoggingError(hiscallInfo, TerminateErr) + return irs.Failed, TerminateErr + } + LoggingInfo(hiscallInfo, start) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete VM Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + return irs.Terminating, nil +} + +func (vmHandler *IbmVMHandler) ListVMStatus() ([]*irs.VMStatusInfo, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, "VMStatus", "ListVMStatus()") + start := call.Start() + options := &vpcv1.ListInstancesOptions{} + instances, _, err := vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, options) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VMStatus. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + var vmStatusList []*irs.VMStatusInfo + for { + for _, instance := range instances.Instances { + vmStatusString, _ := convertInstanceStatus(*instance.Status) + VMStatusInfo := irs.VMStatusInfo{ + IId: irs.IID{ + NameId: *instance.Name, + SystemId: *instance.ID, + }, + VmStatus: vmStatusString, + } + + vmStatusList = append(vmStatusList, &VMStatusInfo) + } + nextstr, _ := getVMNextHref(instances.Next) + if nextstr != "" { + listVpcsOptions2 := &vpcv1.ListInstancesOptions{ + Start: core.StringPtr(nextstr), + } + instances, _, err = vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, listVpcsOptions2) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VMStatus. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + } else { + break + } + } + LoggingInfo(hiscallInfo, start) + return vmStatusList, nil +} +func (vmHandler *IbmVMHandler) GetVMStatus(vmIID irs.IID) (irs.VMStatus, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "GetVMStatus()") + start := call.Start() + err := checkVmIID(vmIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VMStatus. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return "", getErr + } + instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VMStatus. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return "", getErr + } + LoggingInfo(hiscallInfo, start) + return convertInstanceStatus(*instance.Status) +} + +func (vmHandler *IbmVMHandler) ListVM() ([]*irs.VMInfo, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, "VM", "ListVM()") + start := call.Start() + options := &vpcv1.ListInstancesOptions{} + instances, _, err := vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, options) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + + var vmInstanceList []vpcv1.Instance + + for { + vmInstanceList = append(vmInstanceList, instances.Instances...) + nextstr, _ := getVMNextHref(instances.Next) + if nextstr != "" { + listVpcsOptions2 := &vpcv1.ListInstancesOptions{ + Start: core.StringPtr(nextstr), + } + instances, _, err = vmHandler.VpcService.ListInstancesWithContext(vmHandler.Ctx, listVpcsOptions2) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + //break + } + } else { + break + } + } + + vmList, err := vmHandler.setVMList(vmInstanceList) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + LoggingInfo(hiscallInfo, start) + return vmList, nil +} + +func (vmHandler *IbmVMHandler) GetVM(vmIID irs.IID) (irs.VMInfo, error) { + hiscallInfo := GetCallLogScheme(vmHandler.Region, call.VM, vmIID.NameId, "GetVM()") + start := call.Start() + err := checkVmIID(vmIID) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.VMInfo{}, getErr + } + instance, err := getRawInstance(vmIID, vmHandler.VpcService, vmHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.VMInfo{}, getErr + } + + vmInfo, err := vmHandler.setVmInfo(instance) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VM. err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.VMInfo{}, getErr + } + LoggingInfo(hiscallInfo, start) + return vmInfo, nil +} + +type IBMIPBindReqInfo struct { + vmID string + floatingIPID string + NetworkInterfaceID string +} + +func floatingIPBind(IPBindReqInfo IBMIPBindReqInfo, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.FloatingIP, error) { + if IPBindReqInfo.vmID == "" || IPBindReqInfo.floatingIPID == "" || IPBindReqInfo.NetworkInterfaceID == "" { + return vpcv1.FloatingIP{}, errors.New("invalid IDs") + } + addInstanceNetworkInterfaceFloatingIPOptions := &vpcv1.AddInstanceNetworkInterfaceFloatingIPOptions{} + addInstanceNetworkInterfaceFloatingIPOptions.SetID(IPBindReqInfo.floatingIPID) + addInstanceNetworkInterfaceFloatingIPOptions.SetInstanceID(IPBindReqInfo.vmID) + addInstanceNetworkInterfaceFloatingIPOptions.SetNetworkInterfaceID(IPBindReqInfo.NetworkInterfaceID) + floatingIP, _, err := vpcService.AddInstanceNetworkInterfaceFloatingIPWithContext(ctx, addInstanceNetworkInterfaceFloatingIPOptions) + if err != nil { + return vpcv1.FloatingIP{}, err + } + return *floatingIP, nil +} + +func floatingIPUnBind(IPBindReqInfo IBMIPBindReqInfo, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { + if IPBindReqInfo.vmID == "" || IPBindReqInfo.floatingIPID == "" || IPBindReqInfo.NetworkInterfaceID == "" { + return false, errors.New("invalid IDs") + } + removeInstanceNetworkInterfaceFloatingIPOptions := &vpcv1.RemoveInstanceNetworkInterfaceFloatingIPOptions{} + removeInstanceNetworkInterfaceFloatingIPOptions.SetID(IPBindReqInfo.floatingIPID) + removeInstanceNetworkInterfaceFloatingIPOptions.SetInstanceID(IPBindReqInfo.vmID) + removeInstanceNetworkInterfaceFloatingIPOptions.SetNetworkInterfaceID(IPBindReqInfo.NetworkInterfaceID) + _, err := vpcService.RemoveInstanceNetworkInterfaceFloatingIPWithContext(ctx, removeInstanceNetworkInterfaceFloatingIPOptions) + if err != nil { + return false, err + } + deleteFloatingIPOptions := vpcService.NewDeleteFloatingIPOptions(IPBindReqInfo.floatingIPID) + _, err = vpcService.DeleteFloatingIPWithContext(ctx, deleteFloatingIPOptions) + if err != nil { + return false, err + } + return true, nil +} + +func getFloatIPsNextHref(next *vpcv1.FloatingIPCollectionNext) (string, error) { + if next != nil { + href := *next.Href + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + } + return "", errors.New("NOT NEXT") +} + +func getVMNextHref(next *vpcv1.InstanceCollectionNext) (string, error) { + if next != nil { + href := *next.Href + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + } + return "", errors.New("NOT NEXT") +} +func getVolumeNextHref(next *vpcv1.VolumeCollectionNext) (string, error) { + if next != nil { + href := *next.Href + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + } + return "", errors.New("NOT NEXT") +} +func checkVmIID(vmIID irs.IID) error { + if vmIID.SystemId == "" && vmIID.NameId == "" { + return errors.New("invalid IID") + } + return nil +} + +func checkVMReqInfo(vmReqInfo irs.VMReqInfo) error { + err := notSupportRootDiskCustom(vmReqInfo) + if err != nil { + return err + } + if vmReqInfo.IId.NameId == "" { + return errors.New("invalid VM IID") + } + if vmReqInfo.ImageIID.NameId == "" && vmReqInfo.ImageIID.SystemId == "" { + return errors.New("invalid VM ImageIID") + } + if vmReqInfo.VpcIID.NameId == "" && vmReqInfo.VpcIID.SystemId == "" { + return errors.New("invalid VM VpcIID") + } + if vmReqInfo.SubnetIID.NameId == "" && vmReqInfo.SubnetIID.SystemId == "" { + return errors.New("invalid VM SubnetIID") + } + if vmReqInfo.KeyPairIID.NameId == "" && vmReqInfo.KeyPairIID.SystemId == "" { + return errors.New("invalid VM KeyPairIID") + } + if vmReqInfo.VMSpecName == "" { + return errors.New("invalid VM VMSpecName") + } + return nil +} +func existInstance(vmIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { + options := &vpcv1.ListInstancesOptions{} + instances, _, err := vpcService.ListInstancesWithContext(ctx, options) + if err != nil { + return false, err + } + for { + for _, instance := range instances.Instances { + if *instance.Name == vmIID.NameId { + return true, nil + } + } + nextstr, _ := getVMNextHref(instances.Next) + if nextstr != "" { + listInstanceOptionsNext := &vpcv1.ListInstancesOptions{ + Start: core.StringPtr(nextstr), + } + instances, _, err = vpcService.ListInstancesWithContext(ctx, listInstanceOptionsNext) + if err != nil { + return false, err + } + } else { + break + } + } + return false, nil +} + +func getRawVolume(volumeIId irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Volume, error) { + if volumeIId.SystemId == "" { + options := &vpcv1.ListVolumesOptions{} + volumes, _, err := vpcService.ListVolumesWithContext(ctx, options) + if err != nil { + return vpcv1.Volume{}, err + } + for { + for _, volume := range volumes.Volumes { + if *volume.Name == volumeIId.NameId { + return volume, nil + } + } + nextstr, _ := getVolumeNextHref(volumes.Next) + if nextstr != "" { + listVolumeOptionsNext := &vpcv1.ListVolumesOptions{ + Start: core.StringPtr(nextstr), + } + volumes, _, err = vpcService.ListVolumesWithContext(ctx, listVolumeOptionsNext) + if err != nil { + return vpcv1.Volume{}, err + } + } else { + break + } + } + err = errors.New(fmt.Sprintf("not found Volume %s", volumeIId.NameId)) + return vpcv1.Volume{}, err + } else { + options := &vpcv1.GetVolumeOptions{} + options.SetID(volumeIId.SystemId) + volume, _, err := vpcService.GetVolumeWithContext(ctx, options) + if err != nil { + return vpcv1.Volume{}, err + } + return *volume, err + } +} + +func getRawInstance(vmIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Instance, error) { + if vmIID.SystemId == "" { + options := &vpcv1.ListInstancesOptions{} + instances, _, err := vpcService.ListInstancesWithContext(ctx, options) + if err != nil { + return vpcv1.Instance{}, err + } + for { + for _, instance := range instances.Instances { + if *instance.Name == vmIID.NameId { + return instance, nil + } + } + nextstr, _ := getVMNextHref(instances.Next) + if nextstr != "" { + listInstanceOptionsNext := &vpcv1.ListInstancesOptions{ + Start: core.StringPtr(nextstr), + } + instances, _, err = vpcService.ListInstancesWithContext(ctx, listInstanceOptionsNext) + if err != nil { + // LoggingError(hiscallInfo, err) + return vpcv1.Instance{}, err + //break + } + } else { + break + } + } + err = errors.New(fmt.Sprintf("not found VM %s", vmIID.NameId)) + return vpcv1.Instance{}, err + } else { + instanceOptions := &vpcv1.GetInstanceOptions{} + instanceOptions.SetID(vmIID.SystemId) + instance, _, err := vpcService.GetInstanceWithContext(ctx, instanceOptions) + if err != nil { + return vpcv1.Instance{}, err + } + return *instance, nil + } +} +func getSuspendVMCheck(status string) error { + switch status { + case "running": + return nil + case "pausing", "pending", "stopping", "resuming", "restarting", "failed", "stopped", "paused", "starting": + status, _ := convertInstanceStatus(status) + return errors.New(fmt.Sprintf("can't ReBoot VM when your VM Status is %s", status)) + case "deleting": + return errors.New("can't ReBoot VM when your VM Status is Terminating") + //case "starting": + // return errors.New("can't ReBoot VM when your VM Status is Creating ") + case "": + return errors.New("can't ReBoot VM when your VM Status is NotExist") + default: + return errors.New("UnKnown STATUS") + } +} + +func getResumeVMCheck(status string) error { + switch status { + case "stopped", "paused": + return nil + case "pausing", "pending", "stopping", "running", "resuming", "restarting", "failed", "starting": + status, _ := convertInstanceStatus(status) + return errors.New(fmt.Sprintf("can't ReBoot VM when your VM Status is %s", status)) + case "deleting": + return errors.New("can't ReBoot VM when your VM Status is Terminating") + //case "starting": + // return errors.New("can't ReBoot VM when your VM Status is Creating ") + case "": + return errors.New("can't ReBoot VM when your VM Status is NotExist") + default: + return errors.New("UnKnown STATUS") + } +} +func getRebootCheck(status string) error { + switch status { + case "pausing", "pending", "stopping", "running", "resuming", "restarting", "failed", "stopped", "paused", "starting": + return nil + case "deleting": + return errors.New("can't ReBoot VM when your VM Status is Terminating") + //case "starting": + // return errors.New("can't ReBoot VM when your VM Status is Creating") + case "": + return errors.New("can't ReBoot VM when your VM Status is NotExist") + default: + return errors.New("UnKnown STATUS") + } +} + +func convertInstanceStatus(status string) (irs.VMStatus, error) { + switch status { + case "pausing", "pending", "stopping": + return irs.Suspending, nil + case "stopped", "paused": + return irs.Suspended, nil + case "failed": + return irs.Failed, nil + case "restarting": + return irs.Rebooting, nil + case "resuming": + return irs.Resuming, nil + case "deleting": + return irs.Terminating, nil + case "running": + return irs.Running, nil + // TODO: starting and Creating 구분 못함. + case "starting": + return irs.Resuming, nil + case "": + return irs.NotExist, nil + default: + return "", errors.New("UnKnown STATUS") + } +} + +func deleteInstance(instanceId string, vpcService *vpcv1.VpcV1, ctx context.Context) error { + deleteInstanceOptions := &vpcv1.DeleteInstanceOptions{} + deleteInstanceOptions.SetID(instanceId) + _, err := vpcService.DeleteInstanceWithContext(ctx, deleteInstanceOptions) + return err +} + +func removeFloatingIps(instance vpcv1.Instance, vpcService *vpcv1.VpcV1, ctx context.Context) error { + instanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} + instanceNetworkInterfaceOptions.SetID(*instance.PrimaryNetworkInterface.ID) + instanceNetworkInterfaceOptions.SetInstanceID(*instance.ID) + networkInterface, _, err := vpcService.GetInstanceNetworkInterfaceWithContext(ctx, instanceNetworkInterfaceOptions) + if err != nil { + return err + } + if networkInterface.FloatingIps != nil { + for _, floatingIp := range networkInterface.FloatingIps { + ipBindInfo := IBMIPBindReqInfo{ + vmID: *instance.ID, + floatingIPID: *floatingIp.ID, + NetworkInterfaceID: *instance.PrimaryNetworkInterface.ID, + } + _, err := floatingIPUnBind(ipBindInfo, vpcService, ctx) + if err != nil { + return err + } + } + } + return nil +} + +func (vmHandler *IbmVMHandler) getKeyIId(instance vpcv1.Instance) irs.IID { + // KeyGet + var instanceId = "" + if instance.ID != nil { + instanceId = *instance.ID + } else { + return irs.IID{} + } + instanceInitializationOptions := &vpcv1.GetInstanceInitializationOptions{} + instanceInitializationOptions.SetID(instanceId) + initData, _, err := vmHandler.VpcService.GetInstanceInitializationWithContext(vmHandler.Ctx, instanceInitializationOptions) + if err == nil && initData.Keys != nil && len(initData.Keys) > 0 { + jsonInitDataBytes, err := json.Marshal(initData.Keys[0]) + if err == nil { + var keyRef vpcv1.KeyReferenceInstanceInitializationContextKeyReference + err = json.Unmarshal(jsonInitDataBytes, &keyRef) + if err == nil && keyRef.ID != nil && keyRef.Name != nil { + return irs.IID{ + NameId: *keyRef.Name, + SystemId: *keyRef.ID, + } + } + } + } + return irs.IID{} +} + +type vmNetworkInfo struct { + NetworkInterface string + PublicIP string + AccessPoint string + SecurityGroupIIds []irs.IID +} + +func (vmHandler *IbmVMHandler) getBootVolumeInfo(instance vpcv1.Instance) (rootDiskSize string) { + var bootVolumeId = "" + if instance.BootVolumeAttachment != nil && instance.BootVolumeAttachment.Volume.ID != nil { + bootVolumeId = *instance.BootVolumeAttachment.Volume.ID + } else { + return "" + } + volumeIId := irs.IID{SystemId: bootVolumeId} + rawVolume, err := getRawVolume(volumeIId, vmHandler.VpcService, vmHandler.Ctx) + + if err == nil { + return strconv.Itoa(int(*rawVolume.Capacity)) + } + return "" +} + +// networkDone <- vmHandler.getNetworkInfo(*instance.ID, *instance.PrimaryNetworkInterface.ID, *instance.VPC.ID) +func (vmHandler *IbmVMHandler) getNetworkInfo(instance vpcv1.Instance) vmNetworkInfo { + // Network Get + var instanceId = "" + var instancePrimaryNIId = "" + var vpcId = "" + if instance.ID != nil { + instanceId = *instance.ID + } + if instance.PrimaryNetworkInterface != nil && instance.PrimaryNetworkInterface.ID != nil { + instancePrimaryNIId = *instance.PrimaryNetworkInterface.ID + } + if instance.VPC != nil && instance.VPC.ID != nil { + vpcId = *instance.VPC.ID + } + if instanceId == "" || instancePrimaryNIId == "" { + return vmNetworkInfo{} + } + info := vmNetworkInfo{} + instanceNetworkInterfaceOptions := &vpcv1.GetInstanceNetworkInterfaceOptions{} + instanceNetworkInterfaceOptions.SetID(instancePrimaryNIId) + instanceNetworkInterfaceOptions.SetInstanceID(instanceId) + networkInterface, _, err := vmHandler.VpcService.GetInstanceNetworkInterfaceWithContext(vmHandler.Ctx, instanceNetworkInterfaceOptions) + if err == nil { + // SET IP + info.NetworkInterface = *networkInterface.Name + if networkInterface.FloatingIps != nil && len(networkInterface.FloatingIps) > 0 { + info.PublicIP = *networkInterface.FloatingIps[0].Address + info.AccessPoint = info.PublicIP + } + if vpcId == "" { + info.SecurityGroupIIds = []irs.IID{} + return info + } + // SET SG + getVpcOptions := &vpcv1.GetVPCOptions{} + getVpcOptions.SetID(vpcId) + vpc, _, _ := vmHandler.VpcService.GetVPCWithContext(vmHandler.Ctx, getVpcOptions) + var sgIIds []irs.IID + if vpc != nil && vpc.DefaultSecurityGroup != nil { + defaultSGId := *vpc.DefaultSecurityGroup.ID + vmSecurityGroups := networkInterface.SecurityGroups + for _, seg := range vmSecurityGroups { + if defaultSGId != *seg.ID { + sgIIds = append(sgIIds, irs.IID{NameId: *seg.Name, SystemId: *seg.ID}) + } + } + } + info.SecurityGroupIIds = sgIIds + } + return info +} + +func (vmHandler *IbmVMHandler) setVmInfo(instance vpcv1.Instance) (irs.VMInfo, error) { + var dataDiskIIDs []irs.IID + for _, rawDataDisk := range instance.VolumeAttachments { + if *rawDataDisk.Volume.ID != *instance.BootVolumeAttachment.Volume.ID { + dataDiskIIDs = append(dataDiskIIDs, irs.IID{ + NameId: *rawDataDisk.Volume.Name, + SystemId: *rawDataDisk.Volume.ID, + }) + } + } + vmInfo := irs.VMInfo{ + IId: irs.IID{ + NameId: *instance.Name, + SystemId: *instance.ID, + }, + StartTime: time.Time(*instance.CreatedAt).Local(), + Region: irs.RegionInfo{ + Region: vmHandler.Region.Region, + Zone: *instance.Zone.Name, + }, + VMSpecName: *instance.Profile.Name, + VpcIID: irs.IID{ + NameId: *instance.VPC.Name, + SystemId: *instance.VPC.ID, + }, + SubnetIID: irs.IID{ + NameId: *instance.PrimaryNetworkInterface.Subnet.Name, + SystemId: *instance.PrimaryNetworkInterface.Subnet.ID, + }, + PrivateIP: *instance.PrimaryNetworkInterface.PrimaryIpv4Address, + VMUserId: CBDefaultVmUserName, + RootDeviceName: "Not visible in IBMCloud-VPC", + VMBlockDisk: "Not visible in IBMCloud-VPC", + DataDiskIIDs: dataDiskIIDs, + } + chanCount := 0 + // KeyGet + keyDone := make(chan irs.IID) + chanCount++ + go func() { + keyDone <- vmHandler.getKeyIId(instance) + }() + + networkDone := make(chan vmNetworkInfo) + chanCount++ + go func() { + networkDone <- vmHandler.getNetworkInfo(instance) + }() + + volumeDone := make(chan string) + chanCount++ + go func() { + volumeDone <- vmHandler.getBootVolumeInfo(instance) + }() + + for i := 0; i < chanCount; i++ { + select { + case keyIID := <-keyDone: + vmInfo.KeyPairIId = keyIID + case netInfo := <-networkDone: + vmInfo.NetworkInterface = netInfo.NetworkInterface + vmInfo.PublicIP = netInfo.PublicIP + vmInfo.AccessPoint = netInfo.AccessPoint + vmInfo.SecurityGroupIIds = netInfo.SecurityGroupIIds + case volumeRootDiskSize := <-volumeDone: + vmInfo.RootDiskSize = volumeRootDiskSize + } + } + + vmInfo.RootDiskType = "general-purpose" + + vmInfo.VMBootDisk = *instance.BootVolumeAttachment.Volume.ID + rawBootDisk, getRawBootDiskErr := getRawDisk(vmHandler.VpcService, vmHandler.Ctx, irs.IID{SystemId: vmInfo.VMBootDisk}) + if getRawBootDiskErr == nil { + isWindows := strings.Contains(strings.ToLower(*rawBootDisk.OperatingSystem.Name), "windows") + if isWindows { + vmInfo.Platform = irs.WINDOWS + vmInfo.VMUserId = "Administrator" + vmInfo.AccessPoint = vmInfo.AccessPoint + ":3389" + } else { + vmInfo.Platform = irs.LINUX_UNIX + vmInfo.VMUserId = "cb-user" + vmInfo.AccessPoint = vmInfo.AccessPoint + ":22" + } + } + + return vmInfo, nil +} + +func (vmHandler *IbmVMHandler) checkFloatingIPName(floatingIPName string) (exist bool, err error) { + options := &vpcv1.ListFloatingIpsOptions{} + floatingIPs, _, err := vmHandler.VpcService.ListFloatingIpsWithContext(vmHandler.Ctx, options) + if err != nil { + return false, err + } + for { + for _, floatingIP := range floatingIPs.FloatingIps { + if *floatingIP.Name == floatingIPName { + return true, nil + } + } + nextstr, _ := getFloatIPsNextHref(floatingIPs.Next) + if nextstr != "" { + listFloatingNext := &vpcv1.ListFloatingIpsOptions{ + Start: core.StringPtr(nextstr), + } + floatingIPs, _, err = vmHandler.VpcService.ListFloatingIpsWithContext(vmHandler.Ctx, listFloatingNext) + if err != nil { + return false, err + } + } else { + break + } + } + return false, nil +} + +func notSupportRootDiskCustom(vmReqInfo irs.VMReqInfo) error { + if vmReqInfo.RootDiskType != "" && strings.ToLower(vmReqInfo.RootDiskType) != "default" { + return errors.New("IBM-VPC_CANNOT_CHANGE_ROOTDISKTYPE") + } + if vmReqInfo.RootDiskSize != "" && strings.ToLower(vmReqInfo.RootDiskSize) != "default" { + return errors.New("IBM-VPC_CANNOT_CHANGE_ROOTDISKSIZE") + } + return nil +} + +type vmInfoWithError struct { + VMInfo irs.VMInfo + err error +} + +func (vmHandler *IbmVMHandler) setVmInfoWithContext(ctx context.Context, instance vpcv1.Instance) (irs.VMInfo, error) { + done := make(chan vmInfoWithError) + + go func() { + vmInfo, err := vmHandler.setVmInfo(instance) + done <- vmInfoWithError{ + VMInfo: vmInfo, + err: err, + } + }() + select { + case vmInfoWithErrorDone := <-done: + return vmInfoWithErrorDone.VMInfo, vmInfoWithErrorDone.err + case <-ctx.Done(): + return irs.VMInfo{}, nil + } +} + +func (vmHandler *IbmVMHandler) setVMList(instanceList []vpcv1.Instance) ([]*irs.VMInfo, error) { + vmListCount := len(instanceList) + vmList := make([]*irs.VMInfo, len(instanceList)) + + if vmListCount == 0 { + return vmList, nil + } + var wg sync.WaitGroup + + ctx, cancel := context.WithCancel(context.Background()) + + defer cancel() + + var globalErr error + + for i, vmInstance := range instanceList { + wg.Add(1) + index := i + dumpInstance := vmInstance + go func() { + defer wg.Done() + vmInfo, err := vmHandler.setVmInfoWithContext(ctx, dumpInstance) + if err != nil { + cancel() + if globalErr == nil { + globalErr = err + } + } + vmList[index] = &vmInfo + }() + } + wg.Wait() + + if globalErr != nil { + return nil, globalErr + } + + return vmList, nil +} diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VPCHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VPCHandler.go index acc39a360..d1a121e10 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VPCHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/VPCHandler.go @@ -1,731 +1,780 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "net/url" - "time" - - "github.com/IBM/go-sdk-core/v5/core" - "github.com/IBM/vpc-go-sdk/vpcv1" - 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 IbmVPCHandler struct { - CredentialInfo idrv.CredentialInfo - Region idrv.RegionInfo - VpcService *vpcv1.VpcV1 - Ctx context.Context -} - -func checkValidVpcReqInfo(vpcReqInfo irs.VPCReqInfo) error { - if vpcReqInfo.IId.NameId == "" { - return errors.New("invalid VPCReqInfo NameId") - } - if vpcReqInfo.IPv4_CIDR == "" { - return errors.New("invalid VPCReqInfo IPv4_CIDR") - } - if vpcReqInfo.SubnetInfoList != nil { - for _, subnetInfo := range vpcReqInfo.SubnetInfoList { - if subnetInfo.IPv4_CIDR == "" || subnetInfo.IId.NameId == "" { - return errors.New("invalid subnetInfo") - } - } - } - return nil -} - -func (vpcHandler *IbmVPCHandler) CreateVPC(vpcReqInfo irs.VPCReqInfo) (irs.VPCInfo, error) { - hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, "VPC", "CreateVPC()") - start := call.Start() - err := checkValidVpcReqInfo(vpcReqInfo) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - - if vpcHandler.Region.Zone == "" { - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = Zone is not provided")) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - - exist, err := existVpc(vpcReqInfo.IId, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - if exist { - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = VPC is already exist")) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - - // Create VPC - createVPCOptions := &vpcv1.CreateVPCOptions{} - createVPCOptions.SetAddressPrefixManagement("manual") - createVPCOptions.SetName(vpcReqInfo.IId.NameId) - vpc, _, err := vpcHandler.VpcService.CreateVPCWithContext(vpcHandler.Ctx, createVPCOptions) - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - newVpcIId := irs.IID{ - NameId: *vpc.Name, - SystemId: *vpc.ID, - } - if len(vpcReqInfo.SubnetInfoList) == 0 { - createErr := errors.New("Failed to Create VPC err = Subnet info list is not provided") - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - - // If the zone is not specified in the subnet, use the zone of the connection. - for i, subnetInfo := range vpcReqInfo.SubnetInfoList { - if subnetInfo.Zone == "" { - vpcReqInfo.SubnetInfoList[i].Zone = vpcHandler.Region.Zone - } - } - - // createVPCAddressPrefix - createVPCAddressPrefixOptions := &vpcv1.CreateVPCAddressPrefixOptions{} - createVPCAddressPrefixOptions.SetVPCID(newVpcIId.SystemId) - createVPCAddressPrefixOptions.SetCIDR(vpcReqInfo.IPv4_CIDR) - createVPCAddressPrefixOptions.SetName(newVpcIId.NameId) - createVPCAddressPrefixOptions.SetZone(&vpcv1.ZoneIdentity{ - Name: core.StringPtr(vpcReqInfo.SubnetInfoList[0].Zone), - }) - _, _, err = vpcHandler.VpcService.CreateVPCAddressPrefixWithContext(vpcHandler.Ctx, createVPCAddressPrefixOptions) - // createVPCAddressPrefix error - if err != nil { - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - _, delErr := vpcHandler.DeleteVPC(newVpcIId) - if delErr != nil { - createErr = errors.New(err.Error() + delErr.Error()) - } - return irs.VPCInfo{}, createErr - } - - if vpcReqInfo.SubnetInfoList != nil && len(vpcReqInfo.SubnetInfoList) > 0 { - for _, subnetInfo := range vpcReqInfo.SubnetInfoList { - err = attachSubnet(*vpc, subnetInfo, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - _, delErr := vpcHandler.DeleteVPC(newVpcIId) - if delErr != nil { - err = errors.New(err.Error() + delErr.Error()) - } - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - } - } - //// default SecurityGroup modify - options := &vpcv1.GetSecurityGroupOptions{} - options.SetID(*vpc.DefaultSecurityGroup.ID) - sg, _, err := vpcHandler.VpcService.GetSecurityGroupWithContext(vpcHandler.Ctx, options) - - if err != nil { - _, delErr := vpcHandler.DeleteVPC(newVpcIId) - if delErr != nil { - err = errors.New(err.Error() + delErr.Error()) - } - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - - err = ModifyVPCDefaultRule(sg.Rules, irs.IID{NameId: *sg.Name, SystemId: *sg.ID}, vpcHandler.VpcService, vpcHandler.Ctx) - - if err != nil { - _, delErr := vpcHandler.DeleteVPC(newVpcIId) - if delErr != nil { - err = errors.New(err.Error() + delErr.Error()) - } - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - - vpcInfo, err := setVPCInfo(*vpc, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - _, delErr := vpcHandler.DeleteVPC(newVpcIId) - if delErr != nil { - err = errors.New(err.Error() + delErr.Error()) - } - createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) - cblogger.Error(createErr.Error()) - LoggingError(hiscallInfo, createErr) - return irs.VPCInfo{}, createErr - } - LoggingInfo(hiscallInfo, start) - return vpcInfo, nil -} -func (vpcHandler *IbmVPCHandler) ListVPC() ([]*irs.VPCInfo, error) { - hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, "VPC", "ListVPC()") - listVpcsOptions := &vpcv1.ListVpcsOptions{} - var vpcInfos []*irs.VPCInfo - start := call.Start() - vpcs, _, err := vpcHandler.VpcService.ListVpcsWithContext(vpcHandler.Ctx, listVpcsOptions) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VPC err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - // Next Check - for { - for _, vpc := range vpcs.Vpcs { - vpcInfo, err := setVPCInfo(vpc, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VPC err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - vpcInfos = append(vpcInfos, &vpcInfo) - } - nextstr, _ := getVPCNextHref(vpcs.Next) - if nextstr != "" { - listVpcsOptions2 := &vpcv1.ListVpcsOptions{ - Start: core.StringPtr(nextstr), - } - vpcs, _, err = vpcHandler.VpcService.ListVpcsWithContext(vpcHandler.Ctx, listVpcsOptions2) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to List VPC err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return nil, getErr - } - } else { - break - } - } - LoggingInfo(hiscallInfo, start) - return vpcInfos, nil -} -func (vpcHandler *IbmVPCHandler) GetVPC(vpcIID irs.IID) (irs.VPCInfo, error) { - hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, "VPC", "GetVPC()") - start := call.Start() - vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.VPCInfo{}, getErr - } - // default SecurityGroup modify - - options := &vpcv1.GetSecurityGroupOptions{} - options.SetID(*vpc.DefaultSecurityGroup.ID) - sg, _, err := vpcHandler.VpcService.GetSecurityGroupWithContext(vpcHandler.Ctx, options) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.VPCInfo{}, getErr - } - err = ModifyVPCDefaultRule(sg.Rules, irs.IID{NameId: *sg.Name, SystemId: *sg.ID}, vpcHandler.VpcService, vpcHandler.Ctx) - - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.VPCInfo{}, getErr - } - vpcInfo, err := setVPCInfo(vpc, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) - cblogger.Error(getErr.Error()) - LoggingError(hiscallInfo, getErr) - return irs.VPCInfo{}, getErr - } - LoggingInfo(hiscallInfo, start) - return vpcInfo, nil -} -func (vpcHandler *IbmVPCHandler) DeleteVPC(vpcIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, vpcIID.NameId, "DeleteVPC()") - start := call.Start() - vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - - // Remove all Subnet - rawSubnets, err := getVPCRawSubnets(vpc, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - if rawSubnets != nil { - for _, subnet := range rawSubnets { - options := &vpcv1.DeleteSubnetOptions{} - options.SetID(*subnet.ID) - _, err := vpcHandler.VpcService.DeleteSubnetWithContext(vpcHandler.Ctx, options) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - } - } - // subnets delete Time delay - curRetryCnt := 0 - maxRetryCnt := 60 - for { - rawDeleteSubnets, err := getVPCRawSubnets(vpc, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - if rawDeleteSubnets == nil { - break - } - curRetryCnt++ - time.Sleep(1 * time.Second) - if curRetryCnt > maxRetryCnt { - err = errors.New("failed delete VPC - subnets delete TimeOut") - delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - } - // Delete VPC - deleteVpcOptions := &vpcv1.DeleteVPCOptions{} - deleteVpcOptions.SetID(*vpc.ID) - _, err = vpcHandler.VpcService.DeleteVPCWithContext(vpcHandler.Ctx, deleteVpcOptions) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - LoggingInfo(hiscallInfo, start) - return true, nil -} -func (vpcHandler *IbmVPCHandler) AddSubnet(vpcIID irs.IID, subnetInfo irs.SubnetInfo) (irs.VPCInfo, error) { - hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, subnetInfo.IId.NameId, "AddSubnet()") - start := call.Start() - vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) - cblogger.Error(addSubnetErr.Error()) - LoggingError(hiscallInfo, addSubnetErr) - return irs.VPCInfo{}, addSubnetErr - } - err = attachSubnet(vpc, subnetInfo, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) - cblogger.Error(addSubnetErr.Error()) - LoggingError(hiscallInfo, addSubnetErr) - return irs.VPCInfo{}, addSubnetErr - } - LoggingInfo(hiscallInfo, start) - vpc, err = GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) - cblogger.Error(addSubnetErr.Error()) - LoggingError(hiscallInfo, addSubnetErr) - return irs.VPCInfo{}, addSubnetErr - } - vpcInfo, err := setVPCInfo(vpc, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) - cblogger.Error(addSubnetErr.Error()) - LoggingError(hiscallInfo, addSubnetErr) - return irs.VPCInfo{}, addSubnetErr - } - return vpcInfo, nil -} -func (vpcHandler *IbmVPCHandler) RemoveSubnet(vpcIID irs.IID, subnetIID irs.IID) (bool, error) { - hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, subnetIID.NameId, "RemoveSubnet()") - start := call.Start() - if subnetIID.SystemId != "" { - options := &vpcv1.DeleteSubnetOptions{} - options.SetID(subnetIID.SystemId) - _, err := vpcHandler.VpcService.DeleteSubnetWithContext(vpcHandler.Ctx, options) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - LoggingInfo(hiscallInfo, start) - return true, nil - } - vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - rawSubnets, err := getVPCRawSubnets(vpc, vpcHandler.VpcService, vpcHandler.Ctx) - if len(rawSubnets) > 0 { - for _, subnet := range rawSubnets { - if *subnet.Name == subnetIID.NameId { - options := &vpcv1.DeleteSubnetOptions{} - options.SetID(*subnet.ID) - _, err := vpcHandler.VpcService.DeleteSubnetWithContext(vpcHandler.Ctx, options) - if err != nil { - delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr - } - LoggingInfo(hiscallInfo, start) - return true, nil - } - } - } - err = errors.New("not found subnet") - delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) - cblogger.Error(delErr.Error()) - LoggingError(hiscallInfo, delErr) - return false, delErr -} - -func attachSubnet(vpc vpcv1.VPC, subnetInfo irs.SubnetInfo, vpcService *vpcv1.VpcV1, ctx context.Context) error { - if subnetInfo.IPv4_CIDR == "" || subnetInfo.IId.NameId == "" { - return errors.New("invalid subnetInfo") - } - exist, err := existSubnet(subnetInfo.IId, vpc, vpcService, ctx) - if err != nil { - return err - } else if exist { - err = errors.New(fmt.Sprintf("already exist %s", subnetInfo.IId.NameId)) - return err - } - - options := &vpcv1.CreateSubnetOptions{} - options.SetSubnetPrototype(&vpcv1.SubnetPrototype{ - Ipv4CIDRBlock: core.StringPtr(subnetInfo.IPv4_CIDR), - Name: core.StringPtr(subnetInfo.IId.NameId), - VPC: &vpcv1.VPCIdentity{ - ID: vpc.ID, - }, - Zone: &vpcv1.ZoneIdentity{ - Name: &subnetInfo.Zone, - }, - }) - _, _, err = vpcService.CreateSubnetWithContext(ctx, options) - return err -} -func getVPCNextHref(next *vpcv1.VPCCollectionNext) (string, error) { - if next != nil { - href := *next.Href - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - } - return "", errors.New("NOT NEXT") -} -func getSubnetNextHref(next *vpcv1.SubnetCollectionNext) (string, error) { - if next != nil { - href := *next.Href - u, err := url.Parse(href) - if err != nil { - return "", err - } - paramMap, _ := url.ParseQuery(u.RawQuery) - if paramMap != nil { - safe := paramMap["start"] - if safe != nil && len(safe) > 0 { - return safe[0], nil - } - } - } - return "", errors.New("NOT NEXT") -} - -func existSubnet(subnetIID irs.IID, vpc vpcv1.VPC, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { - options := &vpcv1.ListSubnetsOptions{} - subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - return false, err - } - for { - if *subnets.TotalCount > 0 { - for _, subnet := range subnets.Subnets { - if *subnet.VPC.ID == *vpc.ID { - if subnetIID.NameId == *subnet.Name || *subnet.ID == subnetIID.SystemId { - return true, nil - } - } - } - } - nextstr, _ := getSubnetNextHref(subnets.Next) - if nextstr != "" { - options := &vpcv1.ListSubnetsOptions{ - Start: core.StringPtr(nextstr), - } - subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - return false, errors.New("failed Get SubnetList") - } - } else { - break - } - } - return false, nil -} - -func existVpc(vpcIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { - if vpcIID.NameId == "" { - return false, errors.New("inValid Name") - } else { - listVpcsOptions := &vpcv1.ListVpcsOptions{} - vpcs, _, err := vpcService.ListVpcsWithContext(ctx, listVpcsOptions) - if err != nil { - return false, err - } - for { - if vpcs.Vpcs != nil { - for _, vpc := range vpcs.Vpcs { - if *vpc.Name == vpcIID.NameId { - return true, nil - } - } - } - nextstr, _ := getVPCNextHref(vpcs.Next) - if nextstr != "" { - listVpcsOptions2 := &vpcv1.ListVpcsOptions{ - Start: core.StringPtr(nextstr), - } - vpcs, _, err = vpcService.ListVpcsWithContext(ctx, listVpcsOptions2) - if err != nil { - return false, errors.New("failed Get VPCList") - } - } else { - break - } - } - return false, nil - } -} -func GetRawVPC(vpcIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.VPC, error) { - if vpcIID.SystemId == "" { - listVpcsOptions := &vpcv1.ListVpcsOptions{} - vpcs, _, err := vpcService.ListVpcsWithContext(ctx, listVpcsOptions) - if err != nil { - return vpcv1.VPC{}, err - } - for { - if vpcs.Vpcs != nil { - for _, vpc := range vpcs.Vpcs { - if *vpc.Name == vpcIID.NameId { - return vpc, nil - } - } - } - nextstr, _ := getVPCNextHref(vpcs.Next) - if nextstr != "" { - listVpcsOptions2 := &vpcv1.ListVpcsOptions{ - Start: core.StringPtr(nextstr), - } - vpcs, _, err = vpcService.ListVpcsWithContext(ctx, listVpcsOptions2) - if err != nil { - break - } - } else { - break - } - } - // NOT EXIST! - if vpcIID.NameId != "" { - err = errors.New(fmt.Sprintf("VPC not found %s", vpcIID.NameId)) - } else { - err = errors.New("VPC not found") - } - return vpcv1.VPC{}, err - } else { - getVpcOptions := &vpcv1.GetVPCOptions{ - ID: &vpcIID.SystemId, - } - vpc, _, err := vpcService.GetVPCWithContext(ctx, getVpcOptions) - if err != nil { - return vpcv1.VPC{}, err - } - return *vpc, nil - } -} - -func getVPCRawSubnets(vpc vpcv1.VPC, vpcService *vpcv1.VpcV1, ctx context.Context) ([]vpcv1.Subnet, error) { - options := &vpcv1.ListSubnetsOptions{} - subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - return nil, err - } - var newSubnetInfos []vpcv1.Subnet - for { - if *subnets.TotalCount > 0 { - for _, subnet := range subnets.Subnets { - if *subnet.VPC.ID == *vpc.ID { - newSubnetInfos = append(newSubnetInfos, subnet) - } - } - } - nextstr, _ := getSubnetNextHref(subnets.Next) - if nextstr != "" { - options := &vpcv1.ListSubnetsOptions{ - Start: core.StringPtr(nextstr), - } - subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - break - } - } else { - break - } - } - return newSubnetInfos, nil -} - -func getRawSubnet(subnetIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Subnet, error) { - options := &vpcv1.ListSubnetsOptions{} - subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - return vpcv1.Subnet{}, err - } - var subnetFoundByName bool - var foundedSubnetByName vpcv1.Subnet - for { - if *subnets.TotalCount > 0 { - for _, subnet := range subnets.Subnets { - if subnetIID.SystemId != "" && *subnet.ID == subnetIID.SystemId { - return subnet, nil - } - if subnetIID.NameId == *subnet.Name { - if subnetFoundByName { - return vpcv1.Subnet{}, errors.New("found multiple subnets") - } - subnetFoundByName = true - foundedSubnetByName = subnet - } - } - } - nextstr, _ := getSubnetNextHref(subnets.Next) - if nextstr != "" { - options := &vpcv1.ListSubnetsOptions{ - Start: core.StringPtr(nextstr), - } - subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - break - } - } else { - break - } - } - - if subnetFoundByName { - return foundedSubnetByName, nil - } - - return vpcv1.Subnet{}, err -} - -func getVPCRawSubnet(vpc vpcv1.VPC, subnetIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Subnet, error) { - options := &vpcv1.ListSubnetsOptions{} - subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - return vpcv1.Subnet{}, err - } - for { - if *subnets.TotalCount > 0 { - for _, subnet := range subnets.Subnets { - if *subnet.VPC.ID == *vpc.ID { - if subnetIID.NameId == *subnet.Name || *subnet.ID == subnetIID.SystemId { - return subnet, nil - } - } - } - } - nextstr, _ := getSubnetNextHref(subnets.Next) - if nextstr != "" { - options := &vpcv1.ListSubnetsOptions{ - Start: core.StringPtr(nextstr), - } - subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) - if err != nil { - break - } - } else { - break - } - } - return vpcv1.Subnet{}, err -} - -func setVPCInfo(vpc vpcv1.VPC, vpcService *vpcv1.VpcV1, ctx context.Context) (irs.VPCInfo, error) { - vpcInfo := irs.VPCInfo{ - IId: irs.IID{ - NameId: *vpc.Name, - SystemId: *vpc.ID, - }, - } - listVpcAddressPrefixesOptions := &vpcv1.ListVPCAddressPrefixesOptions{} - listVpcAddressPrefixesOptions.SetVPCID(*vpc.ID) - addressPrefixes, _, err := vpcService.ListVPCAddressPrefixesWithContext(ctx, listVpcAddressPrefixesOptions) - if err != nil { - return irs.VPCInfo{}, err - } - if *addressPrefixes.TotalCount > 0 { - cidr := *addressPrefixes.AddressPrefixes[0].CIDR - vpcInfo.IPv4_CIDR = cidr - } - rawSubnets, err := getVPCRawSubnets(vpc, vpcService, ctx) - if err != nil { - return irs.VPCInfo{}, err - } - if len(rawSubnets) > 0 { - var newSubnetInfos []irs.SubnetInfo - for _, subnet := range rawSubnets { - subnetInfo := irs.SubnetInfo{ - IId: irs.IID{ - NameId: *subnet.Name, - SystemId: *subnet.ID, - }, - Zone: *subnet.Zone.Name, - IPv4_CIDR: *subnet.Ipv4CIDRBlock, - } - newSubnetInfos = append(newSubnetInfos, subnetInfo) - } - vpcInfo.SubnetInfoList = newSubnetInfos - } - return vpcInfo, nil -} +package resources + +import ( + "context" + "errors" + "fmt" + "net/url" + "time" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/platform-services-go-sdk/globaltaggingv1" + "github.com/IBM/vpc-go-sdk/vpcv1" + 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 IbmVPCHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + VpcService *vpcv1.VpcV1 + Ctx context.Context +} + +func checkValidVpcReqInfo(vpcReqInfo irs.VPCReqInfo) error { + if vpcReqInfo.IId.NameId == "" { + return errors.New("invalid VPCReqInfo NameId") + } + if vpcReqInfo.IPv4_CIDR == "" { + return errors.New("invalid VPCReqInfo IPv4_CIDR") + } + if vpcReqInfo.SubnetInfoList != nil { + for _, subnetInfo := range vpcReqInfo.SubnetInfoList { + if subnetInfo.IPv4_CIDR == "" || subnetInfo.IId.NameId == "" { + return errors.New("invalid subnetInfo") + } + } + } + return nil +} + +func (vpcHandler *IbmVPCHandler) CreateVPC(vpcReqInfo irs.VPCReqInfo) (irs.VPCInfo, error) { + hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, "VPC", "CreateVPC()") + start := call.Start() + err := checkValidVpcReqInfo(vpcReqInfo) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + + if vpcHandler.Region.Zone == "" { + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = Zone is not provided")) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + + exist, err := existVpc(vpcReqInfo.IId, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + if exist { + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = VPC is already exist")) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + + // Create VPC + createVPCOptions := &vpcv1.CreateVPCOptions{} + createVPCOptions.SetAddressPrefixManagement("manual") + createVPCOptions.SetName(vpcReqInfo.IId.NameId) + vpc, _, err := vpcHandler.VpcService.CreateVPCWithContext(vpcHandler.Ctx, createVPCOptions) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + newVpcIId := irs.IID{ + NameId: *vpc.Name, + SystemId: *vpc.ID, + } + if len(vpcReqInfo.SubnetInfoList) == 0 { + createErr := errors.New("Failed to Create VPC err = Subnet info list is not provided") + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + + // If the zone is not specified in the subnet, use the zone of the connection. + for i, subnetInfo := range vpcReqInfo.SubnetInfoList { + if subnetInfo.Zone == "" { + vpcReqInfo.SubnetInfoList[i].Zone = vpcHandler.Region.Zone + } + } + + // createVPCAddressPrefix + createVPCAddressPrefixOptions := &vpcv1.CreateVPCAddressPrefixOptions{} + createVPCAddressPrefixOptions.SetVPCID(newVpcIId.SystemId) + createVPCAddressPrefixOptions.SetCIDR(vpcReqInfo.IPv4_CIDR) + createVPCAddressPrefixOptions.SetName(newVpcIId.NameId) + createVPCAddressPrefixOptions.SetZone(&vpcv1.ZoneIdentity{ + Name: core.StringPtr(vpcReqInfo.SubnetInfoList[0].Zone), + }) + _, _, err = vpcHandler.VpcService.CreateVPCAddressPrefixWithContext(vpcHandler.Ctx, createVPCAddressPrefixOptions) + // createVPCAddressPrefix error + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + _, delErr := vpcHandler.DeleteVPC(newVpcIId) + if delErr != nil { + createErr = errors.New(err.Error() + delErr.Error()) + } + return irs.VPCInfo{}, createErr + } + + if vpcReqInfo.SubnetInfoList != nil && len(vpcReqInfo.SubnetInfoList) > 0 { + for _, subnetInfo := range vpcReqInfo.SubnetInfoList { + err = attachSubnet(*vpc, subnetInfo, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + _, delErr := vpcHandler.DeleteVPC(newVpcIId) + if delErr != nil { + err = errors.New(err.Error() + delErr.Error()) + } + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + // Attach Tag + if subnetInfo.TagList != nil && len(subnetInfo.TagList) > 0 { + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range subnetInfo.TagList{ + _, err := tagHandler.AddTag("SUBNET", subnetInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on Subnet err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + } + } + //// default SecurityGroup modify + options := &vpcv1.GetSecurityGroupOptions{} + options.SetID(*vpc.DefaultSecurityGroup.ID) + sg, _, err := vpcHandler.VpcService.GetSecurityGroupWithContext(vpcHandler.Ctx, options) + + if err != nil { + _, delErr := vpcHandler.DeleteVPC(newVpcIId) + if delErr != nil { + err = errors.New(err.Error() + delErr.Error()) + } + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + + err = ModifyVPCDefaultRule(sg.Rules, irs.IID{NameId: *sg.Name, SystemId: *sg.ID}, vpcHandler.VpcService, vpcHandler.Ctx) + + if err != nil { + _, delErr := vpcHandler.DeleteVPC(newVpcIId) + if delErr != nil { + err = errors.New(err.Error() + delErr.Error()) + } + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + + vpcInfo, err := setVPCInfo(*vpc, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + _, delErr := vpcHandler.DeleteVPC(newVpcIId) + if delErr != nil { + err = errors.New(err.Error() + delErr.Error()) + } + createErr := errors.New(fmt.Sprintf("Failed to Create VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.VPCInfo{}, createErr + } + + // Attach Tag + if vpcInfo.TagList != nil && len(vpcInfo.TagList) > 0 { + var tagHandler irs.TagHandler // TagHandler 초기화 + for _, tag := range vpcInfo.TagList{ + _, err := tagHandler.AddTag("VPC", vpcInfo.IId, tag) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to Attach Tag on VPC err = %s", err.Error())) + cblogger.Error(createErr.Error()) + } + } + } + + LoggingInfo(hiscallInfo, start) + return vpcInfo, nil +} +func (vpcHandler *IbmVPCHandler) ListVPC() ([]*irs.VPCInfo, error) { + hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, "VPC", "ListVPC()") + listVpcsOptions := &vpcv1.ListVpcsOptions{} + var vpcInfos []*irs.VPCInfo + start := call.Start() + vpcs, _, err := vpcHandler.VpcService.ListVpcsWithContext(vpcHandler.Ctx, listVpcsOptions) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VPC err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + // Next Check + for { + for _, vpc := range vpcs.Vpcs { + vpcInfo, err := setVPCInfo(vpc, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VPC err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + vpcInfos = append(vpcInfos, &vpcInfo) + } + nextstr, _ := getVPCNextHref(vpcs.Next) + if nextstr != "" { + listVpcsOptions2 := &vpcv1.ListVpcsOptions{ + Start: core.StringPtr(nextstr), + } + vpcs, _, err = vpcHandler.VpcService.ListVpcsWithContext(vpcHandler.Ctx, listVpcsOptions2) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to List VPC err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + } else { + break + } + } + LoggingInfo(hiscallInfo, start) + return vpcInfos, nil +} +func (vpcHandler *IbmVPCHandler) GetVPC(vpcIID irs.IID) (irs.VPCInfo, error) { + hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, "VPC", "GetVPC()") + start := call.Start() + vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.VPCInfo{}, getErr + } + // default SecurityGroup modify + + options := &vpcv1.GetSecurityGroupOptions{} + options.SetID(*vpc.DefaultSecurityGroup.ID) + sg, _, err := vpcHandler.VpcService.GetSecurityGroupWithContext(vpcHandler.Ctx, options) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.VPCInfo{}, getErr + } + err = ModifyVPCDefaultRule(sg.Rules, irs.IID{NameId: *sg.Name, SystemId: *sg.ID}, vpcHandler.VpcService, vpcHandler.Ctx) + + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.VPCInfo{}, getErr + } + vpcInfo, err := setVPCInfo(vpc, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to Get VPC err = %s", err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.VPCInfo{}, getErr + } + LoggingInfo(hiscallInfo, start) + return vpcInfo, nil +} +func (vpcHandler *IbmVPCHandler) DeleteVPC(vpcIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, vpcIID.NameId, "DeleteVPC()") + start := call.Start() + vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + + // Remove all Subnet + rawSubnets, err := getVPCRawSubnets(vpc, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + if rawSubnets != nil { + for _, subnet := range rawSubnets { + options := &vpcv1.DeleteSubnetOptions{} + options.SetID(*subnet.ID) + _, err := vpcHandler.VpcService.DeleteSubnetWithContext(vpcHandler.Ctx, options) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + } + } + // subnets delete Time delay + curRetryCnt := 0 + maxRetryCnt := 60 + for { + rawDeleteSubnets, err := getVPCRawSubnets(vpc, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + if rawDeleteSubnets == nil { + break + } + curRetryCnt++ + time.Sleep(1 * time.Second) + if curRetryCnt > maxRetryCnt { + err = errors.New("failed delete VPC - subnets delete TimeOut") + delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + } + // Delete VPC + deleteVpcOptions := &vpcv1.DeleteVPCOptions{} + deleteVpcOptions.SetID(*vpc.ID) + _, err = vpcHandler.VpcService.DeleteVPCWithContext(vpcHandler.Ctx, deleteVpcOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete VPC err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete Subnet Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + return true, nil +} +func (vpcHandler *IbmVPCHandler) AddSubnet(vpcIID irs.IID, subnetInfo irs.SubnetInfo) (irs.VPCInfo, error) { + hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, subnetInfo.IId.NameId, "AddSubnet()") + start := call.Start() + vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) + cblogger.Error(addSubnetErr.Error()) + LoggingError(hiscallInfo, addSubnetErr) + return irs.VPCInfo{}, addSubnetErr + } + err = attachSubnet(vpc, subnetInfo, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) + cblogger.Error(addSubnetErr.Error()) + LoggingError(hiscallInfo, addSubnetErr) + return irs.VPCInfo{}, addSubnetErr + } + LoggingInfo(hiscallInfo, start) + vpc, err = GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) + cblogger.Error(addSubnetErr.Error()) + LoggingError(hiscallInfo, addSubnetErr) + return irs.VPCInfo{}, addSubnetErr + } + vpcInfo, err := setVPCInfo(vpc, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + addSubnetErr := errors.New(fmt.Sprintf("Failed to Add Subnet err = %s", err.Error())) + cblogger.Error(addSubnetErr.Error()) + LoggingError(hiscallInfo, addSubnetErr) + return irs.VPCInfo{}, addSubnetErr + } + return vpcInfo, nil +} +func (vpcHandler *IbmVPCHandler) RemoveSubnet(vpcIID irs.IID, subnetIID irs.IID) (bool, error) { + hiscallInfo := GetCallLogScheme(vpcHandler.Region, call.VPCSUBNET, subnetIID.NameId, "RemoveSubnet()") + start := call.Start() + if subnetIID.SystemId != "" { + options := &vpcv1.DeleteSubnetOptions{} + options.SetID(subnetIID.SystemId) + _, err := vpcHandler.VpcService.DeleteSubnetWithContext(vpcHandler.Ctx, options) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + return true, nil + } + vpc, err := GetRawVPC(vpcIID, vpcHandler.VpcService, vpcHandler.Ctx) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + rawSubnets, err := getVPCRawSubnets(vpc, vpcHandler.VpcService, vpcHandler.Ctx) + if len(rawSubnets) > 0 { + for _, subnet := range rawSubnets { + if *subnet.Name == subnetIID.NameId { + options := &vpcv1.DeleteSubnetOptions{} + options.SetID(*subnet.ID) + _, err := vpcHandler.VpcService.DeleteSubnetWithContext(vpcHandler.Ctx, options) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + return true, nil + } + } + } + err = errors.New("not found subnet") + delErr := errors.New(fmt.Sprintf("Failed to Remove Subnet err = %s", err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + + // Detach Tag Auto Delete + var tagService *globaltaggingv1.GlobalTaggingV1 + deleteTagAllOptions := tagService.NewDeleteTagAllOptions() + deleteTagAllOptions.SetTagType("user") + + _, _, err = tagService.DeleteTagAll(deleteTagAllOptions) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to Delete SUBNET Detached Tag err = %s", err.Error())) + cblogger.Error(delErr.Error()) + } + + return false, delErr +} + +func attachSubnet(vpc vpcv1.VPC, subnetInfo irs.SubnetInfo, vpcService *vpcv1.VpcV1, ctx context.Context) error { + if subnetInfo.IPv4_CIDR == "" || subnetInfo.IId.NameId == "" { + return errors.New("invalid subnetInfo") + } + exist, err := existSubnet(subnetInfo.IId, vpc, vpcService, ctx) + if err != nil { + return err + } else if exist { + err = errors.New(fmt.Sprintf("already exist %s", subnetInfo.IId.NameId)) + return err + } + + options := &vpcv1.CreateSubnetOptions{} + options.SetSubnetPrototype(&vpcv1.SubnetPrototype{ + Ipv4CIDRBlock: core.StringPtr(subnetInfo.IPv4_CIDR), + Name: core.StringPtr(subnetInfo.IId.NameId), + VPC: &vpcv1.VPCIdentity{ + ID: vpc.ID, + }, + Zone: &vpcv1.ZoneIdentity{ + Name: &subnetInfo.Zone, + }, + }) + _, _, err = vpcService.CreateSubnetWithContext(ctx, options) + return err +} +func getVPCNextHref(next *vpcv1.VPCCollectionNext) (string, error) { + if next != nil { + href := *next.Href + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + } + return "", errors.New("NOT NEXT") +} +func getSubnetNextHref(next *vpcv1.SubnetCollectionNext) (string, error) { + if next != nil { + href := *next.Href + u, err := url.Parse(href) + if err != nil { + return "", err + } + paramMap, _ := url.ParseQuery(u.RawQuery) + if paramMap != nil { + safe := paramMap["start"] + if safe != nil && len(safe) > 0 { + return safe[0], nil + } + } + } + return "", errors.New("NOT NEXT") +} + +func existSubnet(subnetIID irs.IID, vpc vpcv1.VPC, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { + options := &vpcv1.ListSubnetsOptions{} + subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + return false, err + } + for { + if *subnets.TotalCount > 0 { + for _, subnet := range subnets.Subnets { + if *subnet.VPC.ID == *vpc.ID { + if subnetIID.NameId == *subnet.Name || *subnet.ID == subnetIID.SystemId { + return true, nil + } + } + } + } + nextstr, _ := getSubnetNextHref(subnets.Next) + if nextstr != "" { + options := &vpcv1.ListSubnetsOptions{ + Start: core.StringPtr(nextstr), + } + subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + return false, errors.New("failed Get SubnetList") + } + } else { + break + } + } + return false, nil +} + +func existVpc(vpcIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (bool, error) { + if vpcIID.NameId == "" { + return false, errors.New("inValid Name") + } else { + listVpcsOptions := &vpcv1.ListVpcsOptions{} + vpcs, _, err := vpcService.ListVpcsWithContext(ctx, listVpcsOptions) + if err != nil { + return false, err + } + for { + if vpcs.Vpcs != nil { + for _, vpc := range vpcs.Vpcs { + if *vpc.Name == vpcIID.NameId { + return true, nil + } + } + } + nextstr, _ := getVPCNextHref(vpcs.Next) + if nextstr != "" { + listVpcsOptions2 := &vpcv1.ListVpcsOptions{ + Start: core.StringPtr(nextstr), + } + vpcs, _, err = vpcService.ListVpcsWithContext(ctx, listVpcsOptions2) + if err != nil { + return false, errors.New("failed Get VPCList") + } + } else { + break + } + } + return false, nil + } +} +func GetRawVPC(vpcIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.VPC, error) { + if vpcIID.SystemId == "" { + listVpcsOptions := &vpcv1.ListVpcsOptions{} + vpcs, _, err := vpcService.ListVpcsWithContext(ctx, listVpcsOptions) + if err != nil { + return vpcv1.VPC{}, err + } + for { + if vpcs.Vpcs != nil { + for _, vpc := range vpcs.Vpcs { + if *vpc.Name == vpcIID.NameId { + return vpc, nil + } + } + } + nextstr, _ := getVPCNextHref(vpcs.Next) + if nextstr != "" { + listVpcsOptions2 := &vpcv1.ListVpcsOptions{ + Start: core.StringPtr(nextstr), + } + vpcs, _, err = vpcService.ListVpcsWithContext(ctx, listVpcsOptions2) + if err != nil { + break + } + } else { + break + } + } + // NOT EXIST! + if vpcIID.NameId != "" { + err = errors.New(fmt.Sprintf("VPC not found %s", vpcIID.NameId)) + } else { + err = errors.New("VPC not found") + } + return vpcv1.VPC{}, err + } else { + getVpcOptions := &vpcv1.GetVPCOptions{ + ID: &vpcIID.SystemId, + } + vpc, _, err := vpcService.GetVPCWithContext(ctx, getVpcOptions) + if err != nil { + return vpcv1.VPC{}, err + } + return *vpc, nil + } +} + +func getVPCRawSubnets(vpc vpcv1.VPC, vpcService *vpcv1.VpcV1, ctx context.Context) ([]vpcv1.Subnet, error) { + options := &vpcv1.ListSubnetsOptions{} + subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + return nil, err + } + var newSubnetInfos []vpcv1.Subnet + for { + if *subnets.TotalCount > 0 { + for _, subnet := range subnets.Subnets { + if *subnet.VPC.ID == *vpc.ID { + newSubnetInfos = append(newSubnetInfos, subnet) + } + } + } + nextstr, _ := getSubnetNextHref(subnets.Next) + if nextstr != "" { + options := &vpcv1.ListSubnetsOptions{ + Start: core.StringPtr(nextstr), + } + subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + break + } + } else { + break + } + } + return newSubnetInfos, nil +} + +func getRawSubnet(subnetIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Subnet, error) { + options := &vpcv1.ListSubnetsOptions{} + subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + return vpcv1.Subnet{}, err + } + var subnetFoundByName bool + var foundedSubnetByName vpcv1.Subnet + for { + if *subnets.TotalCount > 0 { + for _, subnet := range subnets.Subnets { + if subnetIID.SystemId != "" && *subnet.ID == subnetIID.SystemId { + return subnet, nil + } + if subnetIID.NameId == *subnet.Name { + if subnetFoundByName { + return vpcv1.Subnet{}, errors.New("found multiple subnets") + } + subnetFoundByName = true + foundedSubnetByName = subnet + } + } + } + nextstr, _ := getSubnetNextHref(subnets.Next) + if nextstr != "" { + options := &vpcv1.ListSubnetsOptions{ + Start: core.StringPtr(nextstr), + } + subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + break + } + } else { + break + } + } + + if subnetFoundByName { + return foundedSubnetByName, nil + } + + return vpcv1.Subnet{}, err +} + +func getVPCRawSubnet(vpc vpcv1.VPC, subnetIID irs.IID, vpcService *vpcv1.VpcV1, ctx context.Context) (vpcv1.Subnet, error) { + options := &vpcv1.ListSubnetsOptions{} + subnets, _, err := vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + return vpcv1.Subnet{}, err + } + for { + if *subnets.TotalCount > 0 { + for _, subnet := range subnets.Subnets { + if *subnet.VPC.ID == *vpc.ID { + if subnetIID.NameId == *subnet.Name || *subnet.ID == subnetIID.SystemId { + return subnet, nil + } + } + } + } + nextstr, _ := getSubnetNextHref(subnets.Next) + if nextstr != "" { + options := &vpcv1.ListSubnetsOptions{ + Start: core.StringPtr(nextstr), + } + subnets, _, err = vpcService.ListSubnetsWithContext(ctx, options) + if err != nil { + break + } + } else { + break + } + } + return vpcv1.Subnet{}, err +} + +func setVPCInfo(vpc vpcv1.VPC, vpcService *vpcv1.VpcV1, ctx context.Context) (irs.VPCInfo, error) { + vpcInfo := irs.VPCInfo{ + IId: irs.IID{ + NameId: *vpc.Name, + SystemId: *vpc.ID, + }, + } + listVpcAddressPrefixesOptions := &vpcv1.ListVPCAddressPrefixesOptions{} + listVpcAddressPrefixesOptions.SetVPCID(*vpc.ID) + addressPrefixes, _, err := vpcService.ListVPCAddressPrefixesWithContext(ctx, listVpcAddressPrefixesOptions) + if err != nil { + return irs.VPCInfo{}, err + } + if *addressPrefixes.TotalCount > 0 { + cidr := *addressPrefixes.AddressPrefixes[0].CIDR + vpcInfo.IPv4_CIDR = cidr + } + rawSubnets, err := getVPCRawSubnets(vpc, vpcService, ctx) + if err != nil { + return irs.VPCInfo{}, err + } + if len(rawSubnets) > 0 { + var newSubnetInfos []irs.SubnetInfo + for _, subnet := range rawSubnets { + subnetInfo := irs.SubnetInfo{ + IId: irs.IID{ + NameId: *subnet.Name, + SystemId: *subnet.ID, + }, + Zone: *subnet.Zone.Name, + IPv4_CIDR: *subnet.Ipv4CIDRBlock, + } + newSubnetInfos = append(newSubnetInfos, subnetInfo) + } + vpcInfo.SubnetInfoList = newSubnetInfos + } + return vpcInfo, nil +}