Skip to content

Commit 8e2ac04

Browse files
committed
feat(volcengine): add demo replay support
1 parent cc4003b commit 8e2ac04

15 files changed

Lines changed: 1653 additions & 85 deletions

File tree

pkg/providers/alibaba/replay/meta.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
package replay
22

3-
import "strings"
3+
import (
4+
"strings"
5+
6+
demoreplay "github.com/404tk/cloudtoolkit/pkg/providers/replay"
7+
)
48

59
type Credentials struct {
610
AccessKey string
711
SecretKey string
812
}
913

1014
func SupportsProvider(provider string) bool {
11-
return normalizeProvider(provider) == "alibaba"
15+
return strings.TrimSpace(provider) == "alibaba"
1216
}
1317

1418
func CredentialsFor(provider string) (Credentials, bool) {
1519
if !SupportsProvider(provider) {
1620
return Credentials{}, false
1721
}
22+
creds, ok := demoreplay.CredentialsFor("alibaba")
23+
if !ok {
24+
return Credentials{}, false
25+
}
1826
return Credentials{
19-
AccessKey: DemoAccessKeyID,
20-
SecretKey: DemoAccessKeySecret,
27+
AccessKey: creds.AccessKey,
28+
SecretKey: creds.SecretKey,
2129
}, true
2230
}
23-
24-
func normalizeProvider(provider string) string {
25-
return strings.TrimSpace(provider)
26-
}
Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,23 @@
11
package replay
22

3-
import "sync"
4-
5-
type replayState struct {
6-
Active bool
7-
Provider string
8-
}
9-
10-
var (
11-
replayStateMu sync.RWMutex
12-
currentState replayState
13-
)
3+
import demoreplay "github.com/404tk/cloudtoolkit/pkg/providers/replay"
144

155
func Enable(provider string) {
16-
replayStateMu.Lock()
17-
defer replayStateMu.Unlock()
18-
currentState = replayState{
19-
Active: true,
20-
Provider: normalizeProvider(provider),
21-
}
6+
demoreplay.Enable(provider)
227
}
238

249
func Disable() {
25-
replayStateMu.Lock()
26-
defer replayStateMu.Unlock()
27-
currentState = replayState{}
10+
demoreplay.Disable()
2811
}
2912

3013
func IsActive() bool {
31-
replayStateMu.RLock()
32-
defer replayStateMu.RUnlock()
33-
return currentState.Active && currentState.Provider != ""
14+
return demoreplay.IsActive()
3415
}
3516

3617
func ActiveProvider() string {
37-
replayStateMu.RLock()
38-
defer replayStateMu.RUnlock()
39-
return currentState.Provider
18+
return demoreplay.ActiveProvider()
4019
}
4120

4221
func IsActiveForProvider(provider string) bool {
43-
replayStateMu.RLock()
44-
defer replayStateMu.RUnlock()
45-
return currentState.Active && currentState.Provider != "" && currentState.Provider == normalizeProvider(provider)
22+
return demoreplay.IsActiveForProvider(provider)
4623
}

