mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #13922 from ioito/hotfix/qx-account-read-only
fix(region): account read only
This commit is contained in:
@@ -153,7 +153,7 @@ require (
|
||||
yunion.io/x/jsonutils v0.0.0-20220106020632-953b71a4c3a8
|
||||
yunion.io/x/log v0.0.0-20201210064738-43181789dc74
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
|
||||
yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38
|
||||
yunion.io/x/pkg v0.0.0-20220406030238-39fbc60d5d4e
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
|
||||
yunion.io/x/sqlchemy v0.0.0-20220405074102-7b815a97eb67
|
||||
yunion.io/x/structarg v0.0.0-20220312084958-9c6c79c7d1c6
|
||||
|
||||
@@ -994,8 +994,8 @@ yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7/go.mod h1:0vLkNEhlmA64HViPB
|
||||
yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20200814072949-4f1b541857d6/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38 h1:QV3gVskJfi1J0e5kTs4oTx8D+Mc0JFik3Qe6c1PgO90=
|
||||
yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20220406030238-39fbc60d5d4e h1:ovxSHuAa8hOBiZPU+ezrwqmVuCN7QTNx0sRRDGMaAkY=
|
||||
yunion.io/x/pkg v0.0.0-20220406030238-39fbc60d5d4e/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
|
||||
yunion.io/x/sqlchemy v0.0.0-20220405074102-7b815a97eb67 h1:vZiiB5oc6wqEvr1UNmJPFCX3FmLznZbvoUZ90ONgAcE=
|
||||
|
||||
@@ -207,6 +207,8 @@ type CloudaccountCreateInput struct {
|
||||
|
||||
// swagger:ignore
|
||||
SubAccounts *cloudprovider.SubAccounts
|
||||
|
||||
ReadOnly bool `json:"read_only"`
|
||||
}
|
||||
|
||||
type CloudaccountShareModeInput struct {
|
||||
@@ -339,6 +341,8 @@ type CloudaccountUpdateInput struct {
|
||||
|
||||
// 临时清除缺失的权限提示,云账号权限缺失依然会自动刷新
|
||||
CleanLakeOfPermissions bool `json:"clean_lake_of_permissions"`
|
||||
|
||||
ReadOnly bool `json:"read_only"`
|
||||
}
|
||||
|
||||
type CloudaccountPerformPublicInput struct {
|
||||
|
||||
@@ -138,6 +138,8 @@ type CloudproviderDetails struct {
|
||||
// 子订阅品牌信息
|
||||
Brand string `json:"brand"`
|
||||
|
||||
ReadOnly bool `json:"read_only"`
|
||||
|
||||
ProjectMappingResourceInfo
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@ type SCloudaccount struct {
|
||||
SAMLAuth tristate.TriState `list:"domain" default:"false"`
|
||||
|
||||
AccessUrl string `width:"64" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
|
||||
|
||||
ReadOnly bool `default:"false" create:"domain_optional" list:"domain" update:"domain"`
|
||||
}
|
||||
|
||||
func (manager *SCloudaccountManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
|
||||
@@ -395,6 +397,7 @@ func (self *SCloudaccount) syncWithICloudaccount(ctx context.Context, userCred m
|
||||
self.SAMLAuth = account.SAMLAuth
|
||||
self.AccountId = account.AccountId
|
||||
self.AccessUrl = account.AccessUrl
|
||||
self.ReadOnly = account.ReadOnly
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -481,6 +484,8 @@ type SCloudDelegate struct {
|
||||
Provider string
|
||||
Brand string
|
||||
|
||||
ReadOnly bool
|
||||
|
||||
Options struct {
|
||||
cloudprovider.SHCSOEndpoints
|
||||
cloudprovider.SApsaraEndpoints
|
||||
@@ -570,6 +575,8 @@ func (account *SCloudDelegate) GetProvider() (cloudprovider.ICloudProvider, erro
|
||||
Secret: passwd,
|
||||
ProxyFunc: proxyFunc,
|
||||
|
||||
ReadOnly: account.ReadOnly,
|
||||
|
||||
DefaultRegion: defaultRegion,
|
||||
Options: options.(*jsonutils.JSONDict),
|
||||
|
||||
|
||||
@@ -166,6 +166,8 @@ type ProviderConfig struct {
|
||||
Account string
|
||||
Secret string
|
||||
|
||||
ReadOnly bool
|
||||
|
||||
AccountId string
|
||||
|
||||
Options *jsonutils.JSONDict
|
||||
|
||||
@@ -29,12 +29,13 @@ const (
|
||||
CloudVMStatusDeploying = "deploying"
|
||||
CloudVMStatusOther = "other"
|
||||
|
||||
ErrNotFound = errors.ErrNotFound
|
||||
ErrDuplicateId = errors.ErrDuplicateId
|
||||
ErrInvalidStatus = errors.ErrInvalidStatus
|
||||
ErrTimeout = errors.ErrTimeout
|
||||
ErrNotImplemented = errors.ErrNotImplemented
|
||||
ErrNotSupported = errors.ErrNotSupported
|
||||
ErrNotFound = errors.ErrNotFound
|
||||
ErrDuplicateId = errors.ErrDuplicateId
|
||||
ErrInvalidStatus = errors.ErrInvalidStatus
|
||||
ErrTimeout = errors.ErrTimeout
|
||||
ErrNotImplemented = errors.ErrNotImplemented
|
||||
ErrNotSupported = errors.ErrNotSupported
|
||||
ErrAccountReadOnly = errors.ErrAccountReadOnly
|
||||
|
||||
ErrInvalidProvider = httperrors.ErrInvalidProvider
|
||||
ErrNoBalancePermission = httperrors.ErrNoBalancePermission
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cloudprovider
|
||||
|
||||
import "net/http"
|
||||
|
||||
type transport struct {
|
||||
readOnlyCheck func(req *http.Request) error
|
||||
ts *http.Transport
|
||||
}
|
||||
|
||||
func (self *transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
err := self.readOnlyCheck(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.ts.RoundTrip(req)
|
||||
}
|
||||
|
||||
func GetReadOnlyCheckTransport(ts *http.Transport, check func(req *http.Request) error) http.RoundTripper {
|
||||
ret := &transport{ts: ts, readOnlyCheck: check}
|
||||
return ret
|
||||
}
|
||||
@@ -166,6 +166,8 @@ type SCloudaccount struct {
|
||||
|
||||
SProjectMappingResourceBase
|
||||
|
||||
ReadOnly bool `default:"false" create:"domain_optional" list:"domain" update:"domain"`
|
||||
|
||||
// 设置允许同步的账号及订阅
|
||||
SubAccounts *cloudprovider.SubAccounts `nullable:"true" get:"user" create:"optional"`
|
||||
|
||||
@@ -991,6 +993,8 @@ func (self *SCloudaccount) getProviderInternal(ctx context.Context) (cloudprovid
|
||||
DefaultRegion: defaultRegion,
|
||||
ProxyFunc: self.proxyFunc(),
|
||||
|
||||
ReadOnly: self.ReadOnly,
|
||||
|
||||
UpdatePermission: self.UpdatePermission(ctx),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -870,6 +870,8 @@ func (self *SCloudprovider) GetProvider(ctx context.Context) (cloudprovider.IClo
|
||||
Secret: passwd,
|
||||
ProxyFunc: account.proxyFunc(),
|
||||
|
||||
ReadOnly: account.ReadOnly,
|
||||
|
||||
DefaultRegion: defaultRegion,
|
||||
Options: account.Options,
|
||||
|
||||
@@ -1015,6 +1017,7 @@ func (manager *SCloudproviderManager) FetchCustomizeColumns(
|
||||
for i := range rows {
|
||||
if account, ok := accounts[accountIds[i]]; ok {
|
||||
rows[i].Cloudaccount = account.Name
|
||||
rows[i].ReadOnly = account.ReadOnly
|
||||
rows[i].Brand = account.Brand
|
||||
|
||||
ps := &rows[i].ProxySetting
|
||||
|
||||
@@ -98,6 +98,14 @@ func (this *Client) SetHttpTransportProxyFunc(proxyFunc httputils.TransportProxy
|
||||
httputils.SetClientProxyFunc(this.httpconn, proxyFunc)
|
||||
}
|
||||
|
||||
func (this *Client) GetClient() *http.Client {
|
||||
return this.httpconn
|
||||
}
|
||||
|
||||
func (this *Client) SetTransport(ts http.RoundTripper) {
|
||||
this.httpconn.Transport = ts
|
||||
}
|
||||
|
||||
func (this *Client) SetDebug(debug bool) {
|
||||
this.debug = debug
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ type SCloudAccountCreateBaseOptions struct {
|
||||
ProxySetting string `help:"proxy setting id or name" json:"proxy_setting"`
|
||||
DryRun bool `help:"test create cloudaccount params"`
|
||||
ShowSubAccounts bool `help:"test and show subaccount info"`
|
||||
ReadOnly bool `help:"Read only account"`
|
||||
}
|
||||
|
||||
type SVMwareCloudAccountCreateOptions struct {
|
||||
@@ -560,6 +561,8 @@ type SCloudAccountUpdateBaseOptions struct {
|
||||
ProxySetting string `help:"proxy setting name or id" json:"proxy_setting"`
|
||||
SamlAuth string `help:"Enable or disable saml auth" choices:"true|false"`
|
||||
|
||||
ReadOnly *bool `help:"is account read only" negative:"no_read_only"`
|
||||
|
||||
CleanLakeOfPermissions bool `help:"clean lake of permissions"`
|
||||
|
||||
Desc string `help:"Description" json:"description" token:"desc"`
|
||||
|
||||
@@ -16,6 +16,8 @@ package aliyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -406,6 +408,22 @@ 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
|
||||
}
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
&credentials.BaseCredential{
|
||||
AccessKeyId: self.accessKey,
|
||||
@@ -512,6 +530,16 @@ func (client *SAliyunClient) getOssClientByEndpoint(endpoint string) (*oss.Clien
|
||||
// https_proxy setting
|
||||
// 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
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.RawPath)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
cliOpts := []oss.ClientOption{
|
||||
oss.HTTPClient(httpClient),
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ package apsara
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -277,6 +279,22 @@ 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
|
||||
}
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
&credentials.BaseCredential{
|
||||
AccessKeyId: self.accessKey,
|
||||
@@ -347,6 +365,16 @@ func (client *SApsaraClient) getOssClient(regionId string) (*oss.Client, error)
|
||||
// https_proxy setting
|
||||
// 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
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
cliOpts := []oss.ClientOption{
|
||||
oss.HTTPClient(httpClient),
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -239,6 +243,35 @@ func (client *SAwsClient) getAwsSession(regionId string, assumeRole bool) (*sess
|
||||
return sess, nil
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
|
||||
}
|
||||
// s3
|
||||
if req.Method == "GET" || req.Method == "HEAD" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
s, err := session.NewSession(&sdk.Config{
|
||||
Region: sdk.String(regionId),
|
||||
Credentials: credentials.NewStaticCredentials(
|
||||
|
||||
@@ -158,6 +158,16 @@ 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 {
|
||||
if self.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
client.Sender = httpClient
|
||||
|
||||
self.env = env
|
||||
|
||||
@@ -211,6 +211,13 @@ func (e sBingoError) Error() string {
|
||||
}
|
||||
|
||||
func (self *SBingoCloudClient) invoke(action string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
if self.cpcfg.ReadOnly {
|
||||
for _, prefix := range []string{"Get", "List", "Describe"} {
|
||||
if strings.HasPrefix(action, prefix) {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
|
||||
}
|
||||
}
|
||||
}
|
||||
var encode = func(k, v string) string {
|
||||
d := url.Values{}
|
||||
d.Set(k, v)
|
||||
|
||||
@@ -16,6 +16,7 @@ package cloudpods
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -93,6 +94,20 @@ type SCloudpodsClient struct {
|
||||
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 {
|
||||
if self.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" || req.Method == "HEAD" {
|
||||
return nil
|
||||
}
|
||||
// 认证
|
||||
if req.Method == "POST" && req.URL.Path == "/v3/auth/tokens" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
token, err := client.AuthenticateByAccessKey(self.accessKey, self.accessSecret, "cli")
|
||||
if err != nil {
|
||||
if errors.Cause(err) == httperrors.ErrUnauthorized {
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -89,6 +90,16 @@ 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 {
|
||||
if cfg.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
client := &SCtyunClient{
|
||||
CtyunClientConfig: cfg,
|
||||
httpClient: httpClient,
|
||||
|
||||
@@ -139,6 +139,17 @@ 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 {
|
||||
if cfg.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package hcso
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -166,6 +167,16 @@ 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 {
|
||||
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
|
||||
|
||||
@@ -16,6 +16,7 @@ package hcso
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -102,6 +103,18 @@ 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
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -171,6 +172,16 @@ 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 {
|
||||
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
|
||||
|
||||
@@ -41,6 +41,10 @@ type ObsClient struct {
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
func (self *ObsClient) GetClient() *http.Client {
|
||||
return self.httpClient
|
||||
}
|
||||
|
||||
func New(ak, sk, endpoint string, configurers ...configurer) (*ObsClient, error) {
|
||||
conf := &config{securityProvider: &securityProvider{ak: ak, sk: sk}, endpoint: endpoint}
|
||||
conf.maxRetryCount = -1
|
||||
|
||||
@@ -16,6 +16,7 @@ package huawei
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -99,6 +100,18 @@ 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
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,18 @@ func (cli *SNutanixClient) getDefaultClient(timeout time.Duration) *http.Client
|
||||
return nil, nil
|
||||
}
|
||||
httputils.SetClientProxyFunc(client, proxy)
|
||||
|
||||
ts, _ := client.Transport.(*http.Transport)
|
||||
client.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
|
||||
if cli.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
|
||||
@@ -423,6 +423,22 @@ func (cli *SOpenStackClient) getDefaultSession(regionName string) *mcclient.Clie
|
||||
func (cli *SOpenStackClient) getDefaultClient() *mcclient.Client {
|
||||
client := mcclient.NewClient(cli.authURL, 5, cli.debug, false, "", "")
|
||||
client.SetHttpTransportProxyFunc(cli.cpcfg.ProxyFunc)
|
||||
_client := client.GetClient()
|
||||
ts, _ := _client.Transport.(*http.Transport)
|
||||
_client.Transport = cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
|
||||
if cli.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" || req.Method == "HEAD" {
|
||||
return nil
|
||||
}
|
||||
// 认证
|
||||
if req.Method == "POST" && strings.HasSuffix(req.URL.Path, "auth/tokens") {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -608,7 +610,28 @@ func (client *SQcloudClient) getSdkClient(regionId string) (*common.Client, erro
|
||||
return nil, err
|
||||
}
|
||||
httpClient := client.cpcfg.AdaptiveTimeoutHttpClient()
|
||||
cli.WithHttpTransport(httpClient.Transport)
|
||||
ts, _ := httpClient.Transport.(*http.Transport)
|
||||
cli.WithHttpTransport(cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
|
||||
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 errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
@@ -870,6 +893,9 @@ func (client *SQcloudClient) getCosClient(bucket *SBucket) (*cos.Client, error)
|
||||
BucketURL: u,
|
||||
}
|
||||
}
|
||||
ts := &http.Transport{
|
||||
Proxy: client.cpcfg.ProxyFunc,
|
||||
}
|
||||
cosClient := cos.NewClient(
|
||||
baseUrl,
|
||||
&http.Client{
|
||||
@@ -881,9 +907,15 @@ func (client *SQcloudClient) getCosClient(bucket *SBucket) (*cos.Client, error)
|
||||
RequestBody: client.debug,
|
||||
ResponseHeader: client.debug,
|
||||
ResponseBody: client.debug,
|
||||
Transport: &http.Transport{
|
||||
Proxy: client.cpcfg.ProxyFunc,
|
||||
},
|
||||
Transport: cloudprovider.GetReadOnlyCheckTransport(ts, func(req *http.Request) error {
|
||||
if client.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" || req.Method == "HEAD" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -19,6 +19,9 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
func unmarshalResult(resp jsonutils.JSONObject, respErr error, resultKey string, result interface{}) error {
|
||||
@@ -76,6 +79,9 @@ func doListPart(client *SUcloudClient, action string, params SParams, resultKey
|
||||
|
||||
// 执行操作
|
||||
func DoAction(client *SUcloudClient, action string, params SParams, resultKey string, result interface{}) error {
|
||||
if client.cpcfg.ReadOnly {
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, action)
|
||||
}
|
||||
params.SetAction(action)
|
||||
resp, err := jsonRequest(client, params)
|
||||
return unmarshalResult(resp, err, resultKey, result)
|
||||
|
||||
@@ -106,6 +106,21 @@ 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 {
|
||||
if cfg.cpcfg.ReadOnly {
|
||||
if req.Method == "GET" || req.Method == "HEAD" {
|
||||
return nil
|
||||
}
|
||||
// 认证
|
||||
if req.Method == "PUT" && req.URL.Path == "/zstack/v1/accounts/login" {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
cli := &SZStackClient{
|
||||
ZstackClientConfig: cfg,
|
||||
httpClient: httpClient,
|
||||
|
||||
Vendored
+1
-1
@@ -1231,7 +1231,7 @@ yunion.io/x/log/hooks
|
||||
yunion.io/x/ovsdb/cli_util
|
||||
yunion.io/x/ovsdb/schema/ovn_nb
|
||||
yunion.io/x/ovsdb/types
|
||||
# yunion.io/x/pkg v0.0.0-20220227083757-28690b33ce38
|
||||
# yunion.io/x/pkg v0.0.0-20220406030238-39fbc60d5d4e
|
||||
yunion.io/x/pkg/errors
|
||||
yunion.io/x/pkg/gotypes
|
||||
yunion.io/x/pkg/prettytable
|
||||
|
||||
+7
-5
@@ -10,13 +10,15 @@ const (
|
||||
ErrEOF = Error("EOFError")
|
||||
ErrNetwork = Error("NetworkError")
|
||||
ErrConnectRefused = Error("ConnectRefusedError")
|
||||
ErrConnectReset = Error("ConnectResetError")
|
||||
ErrTimeout = Error("TimeoutError")
|
||||
|
||||
ErrNotFound = Error("NotFoundError")
|
||||
ErrDuplicateId = Error("DuplicateIdError")
|
||||
ErrInvalidStatus = Error("InvalidStatusError")
|
||||
ErrNotImplemented = Error("NotImplementedError")
|
||||
ErrNotSupported = Error("NotSupportedError")
|
||||
ErrNotFound = Error("NotFoundError")
|
||||
ErrDuplicateId = Error("DuplicateIdError")
|
||||
ErrInvalidStatus = Error("InvalidStatusError")
|
||||
ErrNotImplemented = Error("NotImplementedError")
|
||||
ErrNotSupported = Error("NotSupportedError")
|
||||
ErrAccountReadOnly = Error("AccountReadOnlyError")
|
||||
|
||||
ErrAggregate = Error("AggregateError")
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user