fix: 完善多云同步验证与实例统计
- 修复华为云签名、账单字段与区域映射缓存 - 按真实云实例更新账号服务器数并补充并发测试
This commit is contained in:
1 parent
132fe9ba97
commit
9b895efee3
6 files changed
+226
-64
No files matched your search
@@ -11,6 +11,28 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type huaweiBillRecord struct {
|
||||
ServiceTypeCode string `json:"service_type_code"`
|
||||
ServiceTypeName string `json:"service_type_name"`
|
||||
CloudServiceType string `json:"cloud_service_type"`
|
||||
CloudServiceTypeName string `json:"cloud_service_type_name"`
|
||||
ResourceTypeName string `json:"resource_type_name"`
|
||||
RegionCode string `json:"region_code"`
|
||||
Region string `json:"region"`
|
||||
RegionName string `json:"region_name"`
|
||||
Amount json.RawMessage `json:"amount"`
|
||||
ConsumeAmount json.RawMessage `json:"consume_amount"`
|
||||
OfficialAmount json.RawMessage `json:"official_amount"`
|
||||
DiscountAmount json.RawMessage `json:"discount_amount"`
|
||||
}
|
||||
|
||||
type huaweiBillPage struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
Currency string `json:"currency"`
|
||||
Records []huaweiBillRecord `json:"records"`
|
||||
FeeRecords []huaweiBillRecord `json:"fee_records"`
|
||||
}
|
||||
|
||||
// FetchDailyBill 通过华为云 BSS 费用流水接口拉取单日账单。 // Logan.Li
|
||||
func (p *HuaweiProvider) FetchDailyBill(billingDate string) ([]CloudBillingRecord, error) {
|
||||
if _, err := time.Parse("2006-01-02", billingDate); err != nil {
|
||||
@@ -21,10 +43,11 @@ func (p *HuaweiProvider) FetchDailyBill(billingDate string) ([]CloudBillingRecor
|
||||
region string
|
||||
}
|
||||
aggregation := map[aggregationKey]float64{}
|
||||
currency := "CNY"
|
||||
const pageSize = 1000
|
||||
for offset := 0; ; offset += pageSize {
|
||||
query := url.Values{
|
||||
"cycle": {billingDate[:7]},
|
||||
"bill_cycle": {billingDate[:7]},
|
||||
"bill_date_begin": {billingDate},
|
||||
"bill_date_end": {billingDate},
|
||||
"offset": {strconv.Itoa(offset)},
|
||||
@@ -34,35 +57,27 @@ func (p *HuaweiProvider) FetchDailyBill(billingDate string) ([]CloudBillingRecor
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
FeeRecords []struct {
|
||||
CloudServiceType string `json:"cloud_service_type"`
|
||||
CloudServiceTypeName string `json:"cloud_service_type_name"`
|
||||
ResourceTypeName string `json:"resource_type_name"`
|
||||
Region string `json:"region"`
|
||||
RegionName string `json:"region_name"`
|
||||
Amount json.RawMessage `json:"amount"`
|
||||
OfficialAmount json.RawMessage `json:"official_amount"`
|
||||
DiscountAmount json.RawMessage `json:"discount_amount"`
|
||||
} `json:"fee_records"`
|
||||
page, err := decodeHuaweiBillPage(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal(body, &response); err != nil {
|
||||
return nil, fmt.Errorf("解析华为云 BSS 响应失败: %w", err)
|
||||
if page.Currency != "" {
|
||||
currency = page.Currency
|
||||
}
|
||||
for _, item := range response.FeeRecords {
|
||||
cost := huaweiBillAmount(item.Amount)
|
||||
if cost == 0 {
|
||||
cost = huaweiBillAmount(item.OfficialAmount) - huaweiBillAmount(item.DiscountAmount)
|
||||
}
|
||||
records := page.Records
|
||||
if len(records) == 0 {
|
||||
records = page.FeeRecords
|
||||
}
|
||||
for _, item := range records {
|
||||
cost := huaweiBillRecordCost(item)
|
||||
if cost == 0 {
|
||||
continue
|
||||
}
|
||||
service := firstNonEmpty(item.CloudServiceTypeName, item.ResourceTypeName, item.CloudServiceType, "其他")
|
||||
region := firstNonEmpty(item.RegionName, item.Region, "全局")
|
||||
service := firstNonEmpty(item.ServiceTypeName, item.CloudServiceTypeName, item.ResourceTypeName, item.ServiceTypeCode, item.CloudServiceType, "其他")
|
||||
region := firstNonEmpty(item.RegionName, item.RegionCode, item.Region, "全局")
|
||||
aggregation[aggregationKey{service: service, region: region}] += cost
|
||||
}
|
||||
if len(response.FeeRecords) < pageSize || (response.TotalCount > 0 && offset+pageSize >= response.TotalCount) {
|
||||
if len(records) < pageSize || (page.TotalCount > 0 && offset+pageSize >= page.TotalCount) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -80,13 +95,33 @@ func (p *HuaweiProvider) FetchDailyBill(billingDate string) ([]CloudBillingRecor
|
||||
for _, key := range keys {
|
||||
records = append(records, CloudBillingRecord{
|
||||
BillingDate: billingDate, Provider: "huawei", Cost: math.Round(aggregation[key]*100) / 100,
|
||||
Currency: "CNY", Service: key.service, Region: key.region,
|
||||
Currency: currency, Service: key.service, Region: key.region,
|
||||
Description: "云 API 自动同步(华为云 BSS)",
|
||||
})
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// decodeHuaweiBillPage 兼容华为云 records 与旧版 fee_records 响应。 // Logan.Li
|
||||
func decodeHuaweiBillPage(body []byte) (huaweiBillPage, error) {
|
||||
var page huaweiBillPage
|
||||
if err := json.Unmarshal(body, &page); err != nil {
|
||||
return page, fmt.Errorf("解析华为云 BSS 响应失败: %w", err)
|
||||
}
|
||||
return page, nil
|
||||
}
|
||||
|
||||
// huaweiBillRecordCost 依次读取实际消费、流水金额和官网价减优惠。 // Logan.Li
|
||||
func huaweiBillRecordCost(item huaweiBillRecord) float64 {
|
||||
if cost := huaweiBillAmount(item.ConsumeAmount); cost != 0 {
|
||||
return cost
|
||||
}
|
||||
if cost := huaweiBillAmount(item.Amount); cost != 0 {
|
||||
return cost
|
||||
}
|
||||
return huaweiBillAmount(item.OfficialAmount) - huaweiBillAmount(item.DiscountAmount)
|
||||
}
|
||||
|
||||
// huaweiBillAmount 兼容华为云金额字段的字符串和数字格式。 // Logan.Li
|
||||
func huaweiBillAmount(raw json.RawMessage) float64 {
|
||||
value := strings.Trim(strings.TrimSpace(string(raw)), "\"")
|
||||
|
||||
Reference in new issue
Block a user