Skip to content

Commit

Permalink
add get resource creator account info code
Browse files Browse the repository at this point in the history
  • Loading branch information
bruceybian committed Feb 4, 2024
1 parent 2bca462 commit 853f6b1
Show file tree
Hide file tree
Showing 32 changed files with 163 additions and 107 deletions.
170 changes: 114 additions & 56 deletions tencentcloud/common/cloud_common.go
Original file line number Diff line number Diff line change
@@ -1,77 +1,88 @@
package common

import (
"encoding/json"
cls "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cls/v20201016"
"log"
"strconv"
"strings"
"time"

billing "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing/v20180709"
cam "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam/v20190116"
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/connectivity"
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper"
)

const (
BillingStartMonth = "2018-05"
// DefaultSearchLogStartTimestamp sync logs start time 2023-11-07 16:41:00
DefaultSearchLogStartTimestamp = 1699346460000

DefaultTopicId = "aef50d54-b17d-4782-8618-a7873203ec29"
)

// CreatorAccountInfo 创建者账号信息
type CreatorAccountInfo struct {
UserId string // 用户ID
UserName string // 用户名
// ResourceAccountInfo 资源账户信息
type ResourceAccountInfo struct {
ResourceType string // 资源类型
ResourceName string // 资源名称
AccountId string // 主账号ID
PrincipalId string // 用户ID
UserName string // 用户名
}

// CloudDescribeBillResourceSummary get billing resource summary data
func CloudDescribeBillResourceSummary(client *connectivity.TencentCloudClient, resources []*ResourceInstance) map[string]*CreatorAccountInfo {
resourceIdToSubAccountInfoMap := make(map[string]*CreatorAccountInfo)
// GetResourceCreatorAccountInfo get resource creator user info
func GetResourceCreatorAccountInfo(client *connectivity.TencentCloudClient, resourceCreateAction string, resources []*ResourceInstance) map[string]*ResourceAccountInfo {
resourceIdToSubAccountInfoMap := make(map[string]*ResourceAccountInfo)
if resourceCreateAction == "" {
return resourceIdToSubAccountInfoMap
}

request := billing.NewDescribeBillResourceSummaryRequest()
request.Offset = helper.Uint64(0)
request.Limit = helper.Uint64(1)
request.NeedRecordNum = helper.Int64(1)
request := cls.NewSearchLogRequest()
request.From = helper.IntInt64(DefaultSearchLogStartTimestamp)
request.To = helper.Int64(CurrentTimeMillisecond())
request.TopicId = helper.String(DefaultTopicId)
request.Query = helper.String(resourceCreateAction)

currentMonth := GetCurrentMonth()
for _, r := range resources {
if r.Id == "" {
continue
response, err := client.UseClsClient().SearchLog(request)
if err != nil {
log.Printf("[CRITAL] search resource[%v] log data error: %v", r.Id, err.Error())
return resourceIdToSubAccountInfoMap
}
if response == nil || response.Response == nil {
log.Printf("[CRITAL] search resource[%v] log data response is nil", r.Id)
return resourceIdToSubAccountInfoMap
}
if len(response.Response.Results) == 0 {
log.Printf("[CRITAL] search resource[%v] log data response results is empty", r.Id)
return resourceIdToSubAccountInfoMap
}

request.ResourceId = helper.String(r.Id)
prevMonth := currentMonth
for {
if prevMonth == BillingStartMonth {
break
result := response.Response.Results[0]
if result != nil {
var jsonData string
if len(*result.LogJson) > 2 {
jsonData = *result.LogJson
} else if len(*result.RawLog) > 2 {
jsonData = *result.RawLog
} else {
continue
}

request.Month = helper.String(prevMonth)
response, err := client.UseBillingClient().DescribeBillResourceSummary(request)
if err != nil {
log.Printf("[CRITAL] get billing resource[%v] summary data error: %v", r.Id, err.Error())
break
}
if response == nil || response.Response == nil {
log.Printf("[CRITAL] get billing resource[%v] summary data response is nil", r.Id)
break
}
if *response.Response.Total == 1 {
billResourceSummary := response.Response.ResourceSummarySet[0]
userName := CloudDescribeSubAccounts(client, *billResourceSummary.OperateUin)

resourceIdToSubAccountInfoMap[r.Id] = &CreatorAccountInfo{
UserId: *billResourceSummary.OperateUin,
UserName: userName,
}
break
resourceAccountInfo := ParseLogJsonData(jsonData)
if resourceAccountInfo.PrincipalId == resourceAccountInfo.UserName &&
resourceAccountInfo.PrincipalId != resourceAccountInfo.AccountId {
userName := GetSubAccountUserName(client, resourceAccountInfo.PrincipalId)
resourceAccountInfo.UserName = userName
}

prevMonth = PrevMonth(prevMonth)
resourceIdToSubAccountInfoMap[r.Id] = resourceAccountInfo
}
}

return resourceIdToSubAccountInfoMap
}

// CloudDescribeSubAccounts get sub account data
func CloudDescribeSubAccounts(client *connectivity.TencentCloudClient, uin string) string {
// GetSubAccountUserName get sub account user name
func GetSubAccountUserName(client *connectivity.TencentCloudClient, uin string) string {
uinNum, err := strconv.ParseUint(uin, 10, 64)
if err != nil {
log.Printf("[CRITAL] parse uin[%v] to uint64 type error: %v", uin, err.Error())
Expand All @@ -97,19 +108,66 @@ func CloudDescribeSubAccounts(client *connectivity.TencentCloudClient, uin strin
return *name
}

// GetCurrentMonth get current month
func GetCurrentMonth() string {
currentTime := time.Now()
formattedMonth := currentTime.Format("2006-01")
return formattedMonth
// CurrentTimeMillisecond get the current millisecond timestamp
func CurrentTimeMillisecond() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}

func ParseLogJsonData(jsonData string) *ResourceAccountInfo {
if jsonData == "" {
return nil
}

var data map[string]interface{}
err := json.Unmarshal([]byte(jsonData), &data)
if err != nil {
log.Printf("[CRITAL] parse log json data[%v] error: %v", jsonData, err.Error())
return nil
}

resourceType := ""
if v, ok := data["resourceType"]; ok {
resourceType = v.(string)
}
resourceName := ""
if v, ok := data["resourceName"]; ok {
resourceName = v.(string)
if resourceName != "" {
resourceName = strings.Split(resourceName, "/")[0]
}
}
accountId, principalId, userName := parseUserIdentityFields(data)

return &ResourceAccountInfo{
ResourceType: resourceType,
ResourceName: resourceName,
AccountId: accountId,
PrincipalId: principalId,
UserName: userName,
}
}

// PrevMonth get prev month
func PrevMonth(date string) string {
t, _ := time.Parse("2006-01", date)
t = t.AddDate(0, -1, 0)
if t.Before(time.Date(2018, 5, 1, 0, 0, 0, 0, time.UTC)) {
return BillingStartMonth
func parseUserIdentityFields(data map[string]interface{}) (accountId, principalId, userName string) {
if v, ok := data["userIdentity.accountId"]; ok {
accountId = v.(string)
}
if v, ok := data["userIdentity.principalId"]; ok {
principalId = v.(string)
}
if v, ok := data["userIdentity.userName"]; ok {
userName = v.(string)
}
if v, ok := data["userIdentity"]; ok {
switch v := v.(type) {
case string:
var userIdentity map[string]string
err := json.Unmarshal([]byte(v), &userIdentity)
if err == nil {
accountId = userIdentity["accountId"]
principalId = userIdentity["principalId"]
userName = userIdentity["userName"]
}
}
}
return t.Format("2006-01")
return
}
2 changes: 1 addition & 1 deletion tencentcloud/common/file_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const (
)

var ResourceScanHeader = []string{"资源类型", "资源名称", "实例ID", "实例名称", "分类", "创建时长(天)", "创建者用户ID", "创建者用户名"}
var NonKeepResourceScanHeader = []string{"ResourceType", "ResourceName", "InstanceId", "InstanceName", "UserId", "UserName"}
var NonKeepResourceScanHeader = []string{"ResourceType", "ResourceName", "InstanceId", "InstanceName", "PrincipalId", "UserName"}

// WriteCsvFileData write data to csv file
func WriteCsvFileData(dirPath string, header []string, data [][]string) error {
Expand Down
40 changes: 19 additions & 21 deletions tencentcloud/common/resource_scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
const (
KeepResource = "keep"
NonKeepResource = "non-keep"

RemarkResourceFree = "资源免费"
)

// TimeFormats add all possible time formats
Expand All @@ -31,17 +29,17 @@ type ResourceInstance struct {
DefaultKeep bool
}

func ProcessScanCloudResources(client *connectivity.TencentCloudClient, resources, nonKeepResources []*ResourceInstance, resourceType, resourceName string) {
ProcessResources(client, resources, resourceType, resourceName)
func ProcessScanCloudResources(client *connectivity.TencentCloudClient, resources, nonKeepResources []*ResourceInstance, resourceCreateAction string) {
ProcessResources(client, resources, resourceCreateAction)

ProcessNonKeepResources(client, nonKeepResources, resourceType, resourceName)
ProcessNonKeepResources(client, nonKeepResources, resourceCreateAction)
}

// ProcessResources Process all scanned cloud resources
func ProcessResources(client *connectivity.TencentCloudClient, resources []*ResourceInstance, resourceType, resourceName string) {
data := make([][]string, len(resources))
resourceIdToSubAccountInfoMap := CloudDescribeBillResourceSummary(client, resources)
func ProcessResources(client *connectivity.TencentCloudClient, resources []*ResourceInstance, resourceCreateAction string) {
resourceIdToSubAccountInfoMap := GetResourceCreatorAccountInfo(client, resourceCreateAction, resources)

data := make([][]string, len(resources))
for i, r := range resources {
isResourceKeep := CheckResourceNameKeep(r.Name)
// some resources default to keep
Expand All @@ -54,13 +52,13 @@ func ProcessResources(client *connectivity.TencentCloudClient, resources []*Reso
log.Printf("[CRITAL] compute resource creation duration error: %v", err.Error())
}

var userId, userName string
var resourceType, resourceName, principalId, userName string
creatorAccountInfo := resourceIdToSubAccountInfoMap[r.Id]
if creatorAccountInfo != nil {
userId = creatorAccountInfo.UserId
resourceType = creatorAccountInfo.ResourceType
resourceName = creatorAccountInfo.ResourceName
principalId = creatorAccountInfo.PrincipalId
userName = creatorAccountInfo.UserName
} else {
userName = RemarkResourceFree
}

data[i] = []string{
Expand All @@ -70,7 +68,7 @@ func ProcessResources(client *connectivity.TencentCloudClient, resources []*Reso
r.Name,
isResourceKeep,
creationDuration,
userId,
principalId,
userName,
}
}
Expand All @@ -81,26 +79,26 @@ func ProcessResources(client *connectivity.TencentCloudClient, resources []*Reso
}

// ProcessNonKeepResources Processing scanned non-keep cloud resources
func ProcessNonKeepResources(client *connectivity.TencentCloudClient, nonKeepResources []*ResourceInstance, resourceType, resourceName string) {
data := make([][]string, len(nonKeepResources))
resourceIdToSubAccountInfoMap := CloudDescribeBillResourceSummary(client, nonKeepResources)
func ProcessNonKeepResources(client *connectivity.TencentCloudClient, nonKeepResources []*ResourceInstance, resourceCreateAction string) {
resourceIdToSubAccountInfoMap := GetResourceCreatorAccountInfo(client, resourceCreateAction, nonKeepResources)

data := make([][]string, len(nonKeepResources))
for i, r := range nonKeepResources {
var userId, userName string
var resourceType, resourceName, principalId, userName string
creatorAccountInfo := resourceIdToSubAccountInfoMap[r.Id]
if creatorAccountInfo != nil {
userId = creatorAccountInfo.UserId
resourceType = creatorAccountInfo.ResourceType
resourceName = creatorAccountInfo.ResourceName
principalId = creatorAccountInfo.PrincipalId
userName = creatorAccountInfo.UserName
} else {
userName = RemarkResourceFree
}

data[i] = []string{
resourceType,
resourceName,
r.Id,
r.Name,
userId,
principalId,
userName,
}
}
Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/as/resource_tc_as_attachment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func testSweepAsAttachment(r string) error {
CreatTime: *v.CreatedTime,
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "as", "attachment")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

for _, v := range scalingGroups {
scalingGroupId := *v.AutoScalingGroupId
Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/cam/resource_tc_cam_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func init() {
CreatTime: *v.CreateTime,
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "cam", "group")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

for _, v := range groups {
name := *v.GroupName
Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/cbs/resource_tc_cbs_storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func init() {
CreatTime: *v.CreateTime,
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "cbs", "storage")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

for i := range disks {
disk := disks[i]
Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/ccn/resource_tc_ccn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func testSweepCcnInstance(region string) error {
CreatTime: v.CreateTime(),
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "ccn", "")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

for _, v := range instances {
instanceId := v.CcnId()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func testSweepMySQLInstance(region string) error {
CreatTime: *v.CreateTime,
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "msql", "instance")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

for _, v := range items {
id := *v.InstanceId
Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/clb/resource_tc_clb_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func testSweepClbInstance(region string) error {
CreatTime: *v.CreateTime,
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "clb", "instance")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

if len(res) > 0 {
for _, v := range res {
Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/cls/resource_tc_cls_topic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func testSweepClsTopic(region string) error {
CreatTime: *v.CreateTime,
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "cls", "topic")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

for _, v := range instances {
instanceId := v.TopicId
Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/cos/resource_tc_cos_bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func testSweepCosBuckets(region string) error {
CreatTime: v.CreationDate.Format("2006-01-02 15:04:05"),
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "cos", "bucket")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "")

//prefix := regexp.MustCompile("^(tf|test)-")

Expand Down
2 changes: 1 addition & 1 deletion tencentcloud/services/cvm/resource_tc_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func testSweepCvmInstance(region string) error {
CreatTime: *v.CreatedTime,
})
}
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "cvm", "instance")
tccommon.ProcessScanCloudResources(client, resources, nonKeepResources, "RunInstances")

for _, v := range instances {
instanceId := *v.InstanceId
Expand Down
Loading

0 comments on commit 853f6b1

Please sign in to comment.