-
Notifications
You must be signed in to change notification settings - Fork 136
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
54 changed files
with
9,080 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:enhancement | ||
resource/tencentcloud_mysql_instance: Optimize the availability zone problem when modifying the configuration after active/standby switchover. | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
```release-note:enhancement | ||
resource/tencentcloud_instance: fix private ip release problem | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:enhancement | ||
resource/tencentcloud_clb_attachments: support param `eni_ip` | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package common | ||
|
||
import ( | ||
"encoding/json" | ||
"log" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
cls "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cls/v20201016" | ||
|
||
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 ( | ||
// DefaultSearchLogStartTimestamp sync logs start time 2023-11-07 16:41:00 | ||
DefaultSearchLogStartTimestamp = 1699346460000 | ||
|
||
DefaultTopicId = "aef50d54-b17d-4782-8618-a7873203ec29" | ||
|
||
QueryGrammarRule = " AND " | ||
) | ||
|
||
// ResourceAccountInfo 资源账户信息 | ||
type ResourceAccountInfo struct { | ||
ResourceType string // 资源类型 | ||
ResourceName string // 资源名称 | ||
AccountId string // 主账号ID | ||
PrincipalId string // 用户ID | ||
UserName string // 用户名 | ||
} | ||
|
||
// 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 := cls.NewSearchLogRequest() | ||
request.From = helper.IntInt64(DefaultSearchLogStartTimestamp) | ||
request.To = helper.Int64(CurrentTimeMillisecond()) | ||
request.TopicId = helper.String(DefaultTopicId) | ||
|
||
for _, r := range resources { | ||
query := resourceCreateAction + QueryGrammarRule | ||
if r.Id != "" { | ||
query = query + r.Id | ||
} else if r.Name != "" { | ||
query = query + r.Name | ||
} else { | ||
continue | ||
} | ||
request.Query = helper.String(query) | ||
|
||
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 | ||
} | ||
|
||
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 | ||
} | ||
|
||
resourceAccountInfo := ParseLogJsonData(jsonData) | ||
if resourceAccountInfo.PrincipalId == resourceAccountInfo.UserName && | ||
resourceAccountInfo.PrincipalId != resourceAccountInfo.AccountId { | ||
userName := GetSubAccountUserName(client, resourceAccountInfo.PrincipalId) | ||
resourceAccountInfo.UserName = userName | ||
} | ||
resourceIdToSubAccountInfoMap[r.Id] = resourceAccountInfo | ||
} | ||
} | ||
|
||
return resourceIdToSubAccountInfoMap | ||
} | ||
|
||
// 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()) | ||
return "" | ||
} | ||
|
||
request := cam.NewDescribeSubAccountsRequest() | ||
|
||
uinArray := []*uint64{helper.Uint64(uinNum)} | ||
request.FilterSubAccountUin = uinArray | ||
|
||
response, err := client.UseCamClient().DescribeSubAccounts(request) | ||
if err != nil { | ||
log.Printf("[CRITAL] get sub account[%v] data error: %v", uin, err.Error()) | ||
return "" | ||
} | ||
if response == nil || response.Response == nil { | ||
log.Printf("[CRITAL] get sub account[%v] data response is nil", uin) | ||
return "" | ||
} | ||
|
||
name := response.Response.SubAccounts[0].Name | ||
return *name | ||
} | ||
|
||
// 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, | ||
} | ||
} | ||
|
||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package common | ||
|
||
import ( | ||
"encoding/csv" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"time" | ||
) | ||
|
||
const ( | ||
SweeperResourceScanDir = "../../../tmp/resource_scan/" | ||
SweeperNonKeepResourceScanDir = "../../../tmp/non_keep_resource_scan/" | ||
) | ||
|
||
var ResourceScanHeader = []string{"资源类型", "资源名称", "实例ID", "实例名称", "分类", "创建时长(天)", "创建者用户ID", "创建者用户名"} | ||
var NonKeepResourceScanHeader = []string{"ResourceType", "ResourceName", "InstanceId", "InstanceName", "PrincipalId", "UserName"} | ||
|
||
// WriteCsvFileData write data to csv file | ||
func WriteCsvFileData(dirPath string, header []string, data [][]string) error { | ||
log.Printf("[INFO] write csv file data[%v] to path[%v] start", len(data), dirPath) | ||
|
||
count := 0 | ||
defer func() { | ||
log.Printf("[INFO] write csv file data to path[%v] success count[%v]", dirPath, count) | ||
}() | ||
|
||
if len(data) == 0 { | ||
return nil | ||
} | ||
|
||
err := os.MkdirAll(dirPath, 0755) | ||
if err != nil { | ||
log.Printf("[CRITAL] create directory %s error: %v", dirPath, err.Error()) | ||
return err | ||
} | ||
|
||
currentDate := time.Now().Format("20060102") | ||
filePath := filepath.Join(dirPath, currentDate+".csv") | ||
|
||
_, err = os.Stat(filePath) | ||
if os.IsNotExist(err) { | ||
err = GenerateCsvFile(filePath, header) | ||
if err != nil { | ||
log.Printf("[CRITAL] generate csv file error: %v", err.Error()) | ||
return err | ||
} | ||
} | ||
|
||
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644) | ||
if err != nil { | ||
log.Printf("[CRITAL] open csv file error: %v", err.Error()) | ||
return err | ||
} | ||
defer file.Close() | ||
|
||
writer := csv.NewWriter(file) | ||
|
||
for _, row := range data { | ||
err = writer.Write(row) | ||
if err != nil { | ||
log.Printf("[CRITAL] write data[%v] to csv file error: %v", row, err.Error()) | ||
return err | ||
} | ||
count++ | ||
} | ||
writer.Flush() | ||
|
||
return nil | ||
} | ||
|
||
// GenerateCsvFile generate when csv file does not exist | ||
func GenerateCsvFile(filePath string, header []string) error { | ||
file, err := os.Create(filePath) | ||
if err != nil { | ||
log.Printf("[CRITAL] create csv file error: %v", err.Error()) | ||
return err | ||
} | ||
defer file.Close() | ||
|
||
writer := csv.NewWriter(file) | ||
err = writer.Write(header) | ||
if err != nil { | ||
log.Printf("[CRITAL] write header to csv file error: %v", err.Error()) | ||
return err | ||
} | ||
writer.Flush() | ||
|
||
return nil | ||
} |
Oops, something went wrong.