fix(region): cloud lake of permissions

This commit is contained in:
ioito
2022-04-08 20:42:35 +08:00
parent 06bd541153
commit 0feb31c29d
22 changed files with 308 additions and 202 deletions
+17 -6
View File
@@ -17,19 +17,30 @@ package cloudprovider
import "net/http"
type transport struct {
readOnlyCheck func(req *http.Request) error
ts *http.Transport
check func(*http.Request) (func(resp *http.Response), error)
ts *http.Transport
}
func (self *transport) RoundTrip(req *http.Request) (*http.Response, error) {
err := self.readOnlyCheck(req)
var respCheck func(resp *http.Response) = nil
var err error
if self.check != nil {
respCheck, err = self.check(req)
if err != nil {
return nil, err
}
}
resp, err := self.ts.RoundTrip(req)
if err != nil {
return nil, err
}
return self.ts.RoundTrip(req)
if respCheck != nil {
respCheck(resp)
}
return resp, nil
}
func GetReadOnlyCheckTransport(ts *http.Transport, check func(req *http.Request) error) http.RoundTripper {
ret := &transport{ts: ts, readOnlyCheck: check}
func GetCheckTransport(ts *http.Transport, check func(*http.Request) (func(resp *http.Response), error)) http.RoundTripper {
ret := &transport{ts: ts, check: check}
return ret
}
+59 -37
View File
@@ -15,7 +15,9 @@
package aliyun
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
@@ -161,11 +163,10 @@ func NewAliyunClient(cfg *AliyunClientConfig) (*SAliyunClient, error) {
return &client, nil
}
func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params map[string]string, updateFunc func(string, string), debug bool) (jsonutils.JSONObject, error) {
func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) {
if debug {
log.Debugf("request %s %s %s %s", domain, apiVersion, apiName, params)
}
service := strings.Split(domain, ".")[0]
var resp jsonutils.JSONObject
var err error
for i := 1; i < 4; i++ {
@@ -182,16 +183,8 @@ func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params
if e, ok := errors.Cause(err).(*alierr.ServerError); ok {
code := e.ErrorCode()
switch code {
case "NoPermission", "Forbidden.RAM", "SubAccountNoPermission", "Forbidden":
if updateFunc != nil {
updateFunc(service, apiName)
}
return nil, errors.Wrapf(httperrors.ErrNoPermission, err.Error())
case "InternalError":
if apiName == "QueryAccountBalance" {
if updateFunc != nil {
updateFunc(service, apiName)
}
return nil, errors.Wrapf(httperrors.ErrNoPermission, err.Error())
}
return nil, err
@@ -346,7 +339,7 @@ func (self *SAliyunClient) fetchNasEndpoints() error {
if err != nil {
return errors.Wrapf(err, "getDefaultClient")
}
resp, err := jsonRequest(client, "nas.aliyuncs.com", ALIYUN_NAS_API_VERSION, "DescribeRegions", nil, self.cpcfg.UpdatePermission, self.debug)
resp, err := jsonRequest(client, "nas.aliyuncs.com", ALIYUN_NAS_API_VERSION, "DescribeRegions", nil, self.debug)
if err != nil {
return errors.Wrapf(err, "DescribeRegions")
}
@@ -386,7 +379,7 @@ func (self *SAliyunClient) fetchVpcEndpoints() error {
if err != nil {
return errors.Wrapf(err, "getDefaultClient")
}
resp, err := jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, "DescribeRegions", nil, self.cpcfg.UpdatePermission, self.debug)
resp, err := jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, "DescribeRegions", nil, self.debug)
if err != nil {
return errors.Wrapf(err, "DescribeRegions")
}
@@ -408,21 +401,44 @@ func (self *SAliyunClient) getSdkClient(regionId string) (*sdk.Client, error) {
regionId,
&sdk.Config{
HttpTransport: transport,
Transport: cloudprovider.GetReadOnlyCheckTransport(transport, func(req *http.Request) error {
if self.cpcfg.ReadOnly {
params, err := url.ParseQuery(req.URL.RawQuery)
if err != nil {
return errors.Wrapf(err, "ParseQuery(%s)", req.URL.RawQuery)
}
action := params.Get("Action")
for _, prefix := range []string{"Get", "List", "Describe"} {
if strings.HasPrefix(action, prefix) {
return nil
Transport: cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) {
params, err := url.ParseQuery(req.URL.RawQuery)
if err != nil {
return nil, errors.Wrapf(err, "ParseQuery(%s)", req.URL.RawQuery)
}
service := strings.Split(req.URL.Host, ".")[0]
action := params.Get("Action")
respCheck := func(resp *http.Response) {
if self.cpcfg.UpdatePermission != nil && resp.StatusCode >= 400 && resp.ContentLength > 0 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
resp.Body = ioutil.NopCloser(bytes.NewBuffer(body))
obj, err := jsonutils.Parse(body)
if err != nil {
return
}
ret := struct{ Code string }{}
obj.Unmarshal(&ret)
if utils.IsInStringArray(ret.Code, []string{
"NoPermission",
"SubAccountNoPermission",
}) || utils.HasPrefix(ret.Code, "Forbidden") ||
action == "QueryAccountBalance" && ret.Code == "InternalError" {
self.cpcfg.UpdatePermission(service, action)
}
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
}
return nil
for _, prefix := range []string{"Get", "List", "Describe"} {
if strings.HasPrefix(action, prefix) {
return respCheck, nil
}
}
if self.cpcfg.ReadOnly {
return respCheck, errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
}
return respCheck, nil
}),
},
&credentials.BaseCredential{
@@ -438,7 +454,7 @@ func (self *SAliyunClient) imsRequest(apiName string, params map[string]string)
if err != nil {
return nil, err
}
return jsonRequest(cli, "ims.aliyuncs.com", ALIYUN_IMS_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "ims.aliyuncs.com", ALIYUN_IMS_API_VERSION, apiName, params, self.debug)
}
func (self *SAliyunClient) rmRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -446,7 +462,7 @@ func (self *SAliyunClient) rmRequest(apiName string, params map[string]string) (
if err != nil {
return nil, err
}
return jsonRequest(cli, "resourcemanager.aliyuncs.com", ALIYUN_RM_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "resourcemanager.aliyuncs.com", ALIYUN_RM_API_VERSION, apiName, params, self.debug)
}
func (self *SAliyunClient) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -454,7 +470,7 @@ func (self *SAliyunClient) ecsRequest(apiName string, params map[string]string)
if err != nil {
return nil, err
}
return jsonRequest(cli, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params, self.debug)
}
func (self *SAliyunClient) pvtzRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -462,7 +478,7 @@ func (self *SAliyunClient) pvtzRequest(apiName string, params map[string]string)
if err != nil {
return nil, err
}
return jsonRequest(cli, "pvtz.aliyuncs.com", ALIYUN_PVTZ_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "pvtz.aliyuncs.com", ALIYUN_PVTZ_API_VERSION, apiName, params, self.debug)
}
func (self *SAliyunClient) alidnsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -470,7 +486,7 @@ func (self *SAliyunClient) alidnsRequest(apiName string, params map[string]strin
if err != nil {
return nil, err
}
return jsonRequest(cli, "alidns.aliyuncs.com", ALIYUN_ALIDNS_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "alidns.aliyuncs.com", ALIYUN_ALIDNS_API_VERSION, apiName, params, self.debug)
}
func (self *SAliyunClient) cbnRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -478,7 +494,7 @@ func (self *SAliyunClient) cbnRequest(apiName string, params map[string]string)
if err != nil {
return nil, err
}
return jsonRequest(cli, "cbn.aliyuncs.com", ALIYUN_CBN_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "cbn.aliyuncs.com", ALIYUN_CBN_API_VERSION, apiName, params, self.debug)
}
func (self *SAliyunClient) cdnRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -486,7 +502,7 @@ func (self *SAliyunClient) cdnRequest(apiName string, params map[string]string)
if err != nil {
return nil, err
}
return jsonRequest(cli, "cdn.aliyuncs.com", ALIYUN_CDN_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "cdn.aliyuncs.com", ALIYUN_CDN_API_VERSION, apiName, params, self.debug)
}
func (self *SAliyunClient) fetchRegions() error {
@@ -531,14 +547,20 @@ func (client *SAliyunClient) getOssClientByEndpoint(endpoint string) (*oss.Clien
// oss use no timeout client so as to send/download large files
httpClient := client.cpcfg.AdaptiveTimeoutHttpClient()
transport, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(transport, func(req *http.Request) error {
if client.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
httpClient.Transport = cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) {
path, method := req.URL.Path, req.Method
respCheck := func(resp *http.Response) {
if client.cpcfg.UpdatePermission != nil && resp.StatusCode == 403 {
client.cpcfg.UpdatePermission("oss", fmt.Sprintf("%s %s", method, path))
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.RawPath)
}
return nil
if client.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return respCheck, nil
}
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.RawPath)
}
return respCheck, nil
})
cliOpts := []oss.ClientOption{
oss.HTTPClient(httpClient),
+1 -1
View File
@@ -29,7 +29,7 @@ func (self *SAliyunClient) businessRequest(apiName string, params map[string]str
if err != nil {
return nil, err
}
return jsonRequest(cli, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params, self.debug)
}
type SAccountBalance struct {
+1 -1
View File
@@ -31,7 +31,7 @@ func (r *SRegion) metricsRequest(action string, params map[string]string) (jsonu
if err != nil {
return nil, errors.Wrap(err, "r.getSdkClient")
}
return jsonRequest(client, "metrics.aliyuncs.com", ALIYUN_API_VERSION_METRICS, action, params, r.client.cpcfg.UpdatePermission, r.client.debug)
return jsonRequest(client, "metrics.aliyuncs.com", ALIYUN_API_VERSION_METRICS, action, params, r.client.debug)
}
type SResourceLabel struct {
+1 -1
View File
@@ -23,5 +23,5 @@ func (self *SAliyunClient) ramRequest(apiName string, params map[string]string)
if err != nil {
return nil, err
}
return jsonRequest(cli, "ram.aliyuncs.com", ALIYUN_RAM_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "ram.aliyuncs.com", ALIYUN_RAM_API_VERSION, apiName, params, self.debug)
}
+12 -12
View File
@@ -137,7 +137,7 @@ func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonu
if len(endpoint) == 0 {
endpoint = "ecs.aliyuncs.com"
}
return jsonRequest(client, endpoint, ALIYUN_API_VERSION, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, endpoint, ALIYUN_API_VERSION, apiName, params, self.client.debug)
}
func (self *SRegion) wafRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -149,7 +149,7 @@ func (self *SRegion) wafRequest(apiName string, params map[string]string) (jsonu
return nil, cloudprovider.ErrNotSupported
}
endpoint := fmt.Sprintf("wafopenapi.%s.aliyuncs.com", self.RegionId)
return jsonRequest(client, endpoint, ALIYUN_WAF_API_VERSION, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, endpoint, ALIYUN_WAF_API_VERSION, apiName, params, self.client.debug)
}
func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -158,7 +158,7 @@ func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonut
return nil, err
}
domain := fmt.Sprintf("elasticsearch.%s.aliyuncs.com", self.RegionId)
return jsonRequest(client, domain, ALIYUN_ES_API_VERSION, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, domain, ALIYUN_ES_API_VERSION, apiName, params, self.client.debug)
}
func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -167,7 +167,7 @@ func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jso
return nil, err
}
domain := fmt.Sprintf("alikafka.%s.aliyuncs.com", self.RegionId)
return jsonRequest(client, domain, ALIYUN_KAFKA_API_VERSION, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, domain, ALIYUN_KAFKA_API_VERSION, apiName, params, self.client.debug)
}
func (self *SRegion) rdsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -175,7 +175,7 @@ func (self *SRegion) rdsRequest(apiName string, params map[string]string) (jsonu
if err != nil {
return nil, err
}
return jsonRequest(client, "rds.aliyuncs.com", ALIYUN_RDS_API_VERSION, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, "rds.aliyuncs.com", ALIYUN_RDS_API_VERSION, apiName, params, self.client.debug)
}
func (self *SRegion) k8sRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -183,7 +183,7 @@ func (self *SRegion) k8sRequest(apiName string, params map[string]string) (jsonu
if err != nil {
return nil, err
}
return jsonRequest(client, fmt.Sprintf("cs.%s.aliyuncs.com", self.RegionId), ALIYUN_K8S_API_VERSION, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, fmt.Sprintf("cs.%s.aliyuncs.com", self.RegionId), ALIYUN_K8S_API_VERSION, apiName, params, self.client.debug)
}
func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -191,7 +191,7 @@ func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (j
if err != nil {
return nil, err
}
return jsonRequest(client, "mongodb.aliyuncs.com", ALIYUN_MONGO_DB_API_VERSION, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, "mongodb.aliyuncs.com", ALIYUN_MONGO_DB_API_VERSION, apiName, params, self.client.debug)
}
func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -200,7 +200,7 @@ func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonut
return nil, err
}
endpoint := self.GetClient().getVpcEndpoint(self.RegionId)
return jsonRequest(client, endpoint, ALIYUN_API_VERSION_VPC, action, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, endpoint, ALIYUN_API_VERSION_VPC, action, params, self.client.debug)
}
func (self *SRegion) nasRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -223,7 +223,7 @@ func (self *SRegion) nasRequest(action string, params map[string]string) (jsonut
}
endpint := self.GetClient().getNasEndpoint(self.RegionId)
return jsonRequest(client, endpint, ALIYUN_NAS_API_VERSION, action, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, endpint, ALIYUN_NAS_API_VERSION, action, params, self.client.debug)
}
func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
@@ -236,7 +236,7 @@ func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonut
params["RegionId"] = transRegionIdFromEcsRegionId(self, "redis")
}
return jsonRequest(client, "r-kvstore.aliyuncs.com", ALIYUN_API_VERSION_KVS, action, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, "r-kvstore.aliyuncs.com", ALIYUN_API_VERSION_KVS, action, params, self.client.debug)
}
type LBRegion struct {
@@ -286,7 +286,7 @@ func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonut
}
func (self *SRegion) _lbRequest(client *sdk.Client, apiName string, domain string, params map[string]string) (jsonutils.JSONObject, error) {
return jsonRequest(client, domain, ALIYUN_API_VERSION_LB, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, domain, ALIYUN_API_VERSION_LB, apiName, params, self.client.debug)
}
/////////////////////////////////////////////////////////////////////////////
@@ -1240,5 +1240,5 @@ func (self *SRegion) trialRequest(apiName string, params map[string]string) (jso
return nil, err
}
domain := fmt.Sprintf("actiontrail.%s.aliyuncs.com", self.RegionId)
return jsonRequest(client, domain, ALIYUN_API_VERSION_TRIAL, apiName, params, self.client.cpcfg.UpdatePermission, self.client.debug)
return jsonRequest(client, domain, ALIYUN_API_VERSION_TRIAL, apiName, params, self.client.debug)
}
+1 -1
View File
@@ -23,7 +23,7 @@ func (self *SAliyunClient) stsRequest(apiName string, params map[string]string)
if err != nil {
return nil, err
}
return jsonRequest(cli, "sts.aliyuncs.com", ALIYUN_STS_API_VERSION, apiName, params, self.cpcfg.UpdatePermission, self.debug)
return jsonRequest(cli, "sts.aliyuncs.com", ALIYUN_STS_API_VERSION, apiName, params, self.debug)
}
type SCallerIdentity struct {
+40 -16
View File
@@ -15,8 +15,10 @@
package apsara
import (
"bytes"
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
@@ -279,21 +281,43 @@ func (self *SApsaraClient) getDefaultClient(regionId string) (*sdk.Client, error
regionId,
&sdk.Config{
HttpTransport: transport,
Transport: cloudprovider.GetReadOnlyCheckTransport(transport, func(req *http.Request) error {
if self.cpcfg.ReadOnly {
params, err := url.ParseQuery(req.URL.RawQuery)
if err != nil {
return errors.Wrapf(err, "ParseQuery(%s)", req.URL.RawQuery)
}
action := params.Get("Action")
for _, prefix := range []string{"Get", "List", "Describe"} {
if strings.HasPrefix(action, prefix) {
return nil
Transport: cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) {
params, err := url.ParseQuery(req.URL.RawQuery)
if err != nil {
return nil, errors.Wrapf(err, "ParseQuery(%s)", req.URL.RawQuery)
}
action := params.Get("Action")
service := strings.ToLower(params.Get("Product"))
respCheck := func(resp *http.Response) {
if self.cpcfg.UpdatePermission != nil {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
resp.Body = ioutil.NopCloser(bytes.NewBuffer(body))
obj, err := jsonutils.Parse(body)
if err != nil {
return
}
ret := struct {
AsapiErrorCode string `json:"asapiErrorCode"`
Code int
}{}
obj.Unmarshal(&ret)
if ret.Code == 403 || strings.Contains(ret.AsapiErrorCode, "NoPermission") {
self.cpcfg.UpdatePermission(service, action)
}
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
}
return nil
if self.cpcfg.ReadOnly {
for _, prefix := range []string{"Get", "List", "Describe"} {
if strings.HasPrefix(action, prefix) {
return respCheck, nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
}
return respCheck, nil
}),
},
&credentials.BaseCredential{
@@ -366,14 +390,14 @@ func (client *SApsaraClient) getOssClient(regionId string) (*oss.Client, error)
// oss use no timeout client so as to send/download large files
httpClient := client.cpcfg.AdaptiveTimeoutHttpClient()
transport, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(transport, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) {
if client.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
cliOpts := []oss.ClientOption{
oss.HTTPClient(httpClient),
+38 -20
View File
@@ -244,33 +244,51 @@ func (client *SAwsClient) getAwsSession(regionId string, assumeRole bool) (*sess
}
httpClient := client.cpcfg.AdaptiveTimeoutHttpClient()
transport, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(transport, func(req *http.Request) error {
if client.cpcfg.ReadOnly {
if req.ContentLength > 0 {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return errors.Wrapf(err, "ioutil.ReadAll")
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
params, err := url.ParseQuery(string(body))
if err != nil {
return errors.Wrapf(err, "ParseQuery(%s)", string(body))
}
action := params.Get("Action")
for _, prefix := range []string{"Get", "List", "Describe"} {
if strings.HasPrefix(action, prefix) {
return nil
httpClient.Transport = cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) {
var action string
if req.ContentLength > 0 {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, errors.Wrapf(err, "ioutil.ReadAll")
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
params, err := url.ParseQuery(string(body))
if err != nil {
return nil, errors.Wrapf(err, "ParseQuery(%s)", string(body))
}
action = params.Get("Action")
}
service := strings.Split(req.URL.Host, ".")[0]
method, path := req.Method, req.URL.Path
respCheck := func(resp *http.Response) {
if resp.StatusCode == 403 {
if client.cpcfg.UpdatePermission != nil {
if len(action) > 0 {
client.cpcfg.UpdatePermission(service, action)
} else { // s3
client.cpcfg.UpdatePermission(service, fmt.Sprintf("%s %s", method, path))
}
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
}
}
if client.cpcfg.ReadOnly {
if len(action) > 0 {
for _, prefix := range []string{"Get", "List", "Describe"} {
if strings.HasPrefix(action, prefix) {
return respCheck, nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
}
// s3
if req.Method == "GET" || req.Method == "HEAD" {
return nil
return respCheck, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return respCheck, nil
})
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(regionId),
+4 -4
View File
@@ -159,14 +159,14 @@ func (self *SAzureClient) getClient(resource TAzureResource) (*autorest.Client,
httpClient := self.cpcfg.AdaptiveTimeoutHttpClient()
transport, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(transport, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) {
if self.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
client.Sender = httpClient
+5 -5
View File
@@ -95,18 +95,18 @@ func (self *SCloudpodsClient) auth() error {
client := mcclient.NewClient(self.authURL, 0, self.debug, true, "", "")
client.SetHttpTransportProxyFunc(self.cpcfg.ProxyFunc)
ts, _ := client.GetClient().Transport.(*http.Transport)
client.SetTransport(cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
client.SetTransport(cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if self.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return nil
return nil, nil
}
// 认证
if req.Method == "POST" && req.URL.Path == "/v3/auth/tokens" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
}))
token, err := client.AuthenticateByAccessKey(self.accessKey, self.accessSecret, "cli")
if err != nil {
+4 -4
View File
@@ -91,14 +91,14 @@ type SCtyunClient struct {
func NewSCtyunClient(cfg *CtyunClientConfig) (*SCtyunClient, error) {
httpClient := cfg.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if cfg.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
client := &SCtyunClient{
CtyunClientConfig: cfg,
+16 -4
View File
@@ -140,14 +140,26 @@ func NewGoogleClient(cfg *GoogleClientConfig) (*SGoogleClient, error) {
httpClient := cfg.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
service := strings.Split(req.URL.Host, ".")[0]
if service == "www" {
service = strings.Split(req.URL.Path, "/")[0]
}
method, path := req.Method, req.URL.Path
respCheck := func(resp *http.Response) {
if resp.StatusCode == 403 {
if cfg.cpcfg.UpdatePermission != nil {
cfg.cpcfg.UpdatePermission(service, fmt.Sprintf("%s %s", method, path))
}
}
}
if cfg.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return respCheck, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return respCheck, nil
})
ctx := context.Background()
+8 -8
View File
@@ -156,14 +156,14 @@ func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client,
httpClient := self.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if self.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
cli.SetHttpClient(httpClient)
@@ -178,14 +178,14 @@ func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) {
httpClient := self.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if self.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
cli.SetHttpClient(httpClient)
+4 -4
View File
@@ -105,14 +105,14 @@ func (self *SRegion) getOBSClient() (*obs.ObsClient, error) {
client := obsClient.GetClient()
ts, _ := client.Transport.(*http.Transport)
client.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if self.client.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
self.obsClient = obsClient
+44 -26
View File
@@ -154,21 +154,33 @@ func (self *SHuaweiClient) initSigner() error {
}
func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client, error) {
cli, err := client.NewPublicCloudClientWithAccessKey(regionId, self.ownerId, self.projectId, self.accessKey, self.accessSecret, self.debug)
projectId := self.projectId
if len(regionId) == 0 {
projectId = ""
}
cli, err := client.NewPublicCloudClientWithAccessKey(regionId, self.ownerId, projectId, self.accessKey, self.accessSecret, self.debug)
if err != nil {
return nil, err
}
httpClient := self.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
service, method, path := strings.Split(req.URL.Host, ".")[0], req.Method, req.URL.Path
respCheck := func(resp *http.Response) {
if resp.StatusCode == 403 {
if self.cpcfg.UpdatePermission != nil {
self.cpcfg.UpdatePermission(service, fmt.Sprintf("%s %s", method, path))
}
}
}
if self.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return respCheck, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return respCheck, nil
})
cli.SetHttpClient(httpClient)
@@ -176,25 +188,7 @@ func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client,
}
func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) {
cli, err := client.NewPublicCloudClientWithAccessKey("", self.ownerId, "", self.accessKey, self.accessSecret, self.debug)
if err != nil {
return nil, err
}
httpClient := self.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
if self.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
})
cli.SetHttpClient(httpClient)
return cli, nil
return self.newRegionAPIClient("")
}
func (self *SHuaweiClient) fetchRegions() error {
@@ -271,9 +265,33 @@ func getOBSEndpoint(regionId string) string {
return fmt.Sprintf("obs.%s.myhuaweicloud.com", regionId)
}
func (client *SHuaweiClient) getOBSClient(regionId string) (*obs.ObsClient, error) {
func (self *SHuaweiClient) getOBSClient(regionId string) (*obs.ObsClient, error) {
endpoint := getOBSEndpoint(regionId)
return obs.New(client.accessKey, client.accessSecret, endpoint)
cli, err := obs.New(self.accessKey, self.accessSecret, endpoint)
if err != nil {
return nil, err
}
client := cli.GetClient()
ts, _ := client.Transport.(*http.Transport)
client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
method, path := req.Method, req.URL.Path
respCheck := func(resp *http.Response) {
if resp.StatusCode == 403 {
if self.cpcfg.UpdatePermission != nil {
self.cpcfg.UpdatePermission("obs", fmt.Sprintf("%s %s", method, path))
}
}
}
if self.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return respCheck, nil
}
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return respCheck, nil
})
return cli, nil
}
func (self *SHuaweiClient) fetchBuckets() error {
-13
View File
@@ -16,7 +16,6 @@ package huawei
import (
"fmt"
"net/http"
"strings"
"time"
@@ -100,18 +99,6 @@ func (self *SRegion) getOBSClient() (*obs.ObsClient, error) {
return nil, err
}
client := obsClient.GetClient()
ts, _ := client.Transport.(*http.Transport)
client.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
if self.client.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
})
self.obsClient = obsClient
}
+4 -4
View File
@@ -133,14 +133,14 @@ func (cli *SNutanixClient) getDefaultClient(timeout time.Duration) *http.Client
httputils.SetClientProxyFunc(client, proxy)
ts, _ := client.Transport.(*http.Transport)
client.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if cli.cpcfg.ReadOnly {
if req.Method == "GET" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
return client
+5 -5
View File
@@ -425,18 +425,18 @@ func (cli *SOpenStackClient) getDefaultClient() *mcclient.Client {
client.SetHttpTransportProxyFunc(cli.cpcfg.ProxyFunc)
_client := client.GetClient()
ts, _ := _client.Transport.(*http.Transport)
_client.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
_client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if cli.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return nil
return nil, nil
}
// 认证
if req.Method == "POST" && strings.HasSuffix(req.URL.Path, "auth/tokens") {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
return client
+32 -18
View File
@@ -611,26 +611,32 @@ func (client *SQcloudClient) getSdkClient(regionId string) (*common.Client, erro
}
httpClient := client.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
cli.WithHttpTransport(cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
cli.WithHttpTransport(cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, errors.Wrapf(err, "ioutil.ReadAll")
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
params, err := url.ParseQuery(string(body))
if err != nil {
return nil, errors.Wrapf(err, "ParseQuery(%s)", string(body))
}
service := strings.Split(req.URL.Host, ".")[0]
action := params.Get("Action")
respCheck := func(resp *http.Response) {
if client.cpcfg.UpdatePermission != nil {
client.cpcfg.UpdatePermission(service, action)
}
}
if client.cpcfg.ReadOnly {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return errors.Wrapf(err, "ioutil.ReadAll")
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
params, err := url.ParseQuery(string(body))
if err != nil {
return errors.Wrapf(err, "ParseQuery(%s)", string(body))
}
action := params.Get("Action")
for _, prefix := range []string{"Get", "List", "Describe"} {
if strings.HasPrefix(action, prefix) {
return nil
return respCheck, nil
}
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
}
return nil
return respCheck, nil
}))
return cli, nil
}
@@ -907,14 +913,22 @@ func (client *SQcloudClient) getCosClient(bucket *SBucket) (*cos.Client, error)
RequestBody: client.debug,
ResponseHeader: client.debug,
ResponseBody: client.debug,
Transport: cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
Transport: cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
method, path := req.Method, req.URL.Path
respCheck := func(resp *http.Response) {
if resp.StatusCode == 403 {
if client.cpcfg.UpdatePermission != nil {
client.cpcfg.UpdatePermission("cos", fmt.Sprintf("%s %s", method, path))
}
}
}
if client.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return nil
return respCheck, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s", req.Method, req.URL.Path)
}
return nil
return respCheck, nil
}),
},
},
+7 -7
View File
@@ -106,31 +106,31 @@ type SUcloudClient struct {
func NewUcloudClient(cfg *UcloudClientConfig) (*SUcloudClient, error) {
httpClient := cfg.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if cfg.cpcfg.ReadOnly {
if req.ContentLength > 0 {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return errors.Wrapf(err, "ioutil.ReadAll")
return nil, errors.Wrapf(err, "ioutil.ReadAll")
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
obj, err := jsonutils.Parse(body)
if err != nil {
return errors.Wrapf(err, "Parse request body")
return nil, errors.Wrapf(err, "Parse request body")
}
action, err := obj.GetString("Action")
if err != nil {
return errors.Wrapf(err, "Get request action")
return nil, errors.Wrapf(err, "Get request action")
}
for _, prefix := range []string{"Get", "Describe", "List"} {
if strings.HasPrefix(action, prefix) {
return nil
return nil, nil
}
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
}
return nil
return nil, nil
})
client := SUcloudClient{
UcloudClientConfig: cfg,
+5 -5
View File
@@ -107,18 +107,18 @@ func getSignUrl(uri string) (string, error) {
func NewZStackClient(cfg *ZstackClientConfig) (*SZStackClient, error) {
httpClient := cfg.cpcfg.AdaptiveTimeoutHttpClient()
ts, _ := httpClient.Transport.(*http.Transport)
httpClient.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
if cfg.cpcfg.ReadOnly {
if req.Method == "GET" || req.Method == "HEAD" {
return nil
return nil, nil
}
// 认证
if req.Method == "PUT" && req.URL.Path == "/zstack/v1/accounts/login" {
return nil
return nil, nil
}
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
}
return nil
return nil, nil
})
cli := &SZStackClient{