proxysetting.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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. package proxy
  15. import (
  16. "context"
  17. "database/sql"
  18. "fmt"
  19. "net"
  20. "net/http"
  21. "net/url"
  22. "time"
  23. "golang.org/x/net/http/httpproxy"
  24. "yunion.io/x/jsonutils"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/util/httputils"
  27. "yunion.io/x/pkg/util/rbacscope"
  28. proxyapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/proxy"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  30. "yunion.io/x/onecloud/pkg/httperrors"
  31. "yunion.io/x/onecloud/pkg/mcclient"
  32. "yunion.io/x/onecloud/pkg/util/ctx"
  33. )
  34. type SProxySettingManager struct {
  35. db.SInfrasResourceBaseManager
  36. }
  37. var ProxySettingManager *SProxySettingManager
  38. func init() {
  39. ProxySettingManager = &SProxySettingManager{
  40. SInfrasResourceBaseManager: db.NewInfrasResourceBaseManager(
  41. SProxySetting{},
  42. "proxysettings_tbl",
  43. "proxysetting",
  44. "proxysettings",
  45. ),
  46. }
  47. ProxySettingManager.SetVirtualObject(ProxySettingManager)
  48. }
  49. type SProxySetting struct {
  50. db.SInfrasResourceBase
  51. HTTPProxy string `create:"domain_optional" list:"domain" update:"domain"`
  52. HTTPSProxy string `create:"domain_optional" list:"domain" update:"domain"`
  53. NoProxy string `create:"domain_optional" list:"domain" update:"domain"`
  54. }
  55. func (man *SProxySettingManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data proxyapi.ProxySettingCreateInput) (proxyapi.ProxySettingCreateInput, error) {
  56. var err error
  57. if err := data.ProxySetting.Sanitize(); err != nil {
  58. return data, httperrors.NewInputParameterError("%s", err)
  59. }
  60. data.InfrasResourceBaseCreateInput, err = man.SInfrasResourceBaseManager.ValidateCreateData(
  61. ctx,
  62. userCred,
  63. ownerId,
  64. query,
  65. data.InfrasResourceBaseCreateInput,
  66. )
  67. return data, err
  68. }
  69. func (ps *SProxySetting) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data proxyapi.ProxySettingUpdateInput) (proxyapi.ProxySettingUpdateInput, error) {
  70. if ps.Id == proxyapi.ProxySettingId_DIRECT {
  71. return data, httperrors.NewConflictError("DIRECT setting cannot be changed")
  72. }
  73. var err error
  74. if err := data.ProxySetting.Sanitize(); err != nil {
  75. return data, httperrors.NewInputParameterError("%s", err)
  76. }
  77. data.InfrasResourceBaseUpdateInput, err = ps.SInfrasResourceBase.ValidateUpdateData(
  78. ctx,
  79. userCred,
  80. query,
  81. data.InfrasResourceBaseUpdateInput,
  82. )
  83. return data, err
  84. }
  85. func (ps *SProxySetting) HttpTransportProxyFunc() httputils.TransportProxyFunc {
  86. cfg := &httpproxy.Config{
  87. HTTPProxy: ps.HTTPProxy,
  88. HTTPSProxy: ps.HTTPSProxy,
  89. NoProxy: ps.NoProxy,
  90. }
  91. proxyFunc := cfg.ProxyFunc()
  92. return func(req *http.Request) (*url.URL, error) {
  93. return proxyFunc(req.URL)
  94. }
  95. }
  96. func (ps *SProxySetting) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  97. if ps.Id == proxyapi.ProxySettingId_DIRECT {
  98. return httperrors.NewConflictError("DIRECT setting cannot be deleted")
  99. }
  100. for _, man := range referrersMen {
  101. n, err := man.Query().
  102. Equals("proxy_setting_id", ps.Id).
  103. CountWithError()
  104. if err != nil {
  105. return httperrors.NewInternalServerError("get proxysetting refcount fail %s", err)
  106. }
  107. if n > 0 {
  108. return httperrors.NewResourceBusyError("proxysetting %s is still referred to by %d %s",
  109. ps.Id, n, man.KeywordPlural())
  110. }
  111. }
  112. return ps.SInfrasResourceBase.ValidateDeleteCondition(ctx, nil)
  113. }
  114. func (man *SProxySettingManager) test(ctx context.Context, urls map[string]string) (jsonutils.JSONObject, error) {
  115. type TestURLResult struct {
  116. Ok bool `json:"ok"`
  117. Reason string `json:"reason"`
  118. }
  119. r := map[string]TestURLResult{}
  120. for k, v := range urls {
  121. if v == "" {
  122. r[k] = TestURLResult{Ok: true}
  123. continue
  124. }
  125. u, err := url.Parse(v)
  126. if err != nil {
  127. r[k] = TestURLResult{
  128. Reason: err.Error(),
  129. }
  130. } else if u == nil {
  131. r[k] = TestURLResult{
  132. Reason: fmt.Sprintf("bad url: %q", v),
  133. }
  134. } else {
  135. host := u.Hostname()
  136. port := u.Port()
  137. if port == "" {
  138. switch u.Scheme {
  139. case "http":
  140. port = "80"
  141. case "https":
  142. port = "443"
  143. case "socks5":
  144. port = "1080"
  145. default:
  146. r[k] = TestURLResult{
  147. Reason: fmt.Sprintf("bad url scheme: %s", u.Scheme),
  148. }
  149. continue
  150. }
  151. }
  152. addr := net.JoinHostPort(host, port)
  153. conn, err := net.DialTimeout("tcp", addr, 7*time.Second)
  154. if err != nil {
  155. r[k] = TestURLResult{
  156. Reason: err.Error(),
  157. }
  158. } else {
  159. r[k] = TestURLResult{Ok: true}
  160. conn.Close()
  161. }
  162. }
  163. }
  164. return jsonutils.Marshal(r), nil
  165. }
  166. func (ps *SProxySetting) PerformTest(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  167. urls := map[string]string{
  168. "http_proxy": ps.HTTPProxy,
  169. "https_proxy": ps.HTTPSProxy,
  170. }
  171. return ProxySettingManager.test(ctx, urls)
  172. }
  173. func (man *SProxySettingManager) PerformTest(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data proxyapi.ProxySettingTestInput) (jsonutils.JSONObject, error) {
  174. urls := map[string]string{
  175. "http_proxy": data.HttpProxy,
  176. "https_proxy": data.HttpsProxy,
  177. }
  178. return man.test(ctx, urls)
  179. }
  180. func (man *SProxySettingManager) InitializeData() error {
  181. psObj, err := man.FetchById(proxyapi.ProxySettingId_DIRECT)
  182. if err == nil {
  183. ps := psObj.(*SProxySetting)
  184. if !ps.IsPublic || ps.PublicScope != string(rbacscope.ScopeSystem) {
  185. _, err = db.Update(ps, func() error {
  186. ps.IsPublic = true
  187. ps.PublicScope = string(rbacscope.ScopeSystem)
  188. return nil
  189. })
  190. if err != nil {
  191. return errors.Wrap(err, "Update")
  192. }
  193. }
  194. return nil
  195. }
  196. if err != sql.ErrNoRows {
  197. return err
  198. }
  199. m, err := db.NewModelObject(man)
  200. if err != nil {
  201. return err
  202. }
  203. ps := m.(*SProxySetting)
  204. ps.Id = proxyapi.ProxySettingId_DIRECT
  205. ps.Name = proxyapi.ProxySettingId_DIRECT
  206. ps.Description = "Connect directly"
  207. ps.IsPublic = true
  208. ps.PublicScope = string(rbacscope.ScopeSystem)
  209. if err := man.TableSpec().Insert(ctx.CtxWithTime(), ps); err != nil {
  210. return err
  211. }
  212. return nil
  213. }
  214. var referrersMen []db.IModelManager
  215. func RegisterReferrer(man db.IModelManager) {
  216. referrersMen = append(referrersMen, man)
  217. }
  218. func ValidateProxySettingResourceInput(ctx context.Context, userCred mcclient.TokenCredential, input proxyapi.ProxySettingResourceInput) (*SProxySetting, proxyapi.ProxySettingResourceInput, error) {
  219. m, err := ProxySettingManager.FetchByIdOrName(ctx, userCred, input.ProxySettingId)
  220. if err != nil {
  221. if errors.Cause(err) == sql.ErrNoRows {
  222. return nil, input, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", ProxySettingManager.Keyword(), input.ProxySettingId)
  223. } else {
  224. return nil, input, errors.Wrapf(err, "ProxySettingManager.FetchByIdOrName")
  225. }
  226. }
  227. input.ProxySettingId = m.GetId()
  228. return m.(*SProxySetting), input, nil
  229. }