routers.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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 models
  15. import (
  16. "context"
  17. "fmt"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/gotypes"
  22. "yunion.io/x/pkg/util/netutils"
  23. "yunion.io/x/onecloud/pkg/apis"
  24. api "yunion.io/x/onecloud/pkg/apis/cloudnet"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  27. "yunion.io/x/onecloud/pkg/httperrors"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. )
  30. // Add revision?
  31. type SRouter struct {
  32. db.SStandaloneResourceBase
  33. User string `nullable:"false" list:"user" update:"user" create:"optional"`
  34. Host string `nullable:"false" list:"user" update:"user" create:"required"`
  35. Port int `nullable:"false" list:"user" update:"user" create:"optional"`
  36. PrivateKey string `nullable:"true" update:"user" create:"optional"` // do not allow get, list
  37. RealizeWgIfaces bool `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
  38. RealizeRoutes bool `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
  39. RealizeRules bool `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
  40. }
  41. type SRouterManager struct {
  42. db.SStandaloneResourceBaseManager
  43. }
  44. var RouterManager *SRouterManager
  45. func init() {
  46. RouterManager = &SRouterManager{
  47. SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager(
  48. SRouter{},
  49. "routers_tbl",
  50. "router",
  51. "routers",
  52. ),
  53. }
  54. RouterManager.SetVirtualObject(RouterManager)
  55. }
  56. func (man *SRouterManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
  57. input := apis.StandaloneResourceCreateInput{}
  58. err := data.Unmarshal(&input)
  59. if err != nil {
  60. return nil, httperrors.NewInternalServerError("unmarshal StandaloneResourceCreateInput fail %s", err)
  61. }
  62. input, err = man.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
  63. if err != nil {
  64. return nil, err
  65. }
  66. data.Update(jsonutils.Marshal(input))
  67. vs := []validators.IValidator{
  68. validators.NewStringNonEmptyValidator("user").Default("cloudroot"),
  69. validators.NewStringNonEmptyValidator("host"),
  70. validators.NewPortValidator("port").Default(22),
  71. validators.NewSSHKeyValidator("private_key").Optional(true),
  72. validators.NewBoolValidator("realize_wg_ifaces").Default(true),
  73. validators.NewBoolValidator("realize_routes").Default(true),
  74. validators.NewBoolValidator("realize_rules").Default(true),
  75. }
  76. for _, v := range vs {
  77. if err := v.Validate(ctx, data); err != nil {
  78. return nil, err
  79. }
  80. }
  81. // populate ssh credential through "cloudhost"
  82. //
  83. // if ! skip validation {
  84. // ssh credential validation
  85. // }
  86. return data, nil
  87. }
  88. func (router *SRouter) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  89. err := RuleManager.addRouterRules(ctx, userCred, router)
  90. if err != nil {
  91. log.Errorf("add router rule: %v", err)
  92. }
  93. }
  94. func (man *SRouterManager) getById(id string) (*SRouter, error) {
  95. m, err := db.FetchById(man, id)
  96. if err != nil {
  97. return nil, err
  98. }
  99. router := m.(*SRouter)
  100. return router, err
  101. }
  102. func (router *SRouter) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RouterUpdateInput) (api.RouterUpdateInput, error) {
  103. var err error
  104. input.StandaloneResourceBaseUpdateInput, err = router.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
  105. if err != nil {
  106. return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
  107. }
  108. data := jsonutils.Marshal(input).(*jsonutils.JSONDict)
  109. vs := []validators.IValidator{
  110. validators.NewStringNonEmptyValidator("user"),
  111. validators.NewStringNonEmptyValidator("host"),
  112. validators.NewPortValidator("port"),
  113. validators.NewSSHKeyValidator("private_key").Optional(true),
  114. validators.NewBoolValidator("realize_wg_ifaces"),
  115. validators.NewBoolValidator("realize_routes"),
  116. validators.NewBoolValidator("realize_rules"),
  117. }
  118. for _, v := range vs {
  119. v.Optional(true)
  120. if err := v.Validate(ctx, data); err != nil {
  121. return input, err
  122. }
  123. }
  124. input.OldEndpoint = router.endpointIP()
  125. return input, nil
  126. }
  127. func (router *SRouter) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  128. endpointOld, _ := data.GetString("_old_endpoint")
  129. endpoint := router.endpointIP()
  130. if endpoint != endpointOld {
  131. err := IfacePeerManager.updateEndpointIPByPeerRouter(ctx, endpoint, router)
  132. if err != nil {
  133. log.Errorf("updating peer endpoint failed: %v", err)
  134. }
  135. }
  136. }
  137. func (router *SRouter) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  138. var errs []error
  139. if err := MeshNetworkManager.removeRouter(ctx, userCred, router); err != nil {
  140. errs = append(errs, err)
  141. }
  142. if err := IfaceManager.removeByRouter(ctx, userCred, router); err != nil {
  143. errs = append(errs, err)
  144. }
  145. if err := RuleManager.removeByRouter(ctx, userCred, router); err != nil {
  146. errs = append(errs, err)
  147. }
  148. if err := router.SStandaloneResourceBase.CustomizeDelete(ctx, userCred, query, data); err != nil {
  149. errs = append(errs, err)
  150. }
  151. return errors.NewAggregate(errs)
  152. }
  153. func (router *SRouter) PerformJoinMeshNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  154. mnV := validators.NewModelIdOrNameValidator("mesh_network", "meshnetwork", userCred)
  155. advSubnetsV := validators.NewValidatorByActor("advertise_subnets",
  156. validators.NewActorJoinedBy(",", validators.NewActorIPv4Prefix()))
  157. {
  158. vs := []validators.IValidator{
  159. mnV,
  160. advSubnetsV,
  161. }
  162. jd, ok := data.(*jsonutils.JSONDict)
  163. if !ok {
  164. return nil, httperrors.NewBadRequestError("expecting json dict")
  165. }
  166. for _, v := range vs {
  167. if err := v.Validate(ctx, jd); err != nil {
  168. return nil, err
  169. }
  170. }
  171. }
  172. // TODO dedup
  173. nets := gotypes.ConvertSliceElemType(advSubnetsV.Value, (**netutils.IPV4Prefix)(nil)).([]*netutils.IPV4Prefix)
  174. if len(nets) == 0 {
  175. return nil, httperrors.NewBadRequestError("advertise_subnets must not be empty")
  176. }
  177. mn := mnV.Model.(*SMeshNetwork)
  178. if err := mn.addRouter(ctx, userCred, router, nets); err != nil {
  179. return nil, err
  180. }
  181. return data, nil
  182. }
  183. func (router *SRouter) PerformLeaveMeshNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  184. jd, ok := data.(*jsonutils.JSONDict)
  185. if !ok {
  186. return nil, httperrors.NewBadRequestError("expecting json dict")
  187. }
  188. mnV := validators.NewModelIdOrNameValidator("mesh_network", "meshnetwork", userCred)
  189. if err := mnV.Validate(ctx, jd); err != nil {
  190. return nil, err
  191. }
  192. mn := mnV.Model.(*SMeshNetwork)
  193. if err := mn.removeRouter(ctx, userCred, router); err != nil {
  194. return nil, err
  195. }
  196. return nil, nil
  197. }
  198. func (router *SRouter) PerformRegisterIfname(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  199. jd, ok := data.(*jsonutils.JSONDict)
  200. if !ok {
  201. return nil, httperrors.NewBadRequestError("expecting json dict")
  202. }
  203. ifnameV := validators.NewRegexpValidator("ifname", regexpIfname)
  204. if err := ifnameV.Validate(ctx, jd); err != nil {
  205. return nil, err
  206. }
  207. _, err := IfaceManager.addIface(ctx, userCred, router, ifnameV.Value)
  208. if err != nil {
  209. return nil, err
  210. }
  211. return nil, nil
  212. }
  213. func (router *SRouter) PerformUnregisterIfname(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  214. jd, ok := data.(*jsonutils.JSONDict)
  215. if !ok {
  216. return nil, httperrors.NewBadRequestError("expecting json dict")
  217. }
  218. ifname, err := jd.GetString("ifname")
  219. if err != nil {
  220. return nil, httperrors.NewBadRequestError("get request ifname field: %v", err)
  221. }
  222. iface, err := IfaceManager.getByRouterIfname(router, ifname)
  223. if err != nil {
  224. return nil, httperrors.NewBadRequestError("get iface: %s", err)
  225. }
  226. if iface.NetworkId != "" {
  227. // XXX can_unregister
  228. return nil, httperrors.NewBadRequestError("please use leave network to unregister")
  229. }
  230. if err := iface.remove(ctx, userCred); err != nil {
  231. return nil, httperrors.NewBadRequestError("remove iface: %v", err)
  232. }
  233. return nil, nil
  234. }
  235. func (router *SRouter) mustFindFreePort(ctx context.Context) int {
  236. // loop through ifaces listen port
  237. ifaces, err := IfaceManager.getByRouter(router)
  238. if err != nil {
  239. panic(err)
  240. }
  241. for sport := 20000; sport < 65536; sport++ {
  242. notfound := true
  243. for i := range ifaces {
  244. if ifaces[i].ListenPort == sport {
  245. notfound = false
  246. break
  247. }
  248. }
  249. if notfound {
  250. return sport
  251. }
  252. }
  253. panic(fmt.Sprintf("cannot find free port for host %s(%s)", router.Name, router.Id))
  254. }
  255. func (router *SRouter) endpointIP() string {
  256. return router.Host
  257. }
  258. func (router *SRouter) PerformDeploy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  259. if err := RouterDeploymentManager.requestDeployment(ctx, userCred, router); err != nil {
  260. return nil, err
  261. }
  262. return nil, nil
  263. }