pkg/providers/alibaba/replay/transport.go

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ func (t *transport) handleRPC(req *http.Request) (*http.Response, error) {
6969

7070
host := strings.ToLower(req.URL.Hostname())
7171
action := strings.TrimSpace(req.URL.Query().Get("Action"))
72-
switch host {
73-
case "sts.aliyuncs.com":
72+
switch rpcProductFromHost(host) {
73+
case "sts":
7474
if action == "GetCallerIdentity" {
7575
return jsonResponse(req, http.StatusOK, api.GetCallerIdentityResponse{
7676
IdentityType: "RAMUser",
@@ -81,7 +81,7 @@ func (t *transport) handleRPC(req *http.Request) (*http.Response, error) {
8181
Arn: demoCallerArn(),
8282
}), nil
8383
}
84-
case "business.aliyuncs.com":
84+
case "bssopenapi":
8585
if action == "QueryAccountBalance" {
8686
return jsonResponse(req, http.StatusOK, api.QueryAccountBalanceResponse{
8787
Code: "Success",
@@ -93,23 +93,51 @@ func (t *transport) handleRPC(req *http.Request) (*http.Response, error) {
9393
},
9494
}), nil
9595
}
96-
case "ecs.aliyuncs.com":
96+
case "ecs":
9797
return t.handleECS(req, action)
98-
case "ram.aliyuncs.com":
98+
case "ram":
9999
return t.handleRAM(req, action)
100-
case "rds.aliyuncs.com":
100+
case "rds":
101101
return t.handleRDS(req, action)
102-
case "tds.aliyuncs.com":
102+
case "sas":
103103
return t.handleSAS(req, action)
104-
case "alidns.aliyuncs.com":
104+
case "alidns":
105105
return t.handleDNS(req, action)
106-
case "dysmsapi.aliyuncs.com":
106+
case "dysmsapi":
107107
return t.handleSMS(req, action)
108+
case "location":
109+
return t.handleLocation(req, action)
108110
}
109111

110112
return rpcErrorResponse(req, http.StatusNotFound, "InvalidAction.NotFound", fmt.Sprintf("Unsupported replay action: %s", action)), nil
111113
}
112114

115+
func (t *transport) handleLocation(req *http.Request, action string) (*http.Response, error) {
116+
if action != "DescribeEndpoints" {
117+
return rpcErrorResponse(req, http.StatusNotFound, "InvalidAction.NotFound", fmt.Sprintf("Unsupported Location replay action: %s", action)), nil
118+
}
119+
120+
serviceCode := strings.TrimSpace(req.URL.Query().Get("ServiceCode"))
121+
region := strings.TrimSpace(req.URL.Query().Get("Id"))
122+
if region == "" {
123+
region = api.DefaultRegion
124+
}
125+
host := ""
126+
switch serviceCode {
127+
case "ecs":
128+
host = replayECSEndpoint(region)
129+
}
130+
return jsonResponse(req, http.StatusOK, map[string]any{
131+
"RequestId": "req-location-endpoints",
132+
"Success": true,
133+
"Endpoints": map[string]any{
134+
"Endpoint": []map[string]string{
135+
{"Endpoint": host},
136+
},
137+
},
138+
}), nil
139+
}
140+
113141
func (t *transport) handleECS(req *http.Request, action string) (*http.Response, error) {
114142
query := req.URL.Query()
115143
switch action {
@@ -906,6 +934,68 @@ func isSLSHost(req *http.Request) bool {
906934
return strings.Contains(strings.ToLower(req.URL.Hostname()), ".log.aliyuncs.com")
907935
}
908936

937+
func rpcProductFromHost(host string) string {
938+
host = normalizeRPCReplayHost(host)
939+
switch {
940+
case host == "sts.aliyuncs.com" || strings.HasPrefix(host, "sts-vpc."):
941+
return "sts"
942+
case host == "location-readonly.aliyuncs.com":
943+
return "location"
944+
case host == "business.aliyuncs.com" || strings.HasPrefix(host, "business."):
945+
return "bssopenapi"
946+
case host == "ram.aliyuncs.com":
947+
return "ram"
948+
case host == "alidns.aliyuncs.com":
949+
return "alidns"
950+
case host == "dysmsapi.aliyuncs.com":
951+
return "dysmsapi"
952+
case host == "tds.aliyuncs.com":
953+
return "sas"
954+
case isECSRPCHost(host):
955+
return "ecs"
956+
case isRDSRPCHost(host):
957+
return "rds"
958+
default:
959+
return ""
960+
}
961+
}
962+
963+
func isECSRPCHost(host string) bool {
964+
host = normalizeRPCReplayHost(host)
965+
return host == "ecs.aliyuncs.com" ||
966+
strings.HasPrefix(host, "ecs-") ||
967+
strings.HasPrefix(host, "ecs.") ||
968+
strings.HasPrefix(host, "ecs-vpc.")
969+
}
970+
971+
func isRDSRPCHost(host string) bool {
972+
host = normalizeRPCReplayHost(host)
973+
return host == "rds.aliyuncs.com" ||
974+
strings.HasPrefix(host, "rds-") ||
975+
strings.HasPrefix(host, "rds.") ||
976+
strings.HasPrefix(host, "rds-vpc.")
977+
}
978+
979+
func replayECSEndpoint(region string) string {
980+
region = strings.TrimSpace(region)
981+
if region == "" {
982+
region = api.DefaultRegion
983+
}
984+
switch {
985+
case strings.HasPrefix(region, "cn-"):
986+
return "ecs-" + region + ".aliyuncs.com"
987+
default:
988+
return "ecs." + region + ".aliyuncs.com"
989+
}
990+
}
991+
992+
func normalizeRPCReplayHost(host string) string {
993+
host = strings.ToLower(strings.TrimSpace(host))
994+
host = strings.TrimSuffix(host, ":443")
995+
host = strings.TrimSuffix(host, ":80")
996+
return host
997+
}
998+
909999
func requestHost(req *http.Request) string {
9101000
if req == nil {
9111001
return ""

pkg/providers/providers.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import (
1111
"github.com/404tk/cloudtoolkit/pkg/providers/gcp"
1212
"github.com/404tk/cloudtoolkit/pkg/providers/huawei"
1313
"github.com/404tk/cloudtoolkit/pkg/providers/jdcloud"
14+
demoreplay "github.com/404tk/cloudtoolkit/pkg/providers/replay"
1415
"github.com/404tk/cloudtoolkit/pkg/providers/tencent"
1516
"github.com/404tk/cloudtoolkit/pkg/providers/volcengine"
17+
volcreplay "github.com/404tk/cloudtoolkit/pkg/providers/volcengine/replay"
1618
"github.com/404tk/cloudtoolkit/pkg/schema"
1719
)
1820

@@ -30,7 +32,7 @@ var catalog = []entry{
3032
{
3133
info: Info{Name: "alibaba", Desc: "Alibaba Cloud"},
3234
new: func(block schema.Options) (schema.Provider, error) {
33-
if alireplay.IsActiveForProvider("alibaba") {
35+
if demoreplay.IsActiveForProvider("alibaba") {
3436
return alibaba.NewWithConfig(block, alireplay.ClientConfig())
3537
}
3638
return alibaba.New(block)
@@ -63,6 +65,9 @@ var catalog = []entry{
6365
{
6466
info: Info{Name: "volcengine", Desc: "Volcengine"},
6567
new: func(block schema.Options) (schema.Provider, error) {
68+
if demoreplay.IsActiveForProvider("volcengine") {
69+
return volcengine.NewWithConfig(block, volcreplay.ClientConfig())
70+
}
6671
return volcengine.New(block)
6772
},
6873
},

pkg/providers/replay/replay.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package replay
2+
3+
import (
4+
"strings"
5+
"sync"
6+
)
7+
8+
type State struct {
9+
Active bool
10+
Provider string
11+
}
12+
13+
type Credentials struct {
14+
AccessKey string
15+
SecretKey string
16+
}
17+
18+
type providerMeta struct {
19+
Credentials Credentials
20+
Payloads []string
21+
}
22+
23+
var (
24+
stateMu sync.RWMutex
25+
state State
26+
)
27+
28+
var providers = map[string]providerMeta{
29+
"alibaba": {
30+
Credentials: Credentials{
31+
AccessKey: "LTAI4tDVhjxvrWKTsEXAMPLE",
32+
SecretKey: "EXAMPLEv2fYAa2s7GhvLun7xqctKEY",
33+
},
34+
Payloads: []string{
35+
"cloudlist",
36+
"iam-user-check",
37+
"bucket-check",
38+
"event-check",
39+
"rds-account-check",
40+
"instance-cmd-check",
41+
},
42+
},
43+
"volcengine": {
44+
Credentials: Credentials{
45+
AccessKey: "AKLTOTgzY2UyYzA1NDQ5NGE5MzkEXAMPLE",
46+
SecretKey: "QkN5ZlJmM0d1R2JMb2M5dVhLQXBQd1pHc2ZEXAMPLE",
47+
},
48+
Payloads: []string{
49+
"cloudlist",
50+
"iam-user-check",
51+
"bucket-check",
52+
"instance-cmd-check",
53+
},
54+
},
55+
}
56+
57+
func Enable(provider string) {
58+
stateMu.Lock()
59+
defer stateMu.Unlock()
60+
state = State{
61+
Active: true,
62+
Provider: normalizeProvider(provider),
63+
}
64+
}
65+
66+
func Disable() {
67+
stateMu.Lock()
68+
defer stateMu.Unlock()
69+
state = State{}
70+
}
71+
72+
func IsActive() bool {
73+
stateMu.RLock()
74+
defer stateMu.RUnlock()
75+
return state.Active && state.Provider != ""
76+
}
77+
78+
func ActiveProvider() string {
79+
stateMu.RLock()
80+
defer stateMu.RUnlock()
81+
return state.Provider
82+
}
83+
84+
func IsActiveForProvider(provider string) bool {
85+
stateMu.RLock()
86+
defer stateMu.RUnlock()
87+
return state.Active && state.Provider != "" && state.Provider == normalizeProvider(provider)
88+
}
89+
90+
func SupportsProvider(provider string) bool {
91+
_, ok := providers[normalizeProvider(provider)]
92+
return ok
93+
}
94+
95+
func CredentialsFor(provider string) (Credentials, bool) {
96+
meta, ok := providers[normalizeProvider(provider)]
97+
if !ok {
98+
return Credentials{}, false
99+
}
100+
return meta.Credentials, true
101+
}
102+
103+
func SupportedPayloads(provider string) []string {
104+
meta, ok := providers[normalizeProvider(provider)]
105+
if !ok || len(meta.Payloads) == 0 {
106+
return nil
107+
}
108+
return append([]string(nil), meta.Payloads...)
109+
}
110+
111+
func normalizeProvider(provider string) string {
112+
return strings.TrimSpace(provider)
113+
}

0 commit comments

Comments
 (0)