diff --git a/pkg/apis/cloudcommon/proxy/proxy.go b/pkg/apis/cloudcommon/proxy/proxy.go index 3cc57c627d..49d3119f86 100644 --- a/pkg/apis/cloudcommon/proxy/proxy.go +++ b/pkg/apis/cloudcommon/proxy/proxy.go @@ -13,20 +13,16 @@ const ( type ProxySettingCreateInput struct { apis.StandaloneResourceCreateInput - HttpProxy string - HttpsProxy string - NoProxy string + ProxySetting } type ProxySettingUpdateInput struct { - HttpProxy string - HttpsProxy string - NoProxy string - // 资源名称 Name string `json:"name"` // 资源描述 Description string `json:"description"` + + ProxySetting } // String implements ISerializable interface diff --git a/pkg/apis/cloudcommon/proxy/setting.go b/pkg/apis/cloudcommon/proxy/setting.go new file mode 100644 index 0000000000..14935acfb2 --- /dev/null +++ b/pkg/apis/cloudcommon/proxy/setting.go @@ -0,0 +1,111 @@ +package proxy + +import ( + "fmt" + "net" + "net/url" + "strings" + + "yunion.io/x/pkg/errors" +) + +type ProxySetting struct { + HttpProxy string + HttpsProxy string + NoProxy string +} + +func (v *ProxySetting) Sanitize() error { + v.HttpProxy = strings.TrimSpace(v.HttpProxy) + if u, err := parseProxy(v.HttpProxy); err != nil { + return errors.Wrap(err, "invalid https_proxy url") + } else { + v.HttpProxy = u.String() + } + + v.HttpsProxy = strings.TrimSpace(v.HttpsProxy) + if u, err := parseProxy(v.HttpsProxy); err != nil { + return errors.Wrap(err, "invalid http_proxy url") + } else { + v.HttpsProxy = u.String() + } + + if noProxy, err := parseNoProxy(v.NoProxy); err == nil { + v.NoProxy = strings.Join(noProxy, ",") + } else { + return errors.Wrap(err, "invalid no_proxy") + } + return nil +} + +func parseProxy(proxy string) (*url.URL, error) { + if proxy == "" { + return nil, nil + } + + proxyURL, err := url.Parse(proxy) + if err != nil || + (proxyURL.Scheme != "http" && + proxyURL.Scheme != "https" && + proxyURL.Scheme != "socks5") { + // proxy was bogus. Try prepending "http://" to it and + // see if that parses correctly. If not, we fall + // through and complain about the original one. + if proxyURL, err := url.Parse("http://" + proxy); err == nil { + return proxyURL, nil + } + } + if err != nil { + return nil, errors.Wrapf(err, "invalid proxy address %q", proxy) + } + return proxyURL, nil +} + +func parseNoProxy(noProxy string) ([]string, error) { + var r []string + for _, p := range strings.Split(noProxy, ",") { + p = strings.ToLower(strings.TrimSpace(p)) + if len(p) == 0 { + continue + } + + if p == "*" { + r = append(r, p) + // let it go + //return r, nil + } + + // IPv4/CIDR, IPv6/CIDR + if _, _, err := net.ParseCIDR(p); err == nil { + r = append(r, p) + continue + } + + // IPv4:port, [IPv6]:port + phost, _, err := net.SplitHostPort(p) + if err == nil { + if len(phost) == 0 { + // There is no host part, likely the entry is malformed; ignore. + return nil, fmt.Errorf("host part must not be empty: %s", p) + } + if phost[0] == '[' && phost[len(phost)-1] == ']' { + phost = phost[1 : len(phost)-1] + } + } else { + phost = p + } + // IPv4, IPv6 + if pip := net.ParseIP(phost); pip != nil { + r = append(r, p) + continue + } + + if len(phost) == 0 { + // There is no host part, likely the entry is malformed; ignore. + continue + } + + r = append(r, p) + } + return r, nil +} diff --git a/pkg/apis/compute/cloudaccount.go b/pkg/apis/compute/cloudaccount.go index 343746ceac..05579df1e3 100644 --- a/pkg/apis/compute/cloudaccount.go +++ b/pkg/apis/compute/cloudaccount.go @@ -19,6 +19,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/apis" + proxyapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/proxy" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" ) @@ -180,4 +181,6 @@ type CloudaccountDetail struct { // 存储缓存数量 // example: 10 StoragecacheCount int `json:"storagecache_count,allowempty"` + + ProxySetting proxyapi.SProxySetting `json:"proxy_setting"` } diff --git a/pkg/cloudcommon/db/proxy/proxysetting.go b/pkg/cloudcommon/db/proxy/proxysetting.go index 900ab4e3a7..6320127b32 100644 --- a/pkg/cloudcommon/db/proxy/proxysetting.go +++ b/pkg/cloudcommon/db/proxy/proxysetting.go @@ -46,6 +46,9 @@ type SProxySetting struct { } func (man *SProxySettingManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data proxyapi.ProxySettingCreateInput) (proxyapi.ProxySettingCreateInput, error) { + if err := data.ProxySetting.Sanitize(); err != nil { + return data, httperrors.NewInputParameterError("%s", err) + } return data, nil } @@ -58,6 +61,9 @@ func (ps *SProxySetting) ValidateUpdateData(ctx context.Context, userCred mcclie if ps.Id == proxyapi.ProxySettingId_DIRECT { return data, httperrors.NewConflictError("DIRECT setting cannot be changed") } + if err := data.ProxySetting.Sanitize(); err != nil { + return data, httperrors.NewInputParameterError("%s", err) + } return data, nil } @@ -74,6 +80,9 @@ func (ps *SProxySetting) HttpTransportProxyFunc() httputils.TransportProxyFunc { } func (ps *SProxySetting) ValidateDeleteCondition(ctx context.Context) error { + if ps.Id == proxyapi.ProxySettingId_DIRECT { + return httperrors.NewConflictError("DIRECT setting cannot be deleted") + } for _, man := range referrersMen { t := man.TableSpec().Instance() n, err := t.Query(). diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index 4b70ef3777..4799238dde 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -1714,6 +1714,33 @@ func (manager *SCloudaccountManager) FetchCustomizeColumns(ctx context.Context, } } } + proxySettings := make(map[string]proxy.SProxySetting) + { + proxySettingIds := make([]string, len(objs)) + for i := range objs { + proxySettingId := objs[i].(*SCloudaccount).ProxySettingId + if !utils.IsInStringArray(proxySettingId, proxySettingIds) { + proxySettingIds = append(proxySettingIds, proxySettingId) + } + } + q := proxy.ProxySettingManager.Query().In("id", proxySettingIds) + r := []proxy.SProxySetting{} + if err := db.FetchModelObjects(proxy.ProxySettingManager, q, &r); err != nil { + log.Errorf("FetchModelObjects (%s) fail %s", + proxy.ProxySettingManager.KeywordPlural(), err) + return rows + } + for i := range r { + proxySetting := r[i] + proxySettings[proxySetting.Id] = proxySetting + } + } + for i := range rows { + account := objs[i].(*SCloudaccount) + if proxySetting, ok := proxySettings[account.ProxySettingId]; ok { + rows[i].Set("proxy_setting", jsonutils.Marshal(proxySetting)) + } + } return rows }