diff --git a/cloud-control-manager/cloud-driver/drivers/azure/AzureDriver.go b/cloud-control-manager/cloud-driver/drivers/azure/AzureDriver.go index 08fef4cab..f965189ea 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/AzureDriver.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/AzureDriver.go @@ -65,6 +65,7 @@ func (AzureDriver) GetDriverCapability() idrv.DriverCapabilityInfo { drvCapabilityInfo.RegionZoneHandler = true drvCapabilityInfo.PriceInfoHandler = true drvCapabilityInfo.ClusterHandler = true + drvCapabilityInfo.TagHandler = true return drvCapabilityInfo } @@ -242,6 +243,10 @@ func (driver *AzureDriver) ConnectCloud(connectionInfo idrv.ConnectionInfo) (ico if err != nil { return nil, err } + Ctx, tagsClient, err := getTagsClient(connectionInfo.CredentialInfo) + if err != nil { + return nil, err + } iConn := azcon.AzureCloudConnection{ CredentialInfo: connectionInfo.CredentialInfo, Region: connectionInfo.RegionInfo, @@ -270,6 +275,7 @@ func (driver *AzureDriver) ConnectCloud(connectionInfo idrv.ConnectionInfo) (ico VirtualMachineScaleSetVMsClient: virtualMachineScaleSetVMsClient, VirtualMachineRunCommandsClient: virtualMachineRunCommandClient, GroupsClient: groupsClient, + TagsClient: tagsClient, ResourceSkusClient: resourceSkusClient, } @@ -647,3 +653,16 @@ func getResourceSkusClient(credential idrv.CredentialInfo) (context.Context, *co return ctx, &resourceSkusClient, nil } +func getTagsClient(credential idrv.CredentialInfo) (context.Context, *resources.TagsClient, error) { + config := auth.NewClientCredentialsConfig(credential.ClientId, credential.ClientSecret, credential.TenantId) + authorizer, err := config.Authorizer() + if err != nil { + return nil, nil, err + } + + tagsClient := resources.NewTagsClient(credential.SubscriptionId) + tagsClient.Authorizer = authorizer + ctx, _ := context.WithTimeout(context.Background(), cspTimeout*time.Second) + + return ctx, &tagsClient, nil +} \ No newline at end of file diff --git a/cloud-control-manager/cloud-driver/drivers/azure/connect/Azure_CloudConnection.go b/cloud-control-manager/cloud-driver/drivers/azure/connect/Azure_CloudConnection.go index fe7e28bc4..a80e4a91e 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/connect/Azure_CloudConnection.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/connect/Azure_CloudConnection.go @@ -63,6 +63,7 @@ type AzureCloudConnection struct { VirtualMachineRunCommandsClient *compute.VirtualMachineRunCommandsClient GroupsClient *resources.GroupsClient ResourceSkusClient *compute.ResourceSkusClient + TagsClient *resources.TagsClient } func (cloudConn *AzureCloudConnection) CreateImageHandler() (irs.ImageHandler, error) { @@ -232,5 +233,13 @@ func (cloudConn *AzureCloudConnection) CreateAnyCallHandler() (irs.AnyCallHandle } func (cloudConn *AzureCloudConnection) CreateTagHandler() (irs.TagHandler, error) { - return nil, errors.New("Azure Driver: not implemented") + cblogger.Info("Azure Cloud Driver: called CreateTagHandler()!") + tagHandler := azrs.AzureTagHandler{ + CredentialInfo: cloudConn.CredentialInfo, + Region : cloudConn.Region, + Ctx : cloudConn.Ctx, + Client : cloudConn.TagsClient, + } + return &tagHandler, nil + // return nil, errors.New("Azure Driver: not implemented") } diff --git a/cloud-control-manager/cloud-driver/drivers/azure/main/Test_Resources.go b/cloud-control-manager/cloud-driver/drivers/azure/main/Test_Resources.go index 5601da818..a1721e984 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/main/Test_Resources.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/main/Test_Resources.go @@ -4,6 +4,11 @@ import ( "bufio" "errors" "fmt" + "io/ioutil" + "os" + "strings" + "time" + cblog "github.com/cloud-barista/cb-log" azdrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/drivers/azure" idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces" @@ -11,10 +16,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" - "io/ioutil" - "os" - "strings" - "time" ) type Config struct { @@ -164,7 +165,8 @@ func showTestHandlerInfo() { cblogger.Info("10. RegionZoneHandler") cblogger.Info("11. PriceInfoHandler") cblogger.Info("12. ClusterHandler") - cblogger.Info("13. Exit") + cblogger.Info("13. TagHandler") + cblogger.Info("14. Exit") cblogger.Info("==========================================================") } @@ -216,6 +218,8 @@ func getResourceHandler(resourceType string, config Config) (interface{}, error) resourceHandler, err = cloudConnection.CreatePriceInfoHandler() case "cluster": resourceHandler, err = cloudConnection.CreateClusterHandler() + case "tag": + resourceHandler, err = cloudConnection.CreateTagHandler() } if err != nil { @@ -384,6 +388,7 @@ Loop: reqInfo := irs.SecurityReqInfo{ IId: securityIId, SecurityRules: &securityRulesInfos, + TagList: []irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, VpcIID: targetVPCIId, } security, err := securityHandler.CreateSecurity(reqInfo) @@ -463,6 +468,7 @@ func testVPCHandler(config Config) { VPCReqInfo := irs.VPCReqInfo{ IId: vpcIID, IPv4_CIDR: config.Azure.Resources.VPC.IPv4CIDR, + TagList:[]irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, SubnetInfoList: subnetInfoList, } addSubnet := config.Azure.Resources.VPC.AddSubnet @@ -612,6 +618,7 @@ Loop: cblogger.Info("Start CreateKey() ...") reqInfo := irs.KeyPairReqInfo{ IId: keypairIId, + TagList: []irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, } if keyInfo, err := keyPairHandler.CreateKey(reqInfo); err != nil { cblogger.Error(err) @@ -768,6 +775,7 @@ func testVMHandler(config Config) { SecurityGroupIIDs: SecurityGroupIIDs, VMUserId: config.Azure.Resources.Vm.VMUserId, VMUserPasswd: config.Azure.Resources.Vm.VMUserPasswd, + TagList: []irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, } Loop: @@ -897,26 +905,31 @@ func testNLBHandler(config Config) { NameId: "nlb-tester", }, VpcIID: irs.IID{ - NameId: "nlb-tester-vpc", + NameId: "mcb-test-vpc", }, + // Type: "PUBLIC", + // Scope: "REGION", Listener: irs.ListenerInfo{ Protocol: "TCP", - Port: "8080", + Port: "22", }, VMGroup: irs.VMGroupInfo{ - Port: "80", - Protocol: "TCP", + Port: "22", + Protocol: "TCP", VMs: &[]irs.IID{ - {NameId: "tj-vm-tester"}, - //{NameId: "nlb-tester-vm-02"}, + {NameId: "vm-01"}, + {NameId: "vm-02"}, }, }, HealthChecker: irs.HealthCheckerInfo{ Protocol: "TCP", - Port: "80", + Port: "22", Interval: 10, - Threshold: 429496728, + Timeout: -1, + Threshold: 5, + // Threshold: 429496728, }, + TagList: []irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, } updateListener := irs.ListenerInfo{ Protocol: "TCP", @@ -926,17 +939,17 @@ func testNLBHandler(config Config) { Protocol: "TCP", Port: "8087", VMs: &[]irs.IID{ - {NameId: "nlb-tester-vm-01"}, - {NameId: "nlb-tester-vm-02"}, + {NameId: "mcb-test-vm"}, + {NameId: "mcb-test-vm2"}, }, } addVMs := []irs.IID{ - {NameId: "nlb-tester-vm-01"}, - {NameId: "nlb-tester-vm-02"}, + {NameId: "mcb-test-vm"}, + {NameId: "mcb-test-vm2"}, } removeVMs := []irs.IID{ - {NameId: "nlb-tester-vm-01"}, - {NameId: "nlb-tester-vm-02"}, + {NameId: "mcb-test-vm"}, + {NameId: "mcb-test-vm2"}, } updateHealthCheckerInfo := irs.HealthCheckerInfo{ @@ -1073,6 +1086,8 @@ func testDiskHandler(config Config) { IId: irs.IID{ NameId: config.Azure.Resources.Disk.IID.NameId, }, + Zone: config.Azure.Zone, + TagList: []irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, DiskSize: config.Azure.Resources.Disk.DiskSize, DiskType: config.Azure.Resources.Disk.DiskType, } @@ -1185,6 +1200,7 @@ func testMyImageHandler(config Config) { targetvm := irs.MyImageInfo{ IId: irs.IID{NameId: config.Azure.Resources.MyImage.IID.NameId}, SourceVM: irs.IID{NameId: config.Azure.Resources.MyImage.SourceVM.NameId}, + TagList: []irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, } delimageIId := irs.IID{NameId: config.Azure.Resources.MyImage.IID.NameId} Loop: @@ -1445,12 +1461,12 @@ func testClusterHandler(config Config) { testClusterHandlerListPrint() createreq := irs.ClusterInfo{ IId: irs.IID{ - NameId: "test-cluster-2", + NameId: "test-cluster-1", }, Network: irs.NetworkInfo{ - VpcIID: irs.IID{NameId: "cluster-tester-vpc"}, - SubnetIIDs: []irs.IID{{NameId: "cluster-tester-vpc-sb-01"}}, - SecurityGroupIIDs: []irs.IID{{NameId: "test-cluster-applysg"}}, + VpcIID: irs.IID{NameId: "mcb-test-vpc"}, + SubnetIIDs: []irs.IID{{NameId: "mcb-test-vpc-subnet1"}}, + SecurityGroupIIDs: []irs.IID{{NameId: "mcb-test-sg"}}, }, Version: "1.29.4", // ImageIID @@ -1459,7 +1475,7 @@ func testClusterHandler(config Config) { IId: irs.IID{NameId: "nodegroup0"}, VMSpecName: "Standard_B2s", RootDiskSize: "default", - KeyPairIID: irs.IID{NameId: "azure0916"}, + KeyPairIID: irs.IID{NameId: "mcb-test-key"}, DesiredNodeSize: 1, MaxNodeSize: 2, MinNodeSize: 1, @@ -1476,12 +1492,13 @@ func testClusterHandler(config Config) { // OnAutoScaling: true, //}, }, + TagList: []irs.KeyValue{{Key: "Environment", Value: "Production"},{Key: "Environment2", Value: "Production2"}}, } addNodeGroup := irs.NodeGroupInfo{ IId: irs.IID{NameId: "nodegroup3"}, VMSpecName: "Standard_B2s", RootDiskSize: "default", - KeyPairIID: irs.IID{NameId: "azure0916"}, + KeyPairIID: irs.IID{NameId: "mcb-test-key"}, DesiredNodeSize: 3, MaxNodeSize: 5, MinNodeSize: 2, @@ -1937,6 +1954,96 @@ 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 testTagHandler(config Config) { + resourceHandler, err := getResourceHandler("tag", config) + if err != nil { + cblogger.Error(err) + return + } + + tagHandler := resourceHandler.(irs.TagHandler) + testTagHandlerListPrint() + + tagReq := irs.KeyValue{Key: "Environment", Value: "Production"} + resType := irs.RSType("cluster") + resIID := irs.IID{NameId: "test-cluster-2", SystemId: ""} + // resIID := irs.IID{NameId: "sg01", SystemId: ""} + // resIID := irs.IID{NameId: "keypair-01", SystemId: ""} + // resIID := irs.IID{NameId: "vm-01", SystemId: ""} + + +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() ...") + if tag, err := tagHandler.AddTag(resType, resIID, tagReq); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tag) + } + cblogger.Info("Finish AddTag()") + case 2: + cblogger.Info("Start ListTag() ...") + if tags, err := tagHandler.ListTag(resType, resIID); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tags) + } + cblogger.Info("Finish ListTag()") + case 3: + cblogger.Info("Start GetTag() ...") + if tag, err := tagHandler.GetTag(resType, resIID, tagReq.Key); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tag) + } + cblogger.Info("Finish GetTag()") + case 4: + cblogger.Info("Start RemoveTag() ...") + if success, err := tagHandler.RemoveTag(resType, resIID, tagReq.Key); err != nil { + cblogger.Error(err) + } else { + spew.Dump(success) + } + cblogger.Info("Finish RemoveTag()") + case 5: + cblogger.Info("Start FindTag() ...") + keyword := "Environment" + // keyword := "createdBy" + if tagInfos, err := tagHandler.FindTag(resType, keyword); err != nil { + cblogger.Error(err) + } else { + spew.Dump(tagInfos) + } + cblogger.Info("Finish FindTag()") + case 6: + break Loop + } + } + } +} + func main() { showTestHandlerInfo() config := readConfigFile() @@ -1987,6 +2094,9 @@ Loop: 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/azure/resources/ClusterHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/ClusterHandler.go index f219403b2..0a4c05e2f 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/ClusterHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/ClusterHandler.go @@ -5,14 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" - "github.com/Azure/go-autorest/autorest/to" - 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" - "gopkg.in/yaml.v2" "io" "math" "net" @@ -24,6 +16,15 @@ import ( "strings" "sync" "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" + "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" + "github.com/Azure/go-autorest/autorest/to" + 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" + "gopkg.in/yaml.v2" ) const ( @@ -589,7 +590,9 @@ func setterClusterInfo(cluster containerservice.ManagedCluster, managedClustersC } clusterInfo.KeyValueList = keyValues } - + if cluster.Tags != nil { + clusterInfo.TagList = setTagList(cluster.Tags) + } return clusterInfo, nil } @@ -1037,6 +1040,12 @@ func createCluster(clusterReqInfo irs.ClusterInfo, virtualNetworksClient *networ AddonProfiles: addonProfiles, }, } + if clusterReqInfo.TagList != nil{ + for _, tag := range clusterReqInfo.TagList { + clusterCreateOpts.Tags[tag.Key] = to.StringPtr(tag.Value) + } + } + _, err = managedClustersClient.CreateOrUpdate(ctx, regionInfo.Region, clusterReqInfo.IId.NameId, clusterCreateOpts) if err != nil { return err diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/CommonAzureFunc.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/CommonAzureFunc.go index c988722b7..35cec354e 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/CommonAzureFunc.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/CommonAzureFunc.go @@ -3,7 +3,6 @@ package resources import ( "errors" "fmt" - irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" "math/rand" "net" "sort" @@ -12,7 +11,9 @@ import ( "sync" "time" + "github.com/Azure/go-autorest/autorest/to" cblog "github.com/cloud-barista/cb-log" + irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources" "github.com/sirupsen/logrus" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" @@ -318,3 +319,27 @@ func removeDuplicateStr(array []string) []string { return array[:prev] } + +func setTags(tagList []irs.KeyValue) map[string]*string{ + tags := make(map[string]*string) + for _, tag := range tagList { + tags[tag.Key] = to.StringPtr(tag.Value) + } + return tags +} + +func setTagList(tags map[string]*string) []irs.KeyValue{ + tagList := make([]irs.KeyValue, 0, len(tags)) + if len(tags) != 0 { + for key, value := range tags { + if value != nil { + tagList = append(tagList, irs.KeyValue{ + Key: key, + Value: *value, + }) + } + } + return tagList + } + return nil +} \ No newline at end of file diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/DiskHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/DiskHandler.go index 79879fe8b..c2862527b 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/DiskHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/DiskHandler.go @@ -4,13 +4,14 @@ import ( "context" "errors" "fmt" + "strconv" + "strings" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" "github.com/Azure/go-autorest/autorest/to" 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" - "strconv" - "strings" ) type AzureDiskHandler struct { @@ -41,6 +42,9 @@ func (diskHandler *AzureDiskHandler) CreateDisk(DiskReqInfo irs.DiskInfo) (diskI diskSku := compute.DiskSku{ Name: diskType, } + // Create Tag + tags := setTags(DiskReqInfo.TagList) + creationData := compute.CreationData{ CreateOption: compute.DiskCreateOptionEmpty, } @@ -64,6 +68,7 @@ func (diskHandler *AzureDiskHandler) CreateDisk(DiskReqInfo irs.DiskInfo) (diskI DiskProperties: &diskProperties, Sku: &diskSku, Location: to.StringPtr(diskHandler.Region.Region), + Tags: tags, } // Setting zone if available if diskHandler.Region.Zone != "" { @@ -431,6 +436,9 @@ func setterDiskInfo(disk compute.Disk) (*irs.DiskInfo, error) { diskStatus.Zone = (*disk.Zones)[0] } } + if disk.Tags != nil { + diskStatus.TagList = setTagList(disk.Tags) + } // TODO KeyValueList return &diskStatus, nil } diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/KeyPairHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/KeyPairHandler.go index 417a0de3c..e5e0e8788 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/KeyPairHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/KeyPairHandler.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/Azure/go-autorest/autorest/to" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" @@ -36,6 +37,11 @@ func (keyPairHandler *AzureKeyPairHandler) setterKey(key compute.SSHPublicKeyRes PublicKey: *key.PublicKey, PrivateKey: privateKey, } + + if key.Tags != nil { + keypairInfo.TagList = setTagList(key.Tags) + } + return &keypairInfo, nil } @@ -65,6 +71,9 @@ func (keyPairHandler *AzureKeyPairHandler) CreateKey(keyPairReqInfo irs.KeyPairR LoggingError(hiscallInfo, createErr) return irs.KeyPairInfo{}, createErr } + // Create Tag + tags := setTags(keyPairReqInfo.TagList) + // 2. Create KeyPairData privateKey, publicKey, err := keypair.GenKeyPair() @@ -74,6 +83,7 @@ func (keyPairHandler *AzureKeyPairHandler) CreateKey(keyPairReqInfo irs.KeyPairR SSHPublicKeyResourceProperties: &compute.SSHPublicKeyResourceProperties{ PublicKey: to.StringPtr(string(publicKey)), }, + Tags: tags, } start := call.Start() diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/MyImageHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/MyImageHandler.go index 8693b98b7..3eb720e59 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/MyImageHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/MyImageHandler.go @@ -4,15 +4,16 @@ import ( "context" "errors" "fmt" + "reflect" + "strconv" + "strings" + "time" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" "github.com/Azure/go-autorest/autorest/to" 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" - "reflect" - "strconv" - "strings" - "time" ) type AzureMyImageHandler struct { @@ -97,6 +98,11 @@ func (myImageHandler *AzureMyImageHandler) SnapshotVM(snapshotReqInfo irs.MyImag "createdAt": to.StringPtr(strconv.FormatInt(time.Now().Unix(), 10)), }, } + if snapshotReqInfo.TagList != nil{ + for _, tag := range snapshotReqInfo.TagList { + imagecreatOpt.Tags[tag.Key] = to.StringPtr(tag.Value) + } + } _, err = myImageHandler.VMClient.Generalize(myImageHandler.Ctx, myImageHandler.Region.Region, convertedVMIId.NameId) if err != nil { @@ -258,6 +264,10 @@ func setterMyImageInfo(myImage compute.Image, credentialInfo idrv.CredentialInfo myImageInfo.CreatedTime = time.Unix(timeInt64, 0) } } + if myImage.Tags != nil { + myImageInfo.TagList = setTagList(myImage.Tags) + } + return myImageInfo, nil } diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/NLBHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/NLBHandler.go index 6b4c220e4..d0389aeb6 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/NLBHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/NLBHandler.go @@ -4,6 +4,10 @@ import ( "context" "errors" "fmt" + "strconv" + "strings" + "time" + "github.com/Azure/azure-sdk-for-go/profiles/2020-09-01/monitor/mgmt/insights" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" @@ -11,9 +15,6 @@ import ( 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" - "strconv" - "strings" - "time" ) type AzureNLBHandler struct { @@ -159,6 +160,13 @@ func (nlbHandler *AzureNLBHandler) CreateNLB(nlbReqInfo irs.NLBInfo) (createNLB "createdAt": to.StringPtr(nowTime), }, } + + if nlbReqInfo.TagList != nil{ + for _, tag := range nlbReqInfo.TagList { + options.Tags[tag.Key] = to.StringPtr(tag.Value) + } + } + future, err := nlbHandler.NLBClient.CreateOrUpdate(nlbHandler.Ctx, nlbHandler.Region.Region, nlbReqInfo.IId.NameId, options) if err != nil { createError = errors.New(fmt.Sprintf("Failed to Create NLB. err = %s", err.Error())) @@ -1064,6 +1072,11 @@ func (nlbHandler *AzureNLBHandler) setterNLB(nlb network.LoadBalancer) (*irs.NLB } else { nlbInfo.Scope = string(NLBGlobalType) } + + if nlb.Tags != nil { + nlbInfo.TagList = setTagList(nlb.Tags) + } + return &nlbInfo, nil } func (nlbHandler *AzureNLBHandler) getVPCIIDByLoadBalancerBackendAddresses(address []network.LoadBalancerBackendAddress) (irs.IID, error) { diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/SecurityHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/SecurityHandler.go index 0ff28aaee..191fee0eb 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/SecurityHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/SecurityHandler.go @@ -85,6 +85,11 @@ func (securityHandler *AzureSecurityHandler) setterSec(securityGroup network.Sec }) } } + + if securityGroup.Tags != nil { + security.TagList = setTagList(securityGroup.Tags) + } + security.KeyValueList = keyValues security.SecurityRules = &securityRuleArr @@ -103,7 +108,8 @@ func (securityHandler *AzureSecurityHandler) CreateSecurity(securityReqInfo irs. LoggingError(hiscallInfo, createErr) return irs.SecurityInfo{}, createErr } - + // Create Tag + tags := setTags(securityReqInfo.TagList) sgRuleList, err := convertRuleInfoListCBToAZ(*securityReqInfo.SecurityRules) if err != nil { @@ -127,6 +133,7 @@ func (securityHandler *AzureSecurityHandler) CreateSecurity(securityReqInfo irs. SecurityRules: sgRuleList, }, Location: &securityHandler.Region.Region, + Tags: tags, } start := call.Start() diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/TagHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/TagHandler.go new file mode 100644 index 000000000..021e8f74f --- /dev/null +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/TagHandler.go @@ -0,0 +1,294 @@ +package resources + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + + "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2020-10-01/resources" + "github.com/Azure/go-autorest/autorest/to" + + 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 AzureTagHandler struct { + CredentialInfo idrv.CredentialInfo + Region idrv.RegionInfo + Ctx context.Context + Client *resources.TagsClient +} +type Resource struct { + Id string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Tags map[string]string `json:"tags"` +} + +type Response struct { + Value []Resource `json:"value"` +} + +// find all resource by subscription ID +func GetResourceInfo(credentailInfo idrv.CredentialInfo, url string) (*Response, error){ + token, err := getToken(credentailInfo.TenantId, credentailInfo.ClientId, credentailInfo.ClientSecret) + if err != nil { + return nil, err + } + URL := url + + + var bearer = "Bearer " + token + + ctx := context.Background() + client := &http.Client{} + req, err := http.NewRequest(http.MethodGet, URL, nil) + if err != nil { + return nil, err + } + + req.Header.Add("Authorization", bearer) + req = req.WithContext(ctx) + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer func() { + _ = resp.Body.Close() + }() + + var response Response + err = json.NewDecoder(resp.Body).Decode(&response) + if err != nil { + return nil, err + } + return &response, nil +} +// find SystemId by NameId +func FindIdByName(credentailInfo idrv.CredentialInfo, resIID irs.IID) (string, error) { + if resIID.SystemId != "" { + return resIID.SystemId, nil + } + + url := fmt.Sprintf("https://management.azure.com/subscriptions/%s/resources?api-version=2021-04-01", credentailInfo.SubscriptionId) + response, err := GetResourceInfo(credentailInfo, url) + if err != nil { + return "", fmt.Errorf("failed to fetch resource info: %v", err) + } + + for _, resource := range response.Value { + if strings.Contains(resource.Name, resIID.NameId) { + return resource.Id, nil + } + } + + return "", fmt.Errorf("resource with name containing '%s' not found", resIID.NameId) +} + +func findRSType(azureType string) (irs.RSType, error) { + switch azureType { + case "Microsoft.Compute/virtualMachines": + return irs.VM, nil + case "Microsoft.Compute/disks": + return irs.DISK, nil + case "Microsoft.Network/virtualNetworks": + return irs.VPC, nil + case "Microsoft.Compute/snapshots": + return irs.MYIMAGE, nil + case "Microsoft.Network/loadBalancers": + return irs.NLB, nil + case "Microsoft.Network/networkSecurityGroups": + return irs.SG, nil + case "Microsoft.Compute/sshPublicKeys": + return irs.KEY, nil + case "Microsoft.ContainerService/ManagedClusters": + return irs.CLUSTER, nil + default: + return "", errors.New(azureType + " is not supported Resource!!") + } +} +// AddTag adds a tag to the specified resource +func (tagHandler *AzureTagHandler) AddTag(resType irs.RSType, resIID irs.IID, tag irs.KeyValue) (irs.KeyValue, error) { + resourceID, err := FindIdByName(tagHandler.CredentialInfo, resIID) + if err != nil { + fmt.Printf("Error: %v\n", err) + } + resIID.SystemId = resourceID + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, string(resType), "AddTag()") + // Fetch existing tags + tagsResource, err := tagHandler.Client.GetAtScope(tagHandler.Ctx, resIID.SystemId) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to get existing tags for resource ID %s: %s", resIID.SystemId, err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyValue{}, createErr + } + + // Add new tag + if tagsResource.Properties.Tags == nil { + tagsResource.Properties.Tags = make(map[string]*string) + } + tagsResource.Properties.Tags[tag.Key] = to.StringPtr(tag.Value) + + // Update tags + start := call.Start() + _, err = tagHandler.Client.CreateOrUpdateAtScope(tagHandler.Ctx, resIID.SystemId, tagsResource) + if err != nil { + createErr := errors.New(fmt.Sprintf("Failed to add tag to resource ID %s: %s", resIID.SystemId, err.Error())) + cblogger.Error(createErr.Error()) + LoggingError(hiscallInfo, createErr) + return irs.KeyValue{}, createErr + } + LoggingInfo(hiscallInfo, start) + + return tag, nil +} + +func (tagHandler *AzureTagHandler) ListTag(resType irs.RSType, resIID irs.IID) ([]irs.KeyValue, error) { + resourceID, err := FindIdByName(tagHandler.CredentialInfo, resIID) + if err != nil { + fmt.Printf("Error: %v\n", err) + } + resIID.SystemId = resourceID + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, string(resType), "ListTag()") + + start := call.Start() + tagsResource, err := tagHandler.Client.GetAtScope(tagHandler.Ctx, resIID.SystemId) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to list tags for resource ID %s: %s", resIID.SystemId, err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return nil, getErr + } + LoggingInfo(hiscallInfo, start) + + var tagList []irs.KeyValue + for key, value := range tagsResource.Properties.Tags { + tagList = append(tagList, irs.KeyValue{Key: key, Value: *value}) + } + + return tagList, nil +} + +// GetTag gets a specific tag of the specified resource +func (tagHandler *AzureTagHandler) GetTag(resType irs.RSType, resIID irs.IID, key string) (irs.KeyValue, error) { + resourceID, err := FindIdByName(tagHandler.CredentialInfo, resIID) + if err != nil { + fmt.Printf("Error: %v\n", err) + } + resIID.SystemId = resourceID + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, string(resType), "GetTag()") + start := call.Start() + tagsResource, err := tagHandler.Client.GetAtScope(tagHandler.Ctx, resIID.SystemId) + if err != nil { + getErr := errors.New(fmt.Sprintf("Failed to get tag for resource ID %s: %s", resIID.SystemId, err.Error())) + cblogger.Error(getErr.Error()) + LoggingError(hiscallInfo, getErr) + return irs.KeyValue{}, getErr + } + LoggingInfo(hiscallInfo, start) + + if value, exists := tagsResource.Properties.Tags[key]; exists { + return irs.KeyValue{Key: key, Value: *value}, nil + } + + return irs.KeyValue{}, errors.New("tag not found") +} + +// RemoveTag removes a specific tag from the specified resource +func (tagHandler *AzureTagHandler) RemoveTag(resType irs.RSType, resIID irs.IID, key string) (bool, error) { + resourceID, err := FindIdByName(tagHandler.CredentialInfo, resIID) + if err != nil { + fmt.Printf("Error: %v\n", err) + } + resIID.SystemId = resourceID + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, string(resType), "RemoveTag()") + // Fetch existing tags + tagsResource, err := tagHandler.Client.GetAtScope(tagHandler.Ctx, resIID.SystemId) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to get existing tags for resource ID %s: %s", resIID.SystemId, err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + // Remove the tag + if _, exists := tagsResource.Properties.Tags[key]; !exists { + return false, errors.New("tag not found") + } + delete(tagsResource.Properties.Tags, key) + + // Update tags + start := call.Start() + _, err = tagHandler.Client.CreateOrUpdateAtScope(tagHandler.Ctx, resIID.SystemId, tagsResource) + if err != nil { + delErr := errors.New(fmt.Sprintf("Failed to remove tag from resource ID %s: %s", resIID.SystemId, err.Error())) + cblogger.Error(delErr.Error()) + LoggingError(hiscallInfo, delErr) + return false, delErr + } + LoggingInfo(hiscallInfo, start) + + return true, nil +} + +//FindTag finds tags by key or value +func (tagHandler *AzureTagHandler) FindTag(resType irs.RSType, keyword string) ([]*irs.TagInfo, error) { + urlByProvider:="https://management.azure.com/subscriptions/%s/providers/%s?api-version=2021-04-01" + var url string + switch resType { + case irs.ALL: + url = fmt.Sprintf("https://management.azure.com/subscriptions/%s/resources?api-version=2021-04-01",tagHandler.CredentialInfo.SubscriptionId) + case irs.VM: + url = fmt.Sprintf(urlByProvider,tagHandler.CredentialInfo.SubscriptionId,"Microsoft.Compute/virtualMachines") + case irs.DISK: + url = fmt.Sprintf(urlByProvider,tagHandler.CredentialInfo.SubscriptionId,"Microsoft.Compute/disks") + case irs.VPC: + url = fmt.Sprintf(urlByProvider,tagHandler.CredentialInfo.SubscriptionId,"Microsoft.Network/virtualNetworks") + case irs.MYIMAGE: + url = fmt.Sprintf(urlByProvider,tagHandler.CredentialInfo.SubscriptionId,"Microsoft.Compute/snapshots") + case irs.NLB: + url = fmt.Sprintf(urlByProvider,tagHandler.CredentialInfo.SubscriptionId,"Microsoft.Network/loadBalancers") + case irs.SG: + url = fmt.Sprintf(urlByProvider,tagHandler.CredentialInfo.SubscriptionId,"Microsoft.Network/networkSecurityGroups") + case irs.KEY: + url = fmt.Sprintf(urlByProvider,tagHandler.CredentialInfo.SubscriptionId,"Microsoft.Compute/sshPublicKeys") + case irs.CLUSTER: + url = fmt.Sprintf("https://management.azure.com/subscriptions/%s/providers/%s?api-version=2024-05-01",tagHandler.CredentialInfo.SubscriptionId,"Microsoft.ContainerService/managedClusters") + default: + fmt.Println(errors.New(string(resType) + " is not supported Resource!!")) + } + hiscallInfo := GetCallLogScheme(tagHandler.Region, call.TAG, string(resType), "FindTag()") + start := call.Start() + response, _:= GetResourceInfo(tagHandler.CredentialInfo, url) + LoggingInfo(hiscallInfo, start) + + var foundTags []*irs.TagInfo + for _, resource := range response.Value { + var tagList []irs.KeyValue + for key, value := range resource.Tags { + if strings.Contains(key, keyword) || strings.Contains(value, keyword) { + tagList = append(tagList, irs.KeyValue{Key: key, Value: value}) + } + } + + if len(tagList) > 0 { + resType, err := findRSType(resource.Type) + if err != nil || resType == "" { + continue // resType이 유효하지 않거나 지원되지 않는 경우 pass + } + tagInfo := &irs.TagInfo{ + ResType: resType, + ResIId: irs.IID{NameId: resource.Name, SystemId: resource.Id}, + TagList: tagList, + } + foundTags = append(foundTags, tagInfo) + } + } + + return foundTags, nil +} \ No newline at end of file diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/VMHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/VMHandler.go index c0b69e5b6..23aa3985b 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/VMHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/VMHandler.go @@ -14,7 +14,6 @@ import ( "context" "errors" "fmt" - call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" "math/rand" "reflect" "regexp" @@ -22,6 +21,8 @@ import ( "strings" "time" + call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-03-01/compute" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" "github.com/Azure/go-autorest/autorest/to" @@ -353,6 +354,12 @@ func (vmHandler *AzureVMHandler) StartVM(vmReqInfo irs.VMReqInfo) (irs.VMInfo, e "createdBy": to.StringPtr(vmReqInfo.IId.NameId), } } + // tags := setTags(vmReqInfo.TagList) + if vmReqInfo.TagList != nil{ + for _, tag := range vmReqInfo.TagList { + vmOpts.Tags[tag.Key] = to.StringPtr(tag.Value) + } + } // 4. CreateVM start := call.Start() @@ -1109,6 +1116,10 @@ func (vmHandler *AzureVMHandler) mappingServerInfo(server compute.VirtualMachine vmInfo.AccessPoint = fmt.Sprintf("%s:%s", vmInfo.PublicIP, "22") } } + if server.Tags != nil { + vmInfo.TagList = setTagList(server.Tags) + } + return vmInfo } diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/VPCHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/VPCHandler.go index 8bb61904a..ed54ff514 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/VPCHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/VPCHandler.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" "github.com/Azure/go-autorest/autorest/to" @@ -32,13 +33,15 @@ func (vpcHandler *AzureVPCHandler) setterVPC(network network.VirtualNetwork) *ir IPv4_CIDR: (*network.AddressSpace.AddressPrefixes)[0], KeyValueList: []irs.KeyValue{{Key: "ResourceGroup", Value: vpcHandler.Region.Region}}, } - subnetArr := make([]irs.SubnetInfo, len(*network.Subnets)) for i, subnet := range *network.Subnets { subnetArr[i] = *vpcHandler.setterSubnet(subnet) } vpcInfo.SubnetInfoList = subnetArr + if network.Tags != nil { + vpcInfo.TagList = setTagList(network.Tags) + } return vpcInfo } @@ -66,6 +69,8 @@ func (vpcHandler *AzureVPCHandler) CreateVPC(vpcReqInfo irs.VPCReqInfo) (irs.VPC LoggingError(hiscallInfo, createErr) return irs.VPCInfo{}, createErr } + // Create Tag + tags := setTags(vpcReqInfo.TagList) // Create VPC createOpts := network.VirtualNetwork{ @@ -76,6 +81,7 @@ func (vpcHandler *AzureVPCHandler) CreateVPC(vpcReqInfo irs.VPCReqInfo) (irs.VPC }, }, Location: &vpcHandler.Region.Region, + Tags: tags, } start := call.Start() @@ -161,7 +167,6 @@ func (vpcHandler *AzureVPCHandler) GetVPC(vpcIID irs.IID) (irs.VPCInfo, error) { return irs.VPCInfo{}, getErr } LoggingInfo(hiscallInfo, start) - vpcInfo := vpcHandler.setterVPC(*vpc) return *vpcInfo, nil }