Skip to content

Commit 1cdb32c

Browse files
authored
Merge pull request #1755 from ioito/hotfix/qx-aws-bill-query
fix(aws): support query aws month bill
2 parents 6d5fbc4 + 30c5a43 commit 1cdb32c

File tree

96 files changed

+46181
-290
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+46181
-290
lines changed

go.mod

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible
1111
github.com/aokoli/goutils v1.0.1
1212
github.com/aws/aws-sdk-go v1.39.0
13-
github.com/aws/aws-sdk-go-v2 v1.39.2
13+
github.com/aws/aws-sdk-go-v2 v1.41.4
1414
github.com/aws/aws-sdk-go-v2/config v1.31.12
1515
github.com/aws/aws-sdk-go-v2/credentials v1.18.16
1616
github.com/aws/aws-sdk-go-v2/service/organizations v1.45.3
@@ -55,18 +55,19 @@ require (
5555
github.com/Azure/go-autorest/tracing v0.5.0 // indirect
5656
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 // indirect
5757
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 // indirect
58-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 // indirect
59-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 // indirect
58+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect
59+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect
6060
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
6161
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9 // indirect
62+
github.com/aws/aws-sdk-go-v2/service/costexplorer v1.63.5 // indirect
6263
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
6364
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.0 // indirect
6465
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9 // indirect
6566
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.9 // indirect
6667
github.com/aws/aws-sdk-go-v2/service/sso v1.29.6 // indirect
6768
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1 // indirect
6869
github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 // indirect
69-
github.com/aws/smithy-go v1.23.0 // indirect
70+
github.com/aws/smithy-go v1.24.2 // indirect
7071
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
7172
github.com/beevik/etree v1.1.0 // indirect
7273
github.com/bitly/go-simplejson v0.5.0 // indirect

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo
4747
github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
4848
github.com/aws/aws-sdk-go-v2 v1.39.2 h1:EJLg8IdbzgeD7xgvZ+I8M1e0fL0ptn/M47lianzth0I=
4949
github.com/aws/aws-sdk-go-v2 v1.39.2/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY=
50+
github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=
51+
github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
5052
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 h1:i8p8P4diljCr60PpJp6qZXNlgX4m2yQFpYk+9ZT+J4E=
5153
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1/go.mod h1:ddqbooRZYNoJ2dsTwOty16rM+/Aqmk/GOXrK8cg7V00=
5254
github.com/aws/aws-sdk-go-v2/config v1.31.12 h1:pYM1Qgy0dKZLHX2cXslNacbcEFMkDMl+Bcj5ROuS6p8=
@@ -57,12 +59,18 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 h1:Mv4Bc0mWmv6oDuSWTKnk+wg
5759
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9/go.mod h1:IKlKfRppK2a1y0gy1yH6zD+yX5uplJ6UuPlgd48dJiQ=
5860
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 h1:se2vOWGD3dWQUtfn4wEjRQJb1HK1XsNIt825gskZ970=
5961
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9/go.mod h1:hijCGH2VfbZQxqCDN7bwz/4dzxV+hkyhjawAtdPWKZA=
62+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc=
63+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o=
6064
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 h1:6RBnKZLkJM4hQ+kN6E7yWFveOTg8NLPHAkqrs4ZPlTU=
6165
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9/go.mod h1:V9rQKRmK7AWuEsOMnHzKj8WyrIir1yUJbZxDuZLFvXI=
66+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw=
67+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc=
6268
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
6369
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
6470
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9 h1:w9LnHqTq8MEdlnyhV4Bwfizd65lfNCNgdlNC6mM5paE=
6571
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9/go.mod h1:LGEP6EK4nj+bwWNdrvX/FnDTFowdBNwcSPuZu/ouFys=
72+
github.com/aws/aws-sdk-go-v2/service/costexplorer v1.63.5 h1:iNNJ6ZrQO37Xh12XjNncS3fq/11l1TzyZwBWcZMHWkY=
73+
github.com/aws/aws-sdk-go-v2/service/costexplorer v1.63.5/go.mod h1:auLb1gCiI54TM7iUxSYu5MYSimWr0fL6t5/PgxkJOr0=
6674
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM=
6775
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8=
6876
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.0 h1:X0FveUndcZ3lKbSpIC6rMYGRiQTcUVRNH6X4yYtIrlU=
@@ -83,6 +91,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 h1:p3jIvqYwUZgu/XYeI48bJxOhvm47
8391
github.com/aws/aws-sdk-go-v2/service/sts v1.38.6/go.mod h1:WtKK+ppze5yKPkZ0XwqIVWD4beCwv056ZbPQNoeHqM8=
8492
github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE=
8593
github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
94+
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
95+
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
8696
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
8797
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
8898
github.com/basgys/goxml2json v1.1.1-0.20181031222924-996d9fc8d313 h1:fKPpQHBQgt4dQuG6x+yH4gdgtodFDgN9rvHzwJzTKeg=

pkg/multicloud/aws/business.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Copyright 2019 Yunion
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package aws
16+
17+
import (
18+
"context"
19+
"sort"
20+
"strconv"
21+
"time"
22+
23+
aws2 "github.com/aws/aws-sdk-go-v2/aws"
24+
"github.com/aws/aws-sdk-go-v2/service/costexplorer"
25+
cetypes "github.com/aws/aws-sdk-go-v2/service/costexplorer/types"
26+
27+
api "yunion.io/x/cloudmux/pkg/apis/compute"
28+
"yunion.io/x/pkg/errors"
29+
)
30+
31+
type SMonthBill struct {
32+
Month string `json:"month"`
33+
StartDate string `json:"start_date"`
34+
EndDate string `json:"end_date"`
35+
Currency string `json:"currency"`
36+
Total float64 `json:"total"`
37+
Metric string `json:"metric"`
38+
Granularity string `json:"granularity"`
39+
Services []SMonthBillServiceFee `json:"services"`
40+
}
41+
42+
type SMonthBillServiceFee struct {
43+
Service string `json:"service"`
44+
Amount string `json:"amount"`
45+
Unit string `json:"unit"`
46+
}
47+
48+
func getMonthDateRange(month string) (string, string, error) {
49+
monthStart, err := time.Parse("2006-01", month)
50+
if err != nil {
51+
return "", "", errors.Wrapf(err, "invalid month %q, expected YYYY-MM", month)
52+
}
53+
monthEnd := monthStart.AddDate(0, 1, 0)
54+
return monthStart.Format("2006-01-02"), monthEnd.Format("2006-01-02"), nil
55+
}
56+
57+
func (self *SAwsClient) getCostExplorerRegion() string {
58+
if self.GetAccessEnv() == api.CLOUD_ACCESS_ENV_AWS_CHINA {
59+
return "cn-northwest-1"
60+
}
61+
return "us-east-1"
62+
}
63+
64+
func (self *SAwsClient) GetMonthBill(month string) (*SMonthBill, error) {
65+
startDate, endDate, err := getMonthDateRange(month)
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
cfg, err := self.getConfig(context.Background(), self.getCostExplorerRegion(), true)
71+
if err != nil {
72+
return nil, errors.Wrap(err, "getConfig")
73+
}
74+
75+
ceCli := costexplorer.NewFromConfig(cfg)
76+
resp, err := ceCli.GetCostAndUsage(context.Background(), &costexplorer.GetCostAndUsageInput{
77+
TimePeriod: &cetypes.DateInterval{
78+
Start: aws2.String(startDate),
79+
End: aws2.String(endDate),
80+
},
81+
Granularity: cetypes.GranularityMonthly,
82+
Metrics: []string{"UnblendedCost"},
83+
GroupBy: []cetypes.GroupDefinition{
84+
{
85+
Type: cetypes.GroupDefinitionTypeDimension,
86+
Key: aws2.String("SERVICE"),
87+
},
88+
},
89+
})
90+
if err != nil {
91+
return nil, errors.Wrap(err, "GetCostAndUsage")
92+
}
93+
94+
ret := &SMonthBill{
95+
Month: month,
96+
StartDate: startDate,
97+
EndDate: endDate,
98+
Metric: "UnblendedCost",
99+
Granularity: string(cetypes.GranularityMonthly),
100+
Services: make([]SMonthBillServiceFee, 0),
101+
}
102+
103+
var total float64
104+
for _, byTime := range resp.ResultsByTime {
105+
for _, group := range byTime.Groups {
106+
if len(group.Keys) == 0 {
107+
continue
108+
}
109+
metric, ok := group.Metrics["UnblendedCost"]
110+
if !ok {
111+
continue
112+
}
113+
if len(ret.Currency) == 0 {
114+
ret.Currency = aws2.ToString(metric.Unit)
115+
}
116+
amount := aws2.ToString(metric.Amount)
117+
if len(amount) > 0 {
118+
if val, parseErr := strconv.ParseFloat(amount, 64); parseErr == nil {
119+
total += val
120+
}
121+
}
122+
ret.Services = append(ret.Services, SMonthBillServiceFee{
123+
Service: group.Keys[0],
124+
Amount: amount,
125+
Unit: aws2.ToString(metric.Unit),
126+
})
127+
}
128+
}
129+
ret.Total = total
130+
131+
sort.Slice(ret.Services, func(i, j int) bool {
132+
iVal, iErr := strconv.ParseFloat(ret.Services[i].Amount, 64)
133+
jVal, jErr := strconv.ParseFloat(ret.Services[j].Amount, 64)
134+
if iErr != nil || jErr != nil {
135+
return ret.Services[i].Amount > ret.Services[j].Amount
136+
}
137+
return iVal > jVal
138+
})
139+
140+
return ret, nil
141+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2019 Yunion
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package shell
16+
17+
import (
18+
"yunion.io/x/pkg/util/shellutils"
19+
20+
"yunion.io/x/cloudmux/pkg/multicloud/aws"
21+
)
22+
23+
func init() {
24+
type AwsMonthBillOptions struct {
25+
MONTH string `help:"Billing month, e.g. 2026-03"`
26+
}
27+
shellutils.R(&AwsMonthBillOptions{}, "month-bill", "Query AWS month bill overview", func(cli *aws.SRegion, args *AwsMonthBillOptions) error {
28+
result, err := cli.GetClient().GetMonthBill(args.MONTH)
29+
if err != nil {
30+
return err
31+
}
32+
printObject(result)
33+
return nil
34+
})
35+
}

vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/middleware.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/timeout_read_closer.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)