failover.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package controllers
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "github.com/google/uuid"
  8. "github.com/gorilla/mux"
  9. controller "github.com/gravitl/netmaker/controllers"
  10. "github.com/gravitl/netmaker/logger"
  11. "github.com/gravitl/netmaker/logic"
  12. "github.com/gravitl/netmaker/models"
  13. "github.com/gravitl/netmaker/mq"
  14. proLogic "github.com/gravitl/netmaker/pro/logic"
  15. "golang.org/x/exp/slog"
  16. )
  17. // FailOverHandlers - handlers for FailOver
  18. func FailOverHandlers(r *mux.Router) {
  19. r.HandleFunc("/api/v1/node/{nodeid}/failover", http.HandlerFunc(getfailOver)).Methods(http.MethodGet)
  20. r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(createfailOver))).Methods(http.MethodPost)
  21. r.HandleFunc("/api/v1/node/{nodeid}/failover", logic.SecurityCheck(true, http.HandlerFunc(deletefailOver))).Methods(http.MethodDelete)
  22. r.HandleFunc("/api/v1/node/{network}/failover/reset", logic.SecurityCheck(true, http.HandlerFunc(resetFailOver))).Methods(http.MethodPost)
  23. r.HandleFunc("/api/v1/node/{nodeid}/failover_me", controller.Authorize(true, false, "host", http.HandlerFunc(failOverME))).Methods(http.MethodPost)
  24. }
  25. // swagger:route GET /api/v1/node/failover node getfailOver
  26. //
  27. // get failover node.
  28. //
  29. // Schemes: https
  30. //
  31. // Security:
  32. // oauth
  33. //
  34. // Responses:
  35. // 200: nodeResponse
  36. func getfailOver(w http.ResponseWriter, r *http.Request) {
  37. var params = mux.Vars(r)
  38. nodeid := params["nodeid"]
  39. // confirm host exists
  40. node, err := logic.GetNodeByID(nodeid)
  41. if err != nil {
  42. slog.Error("failed to get node:", "error", err.Error())
  43. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  44. return
  45. }
  46. failOverNode, exists := proLogic.FailOverExists(node.Network)
  47. if !exists {
  48. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failover node not found"), "notfound"))
  49. return
  50. }
  51. w.Header().Set("Content-Type", "application/json")
  52. logic.ReturnSuccessResponseWithJson(w, r, failOverNode, "get failover node successfully")
  53. }
  54. // swagger:route POST /api/v1/node/failover node createfailOver
  55. //
  56. // Create a relay.
  57. //
  58. // Schemes: https
  59. //
  60. // Security:
  61. // oauth
  62. //
  63. // Responses:
  64. // 200: nodeResponse
  65. func createfailOver(w http.ResponseWriter, r *http.Request) {
  66. var params = mux.Vars(r)
  67. nodeid := params["nodeid"]
  68. // confirm host exists
  69. node, err := logic.GetNodeByID(nodeid)
  70. if err != nil {
  71. slog.Error("failed to get node:", "error", err.Error())
  72. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  73. return
  74. }
  75. err = proLogic.CreateFailOver(node)
  76. if err != nil {
  77. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  78. return
  79. }
  80. go mq.PublishPeerUpdate(false)
  81. w.Header().Set("Content-Type", "application/json")
  82. logic.ReturnSuccessResponseWithJson(w, r, node, "created failover successfully")
  83. }
  84. func resetFailOver(w http.ResponseWriter, r *http.Request) {
  85. var params = mux.Vars(r)
  86. net := params["network"]
  87. nodes, err := logic.GetNetworkNodes(net)
  88. if err != nil {
  89. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  90. return
  91. }
  92. for _, node := range nodes {
  93. if node.FailedOverBy != uuid.Nil {
  94. node.FailedOverBy = uuid.Nil
  95. node.FailOverPeers = make(map[string]struct{})
  96. logic.UpsertNode(&node)
  97. }
  98. }
  99. go mq.PublishPeerUpdate(false)
  100. w.Header().Set("Content-Type", "application/json")
  101. logic.ReturnSuccessResponse(w, r, "failover has been reset successfully")
  102. }
  103. // swagger:route DELETE /api/v1/node/failover node deletefailOver
  104. //
  105. // Create a relay.
  106. //
  107. // Schemes: https
  108. //
  109. // Security:
  110. // oauth
  111. //
  112. // Responses:
  113. // 200: nodeResponse
  114. func deletefailOver(w http.ResponseWriter, r *http.Request) {
  115. var params = mux.Vars(r)
  116. nodeid := params["nodeid"]
  117. // confirm host exists
  118. node, err := logic.GetNodeByID(nodeid)
  119. if err != nil {
  120. slog.Error("failed to get node:", "error", err.Error())
  121. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  122. return
  123. }
  124. node.IsFailOver = false
  125. // Reset FailOvered Peers
  126. err = logic.UpsertNode(&node)
  127. if err != nil {
  128. slog.Error("failed to upsert node", "node", node.ID.String(), "error", err)
  129. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  130. return
  131. }
  132. go func() {
  133. proLogic.ResetFailOver(&node)
  134. mq.PublishPeerUpdate(false)
  135. }()
  136. w.Header().Set("Content-Type", "application/json")
  137. logic.ReturnSuccessResponseWithJson(w, r, node, "deleted failover successfully")
  138. }
  139. // swagger:route POST /api/node/{nodeid}/failOverME node failOver_me
  140. //
  141. // Create a relay.
  142. //
  143. // Schemes: https
  144. //
  145. // Security:
  146. // oauth
  147. //
  148. // Responses:
  149. // 200: nodeResponse
  150. func failOverME(w http.ResponseWriter, r *http.Request) {
  151. var params = mux.Vars(r)
  152. nodeid := params["nodeid"]
  153. // confirm host exists
  154. node, err := logic.GetNodeByID(nodeid)
  155. if err != nil {
  156. logger.Log(0, r.Header.Get("user"), "failed to get node:", err.Error())
  157. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  158. return
  159. }
  160. host, err := logic.GetHost(node.HostID.String())
  161. if err != nil {
  162. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  163. return
  164. }
  165. failOverNode, exists := proLogic.FailOverExists(node.Network)
  166. if !exists {
  167. logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("req-from: %s, failover node doesn't exist in the network", host.Name), "badrequest"))
  168. return
  169. }
  170. var failOverReq models.FailOverMeReq
  171. err = json.NewDecoder(r.Body).Decode(&failOverReq)
  172. if err != nil {
  173. logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
  174. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  175. return
  176. }
  177. var sendPeerUpdate bool
  178. peerNode, err := logic.GetNodeByID(failOverReq.NodeID)
  179. if err != nil {
  180. slog.Error("peer not found: ", "nodeid", failOverReq.NodeID, "error", err)
  181. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("peer not found"), "badrequest"))
  182. return
  183. }
  184. if node.IsFailOver {
  185. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is acting as failover"), "badrequest"))
  186. return
  187. }
  188. if node.IsRelayed && node.RelayedBy == peerNode.ID.String() {
  189. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is relayed by peer node"), "badrequest"))
  190. return
  191. }
  192. if node.IsRelay && peerNode.RelayedBy == node.ID.String() {
  193. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as relay for the peer node"), "badrequest"))
  194. return
  195. }
  196. if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() {
  197. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as internet gw for the peer node"), "badrequest"))
  198. return
  199. }
  200. if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() {
  201. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node using a internet gw by the peer node"), "badrequest"))
  202. return
  203. }
  204. err = proLogic.SetFailOverCtx(failOverNode, node, peerNode)
  205. if err != nil {
  206. slog.Error("failed to create failover", "id", node.ID.String(),
  207. "network", node.Network, "error", err)
  208. logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create failover: %v", err), "internal"))
  209. return
  210. }
  211. slog.Info("[auto-relay] created relay on node", "node", node.ID.String(), "network", node.Network)
  212. sendPeerUpdate = true
  213. if sendPeerUpdate {
  214. go mq.PublishPeerUpdate(false)
  215. }
  216. w.Header().Set("Content-Type", "application/json")
  217. logic.ReturnSuccessResponse(w, r, "relayed successfully")
  218. }