hosts.go 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "os"
  8. "github.com/google/uuid"
  9. "github.com/gorilla/mux"
  10. "github.com/gravitl/netmaker/database"
  11. "github.com/gravitl/netmaker/logger"
  12. "github.com/gravitl/netmaker/logic"
  13. "github.com/gravitl/netmaker/models"
  14. "github.com/gravitl/netmaker/mq"
  15. "github.com/gravitl/netmaker/servercfg"
  16. "golang.org/x/crypto/bcrypt"
  17. "golang.org/x/exp/slog"
  18. )
  19. func hostHandlers(r *mux.Router) {
  20. r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).
  21. Methods(http.MethodGet)
  22. r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).
  23. Methods(http.MethodPut)
  24. r.HandleFunc("/api/hosts/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHosts))).
  25. Methods(http.MethodPost)
  26. r.HandleFunc("/api/hosts/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHosts))).
  27. Methods(http.MethodPost)
  28. r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).
  29. Methods(http.MethodPut)
  30. r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).
  31. Methods(http.MethodPost)
  32. r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).
  33. Methods(http.MethodPut)
  34. r.HandleFunc("/api/hosts/{hostid}", Authorize(true, false, "all", http.HandlerFunc(deleteHost))).
  35. Methods(http.MethodDelete)
  36. r.HandleFunc("/api/hosts/{hostid}/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHost))).
  37. Methods(http.MethodPut)
  38. r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).
  39. Methods(http.MethodPost)
  40. r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).
  41. Methods(http.MethodDelete)
  42. r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost)
  43. r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).
  44. Methods(http.MethodGet)
  45. r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).
  46. Methods(http.MethodPost)
  47. r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).
  48. Methods(http.MethodPut)
  49. r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).
  50. Methods(http.MethodDelete)
  51. r.HandleFunc("/api/v1/auth-register/host", socketHandler)
  52. }
  53. // @Summary Requests all the hosts to upgrade their version
  54. // @Router /api/hosts/upgrade [post]
  55. // @Tags Hosts
  56. // @Security oauth
  57. // @Param force query bool false "Force upgrade"
  58. // @Success 200 {string} string "upgrade all hosts request received"
  59. func upgradeHosts(w http.ResponseWriter, r *http.Request) {
  60. w.Header().Set("Content-Type", "application/json")
  61. action := models.Upgrade
  62. if r.URL.Query().Get("force") == "true" {
  63. action = models.ForceUpgrade
  64. }
  65. user := r.Header.Get("user")
  66. go func() {
  67. slog.Info("requesting all hosts to upgrade", "user", user)
  68. hosts, err := logic.GetAllHosts()
  69. if err != nil {
  70. slog.Error("failed to retrieve all hosts", "user", user, "error", err)
  71. return
  72. }
  73. for _, host := range hosts {
  74. go func(host models.Host) {
  75. hostUpdate := models.HostUpdate{
  76. Action: action,
  77. Host: host,
  78. }
  79. if err = mq.HostUpdate(&hostUpdate); err != nil {
  80. slog.Error("failed to request host to upgrade", "user", user, "host", host.ID.String(), "error", err)
  81. } else {
  82. slog.Info("host upgrade requested", "user", user, "host", host.ID.String())
  83. }
  84. }(host)
  85. }
  86. }()
  87. slog.Info("upgrade all hosts request received", "user", user)
  88. logic.ReturnSuccessResponse(w, r, "upgrade all hosts request received")
  89. }
  90. // @Summary Upgrade a host
  91. // @Router /api/hosts/{hostid}/upgrade [put]
  92. // @Tags Hosts
  93. // @Security oauth
  94. // @Param hostid path string true "Host ID"
  95. // @Param force query bool false "Force upgrade"
  96. // @Success 200 {string} string "passed message to upgrade host"
  97. // @Failure 500 {object} models.ErrorResponse
  98. // upgrade host is a handler to send upgrade message to a host
  99. func upgradeHost(w http.ResponseWriter, r *http.Request) {
  100. host, err := logic.GetHost(mux.Vars(r)["hostid"])
  101. if err != nil {
  102. slog.Error("failed to find host", "error", err)
  103. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "notfound"))
  104. return
  105. }
  106. action := models.Upgrade
  107. if r.URL.Query().Get("force") == "true" {
  108. action = models.ForceUpgrade
  109. }
  110. if err := mq.HostUpdate(&models.HostUpdate{Action: action, Host: *host}); err != nil {
  111. slog.Error("failed to upgrade host", "error", err)
  112. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  113. return
  114. }
  115. logic.ReturnSuccessResponse(w, r, "passed message to upgrade host")
  116. }
  117. // @Summary List all hosts
  118. // @Router /api/hosts [get]
  119. // @Tags Hosts
  120. // @Security oauth
  121. // @Success 200 {array} models.ApiHost
  122. // @Failure 500 {object} models.ErrorResponse
  123. func getHosts(w http.ResponseWriter, r *http.Request) {
  124. w.Header().Set("Content-Type", "application/json")
  125. currentHosts := []models.Host{}
  126. var err error
  127. if r.Header.Get("ismaster") == "yes" {
  128. currentHosts, err = logic.GetAllHosts()
  129. if err != nil {
  130. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  131. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  132. return
  133. }
  134. } else {
  135. username := r.Header.Get("user")
  136. user, err := logic.GetUser(username)
  137. if err != nil {
  138. return
  139. }
  140. userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
  141. if err != nil {
  142. return
  143. }
  144. respHostsMap := make(map[string]struct{})
  145. if !userPlatformRole.FullAccess {
  146. nodes, err := logic.GetAllNodes()
  147. if err != nil {
  148. logger.Log(0, "error fetching all nodes info: ", err.Error())
  149. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  150. return
  151. }
  152. filteredNodes := logic.GetFilteredNodesByUserAccess(*user, nodes)
  153. if len(filteredNodes) > 0 {
  154. currentHostsMap, err := logic.GetHostsMap()
  155. if err != nil {
  156. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  157. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  158. return
  159. }
  160. for _, node := range filteredNodes {
  161. if _, ok := respHostsMap[node.HostID.String()]; ok {
  162. continue
  163. }
  164. if host, ok := currentHostsMap[node.HostID.String()]; ok {
  165. currentHosts = append(currentHosts, host)
  166. respHostsMap[host.ID.String()] = struct{}{}
  167. }
  168. }
  169. }
  170. } else {
  171. currentHosts, err = logic.GetAllHosts()
  172. if err != nil {
  173. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  174. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  175. return
  176. }
  177. }
  178. }
  179. apiHosts := logic.GetAllHostsAPI(currentHosts[:])
  180. logger.Log(2, r.Header.Get("user"), "fetched all hosts")
  181. logic.SortApiHosts(apiHosts[:])
  182. w.WriteHeader(http.StatusOK)
  183. json.NewEncoder(w).Encode(apiHosts)
  184. }
  185. // @Summary Used by clients for "pull" command
  186. // @Router /api/v1/host [get]
  187. // @Tags Hosts
  188. // @Security oauth
  189. // @Success 200 {object} models.HostPull
  190. // @Failure 500 {object} models.ErrorResponse
  191. func pull(w http.ResponseWriter, r *http.Request) {
  192. hostID := r.Header.Get(hostIDHeader) // return JSON/API formatted keys
  193. if len(hostID) == 0 {
  194. logger.Log(0, "no host authorized to pull")
  195. logic.ReturnErrorResponse(
  196. w,
  197. r,
  198. logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal"),
  199. )
  200. return
  201. }
  202. host, err := logic.GetHost(hostID)
  203. if err != nil {
  204. logger.Log(0, "no host found during pull", hostID)
  205. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  206. return
  207. }
  208. sendPeerUpdate := false
  209. for _, nodeID := range host.Nodes {
  210. node, err := logic.GetNodeByID(nodeID)
  211. if err != nil {
  212. slog.Error("failed to get node:", "id", node.ID, "error", err)
  213. continue
  214. }
  215. if node.FailedOverBy != uuid.Nil {
  216. logic.ResetFailedOverPeer(&node)
  217. sendPeerUpdate = true
  218. }
  219. }
  220. if sendPeerUpdate {
  221. reset := true
  222. if os.Getenv("RESET_PEER_UPDATE") != "" {
  223. reset = os.Getenv("RESET_PEER_UPDATE") == "true"
  224. }
  225. if err := mq.PublishPeerUpdate(reset); err != nil {
  226. logger.Log(0, "fail to publish peer update: ", err.Error())
  227. }
  228. }
  229. allNodes, err := logic.GetAllNodes()
  230. if err != nil {
  231. logger.Log(0, "failed to get nodes: ", hostID)
  232. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  233. return
  234. }
  235. hPU, err := logic.GetPeerUpdateForHost("", host, allNodes, nil, nil)
  236. if err != nil {
  237. logger.Log(0, "could not pull peers for host", hostID, err.Error())
  238. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  239. return
  240. }
  241. serverConf := servercfg.GetServerInfo()
  242. key, keyErr := logic.RetrievePublicTrafficKey()
  243. if keyErr != nil {
  244. logger.Log(0, "error retrieving key:", keyErr.Error())
  245. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  246. return
  247. }
  248. serverConf.TrafficKey = key
  249. response := models.HostPull{
  250. Host: *host,
  251. Nodes: logic.GetHostNodes(host),
  252. ServerConfig: serverConf,
  253. Peers: hPU.Peers,
  254. PeerIDs: hPU.PeerIDs,
  255. HostNetworkInfo: hPU.HostNetworkInfo,
  256. EgressRoutes: hPU.EgressRoutes,
  257. FwUpdate: hPU.FwUpdate,
  258. ChangeDefaultGw: hPU.ChangeDefaultGw,
  259. DefaultGwIp: hPU.DefaultGwIp,
  260. IsInternetGw: hPU.IsInternetGw,
  261. EndpointDetection: servercfg.IsEndpointDetectionEnabled(),
  262. }
  263. logger.Log(1, hostID, "completed a pull")
  264. w.WriteHeader(http.StatusOK)
  265. json.NewEncoder(w).Encode(&response)
  266. }
  267. // @Summary Updates a Netclient host on Netmaker server
  268. // @Router /api/hosts/{hostid} [put]
  269. // @Tags Hosts
  270. // @Security oauth
  271. // @Param hostid path string true "Host ID"
  272. // @Param body body models.ApiHost true "New host data"
  273. // @Success 200 {object} models.ApiHost
  274. // @Failure 500 {object} models.ErrorResponse
  275. func updateHost(w http.ResponseWriter, r *http.Request) {
  276. var newHostData models.ApiHost
  277. err := json.NewDecoder(r.Body).Decode(&newHostData)
  278. if err != nil {
  279. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  280. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  281. return
  282. }
  283. // confirm host exists
  284. currHost, err := logic.GetHost(newHostData.ID)
  285. if err != nil {
  286. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  287. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  288. return
  289. }
  290. newHost := newHostData.ConvertAPIHostToNMHost(currHost)
  291. logic.UpdateHost(newHost, currHost) // update the in memory struct values
  292. if err = logic.UpsertHost(newHost); err != nil {
  293. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  294. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  295. return
  296. }
  297. // publish host update through MQ
  298. if err := mq.HostUpdate(&models.HostUpdate{
  299. Action: models.UpdateHost,
  300. Host: *newHost,
  301. }); err != nil {
  302. logger.Log(
  303. 0,
  304. r.Header.Get("user"),
  305. "failed to send host update: ",
  306. currHost.ID.String(),
  307. err.Error(),
  308. )
  309. }
  310. go func() {
  311. if err := mq.PublishPeerUpdate(false); err != nil {
  312. logger.Log(0, "fail to publish peer update: ", err.Error())
  313. }
  314. if newHost.Name != currHost.Name {
  315. if servercfg.IsDNSMode() {
  316. logic.SetDNS()
  317. }
  318. }
  319. }()
  320. apiHostData := newHost.ConvertNMHostToAPI()
  321. logger.Log(2, r.Header.Get("user"), "updated host", newHost.ID.String())
  322. w.WriteHeader(http.StatusOK)
  323. json.NewEncoder(w).Encode(apiHostData)
  324. }
  325. // @Summary Updates a Netclient host on Netmaker server
  326. // @Router /api/v1/fallback/host/{hostid} [put]
  327. // @Tags Hosts
  328. // @Security oauth
  329. // @Param hostid path string true "Host ID"
  330. // @Param body body models.HostUpdate true "Host update data"
  331. // @Success 200 {string} string "updated host data"
  332. // @Failure 500 {object} models.ErrorResponse
  333. func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
  334. var params = mux.Vars(r)
  335. hostid := params["hostid"]
  336. currentHost, err := logic.GetHost(hostid)
  337. if err != nil {
  338. slog.Error("error getting host", "id", hostid, "error", err)
  339. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  340. return
  341. }
  342. var sendPeerUpdate bool
  343. var replacePeers bool
  344. var hostUpdate models.HostUpdate
  345. err = json.NewDecoder(r.Body).Decode(&hostUpdate)
  346. if err != nil {
  347. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  348. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  349. return
  350. }
  351. slog.Info("recieved host update", "name", hostUpdate.Host.Name, "id", hostUpdate.Host.ID)
  352. switch hostUpdate.Action {
  353. case models.CheckIn:
  354. sendPeerUpdate = mq.HandleHostCheckin(&hostUpdate.Host, currentHost)
  355. case models.UpdateHost:
  356. if hostUpdate.Host.PublicKey != currentHost.PublicKey {
  357. //remove old peer entry
  358. replacePeers = true
  359. }
  360. sendPeerUpdate = logic.UpdateHostFromClient(&hostUpdate.Host, currentHost)
  361. err := logic.UpsertHost(currentHost)
  362. if err != nil {
  363. slog.Error("failed to update host", "id", currentHost.ID, "error", err)
  364. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  365. return
  366. }
  367. case models.UpdateMetrics:
  368. mq.UpdateMetricsFallBack(hostUpdate.Node.ID.String(), hostUpdate.NewMetrics)
  369. }
  370. if sendPeerUpdate {
  371. err := mq.PublishPeerUpdate(replacePeers)
  372. if err != nil {
  373. slog.Error("failed to publish peer update", "error", err)
  374. }
  375. }
  376. logic.ReturnSuccessResponse(w, r, "updated host data")
  377. }
  378. // @Summary Deletes a Netclient host from Netmaker server
  379. // @Router /api/hosts/{hostid} [delete]
  380. // @Tags Hosts
  381. // @Security oauth
  382. // @Param hostid path string true "Host ID"
  383. // @Param force query bool false "Force delete"
  384. // @Success 200 {object} models.ApiHost
  385. // @Failure 500 {object} models.ErrorResponse
  386. func deleteHost(w http.ResponseWriter, r *http.Request) {
  387. var params = mux.Vars(r)
  388. hostid := params["hostid"]
  389. forceDelete := r.URL.Query().Get("force") == "true"
  390. // confirm host exists
  391. currHost, err := logic.GetHost(hostid)
  392. if err != nil {
  393. logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
  394. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  395. return
  396. }
  397. for _, nodeID := range currHost.Nodes {
  398. node, err := logic.GetNodeByID(nodeID)
  399. if err != nil {
  400. slog.Error("failed to get node", "nodeid", nodeID, "error", err)
  401. continue
  402. }
  403. var gwClients []models.ExtClient
  404. if node.IsIngressGateway {
  405. gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
  406. }
  407. go mq.PublishMqUpdatesForDeletedNode(node, false, gwClients)
  408. }
  409. if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
  410. // delete EMQX credentials for host
  411. if err := mq.GetEmqxHandler().DeleteEmqxUser(currHost.ID.String()); err != nil {
  412. slog.Error(
  413. "failed to remove host credentials from EMQX",
  414. "id",
  415. currHost.ID,
  416. "error",
  417. err,
  418. )
  419. }
  420. }
  421. if err = mq.HostUpdate(&models.HostUpdate{
  422. Action: models.DeleteHost,
  423. Host: *currHost,
  424. }); err != nil {
  425. logger.Log(
  426. 0,
  427. r.Header.Get("user"),
  428. "failed to send delete host update: ",
  429. currHost.ID.String(),
  430. err.Error(),
  431. )
  432. }
  433. if err = logic.RemoveHost(currHost, forceDelete); err != nil {
  434. logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
  435. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  436. return
  437. }
  438. apiHostData := currHost.ConvertNMHostToAPI()
  439. logger.Log(2, r.Header.Get("user"), "removed host", currHost.Name)
  440. w.WriteHeader(http.StatusOK)
  441. json.NewEncoder(w).Encode(apiHostData)
  442. }
  443. // @Summary To Add Host To Network
  444. // @Router /api/hosts/{hostid}/networks/{network} [post]
  445. // @Tags Hosts
  446. // @Security oauth
  447. // @Param hostid path string true "Host ID"
  448. // @Param network path string true "Network name"
  449. // @Success 200 {string} string "OK"
  450. // @Failure 500 {object} models.ErrorResponse
  451. func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
  452. var params = mux.Vars(r)
  453. hostid := params["hostid"]
  454. network := params["network"]
  455. if hostid == "" || network == "" {
  456. logic.ReturnErrorResponse(
  457. w,
  458. r,
  459. logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
  460. )
  461. return
  462. }
  463. // confirm host exists
  464. currHost, err := logic.GetHost(hostid)
  465. if err != nil {
  466. logger.Log(0, r.Header.Get("user"), "failed to find host:", hostid, err.Error())
  467. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  468. return
  469. }
  470. newNode, err := logic.UpdateHostNetwork(currHost, network, true)
  471. if err != nil {
  472. logger.Log(
  473. 0,
  474. r.Header.Get("user"),
  475. "failed to add host to network:",
  476. hostid,
  477. network,
  478. err.Error(),
  479. )
  480. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  481. return
  482. }
  483. logger.Log(1, "added new node", newNode.ID.String(), "to host", currHost.Name)
  484. if currHost.IsDefault {
  485. // make host failover
  486. logic.CreateFailOver(*newNode)
  487. // make host remote access gateway
  488. logic.CreateIngressGateway(network, newNode.ID.String(), models.IngressRequest{})
  489. }
  490. go func() {
  491. mq.HostUpdate(&models.HostUpdate{
  492. Action: models.JoinHostToNetwork,
  493. Host: *currHost,
  494. Node: *newNode,
  495. })
  496. mq.PublishPeerUpdate(false)
  497. if servercfg.IsDNSMode() {
  498. logic.SetDNS()
  499. }
  500. }()
  501. logger.Log(
  502. 2,
  503. r.Header.Get("user"),
  504. fmt.Sprintf("added host %s to network %s", currHost.Name, network),
  505. )
  506. w.WriteHeader(http.StatusOK)
  507. }
  508. // @Summary To Remove Host from Network
  509. // @Router /api/hosts/{hostid}/networks/{network} [delete]
  510. // @Tags Hosts
  511. // @Security oauth
  512. // @Param hostid path string true "Host ID"
  513. // @Param network path string true "Network name"
  514. // @Param force query bool false "Force delete"
  515. // @Success 200 {string} string "OK"
  516. // @Failure 500 {object} models.ErrorResponse
  517. func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
  518. var params = mux.Vars(r)
  519. hostid := params["hostid"]
  520. network := params["network"]
  521. forceDelete := r.URL.Query().Get("force") == "true"
  522. if hostid == "" || network == "" {
  523. logic.ReturnErrorResponse(
  524. w,
  525. r,
  526. logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
  527. )
  528. return
  529. }
  530. // confirm host exists
  531. currHost, err := logic.GetHost(hostid)
  532. if err != nil {
  533. if database.IsEmptyRecord(err) {
  534. // check if there is any daemon nodes that needs to be deleted
  535. node, err := logic.GetNodeByHostRef(hostid, network)
  536. if err != nil {
  537. slog.Error(
  538. "couldn't get node for host",
  539. "hostid",
  540. hostid,
  541. "network",
  542. network,
  543. "error",
  544. err,
  545. )
  546. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  547. return
  548. }
  549. if err = logic.DeleteNodeByID(&node); err != nil {
  550. slog.Error("failed to force delete daemon node",
  551. "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
  552. logic.ReturnErrorResponse(
  553. w,
  554. r,
  555. logic.FormatError(
  556. fmt.Errorf("failed to force delete daemon node: "+err.Error()),
  557. "internal",
  558. ),
  559. )
  560. return
  561. }
  562. logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
  563. return
  564. }
  565. logger.Log(0, r.Header.Get("user"), "failed to find host:", err.Error())
  566. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  567. return
  568. }
  569. node, err := logic.UpdateHostNetwork(currHost, network, false)
  570. if err != nil {
  571. if node == nil && forceDelete {
  572. // force cleanup the node
  573. node, err := logic.GetNodeByHostRef(hostid, network)
  574. if err != nil {
  575. slog.Error(
  576. "couldn't get node for host",
  577. "hostid",
  578. hostid,
  579. "network",
  580. network,
  581. "error",
  582. err,
  583. )
  584. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  585. return
  586. }
  587. if err = logic.DeleteNodeByID(&node); err != nil {
  588. slog.Error("failed to force delete daemon node",
  589. "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
  590. logic.ReturnErrorResponse(
  591. w,
  592. r,
  593. logic.FormatError(
  594. fmt.Errorf("failed to force delete daemon node: "+err.Error()),
  595. "internal",
  596. ),
  597. )
  598. return
  599. }
  600. logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
  601. return
  602. }
  603. logger.Log(
  604. 0,
  605. r.Header.Get("user"),
  606. "failed to remove host from network:",
  607. hostid,
  608. network,
  609. err.Error(),
  610. )
  611. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  612. return
  613. }
  614. var gwClients []models.ExtClient
  615. if node.IsIngressGateway {
  616. gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
  617. }
  618. logger.Log(1, "deleting node", node.ID.String(), "from host", currHost.Name)
  619. if err := logic.DeleteNode(node, forceDelete); err != nil {
  620. logic.ReturnErrorResponse(
  621. w,
  622. r,
  623. logic.FormatError(fmt.Errorf("failed to delete node"), "internal"),
  624. )
  625. return
  626. }
  627. go func() {
  628. mq.PublishMqUpdatesForDeletedNode(*node, true, gwClients)
  629. if servercfg.IsDNSMode() {
  630. logic.SetDNS()
  631. }
  632. }()
  633. logger.Log(
  634. 2,
  635. r.Header.Get("user"),
  636. fmt.Sprintf("removed host %s from network %s", currHost.Name, network),
  637. )
  638. w.WriteHeader(http.StatusOK)
  639. }
  640. // @Summary To Fetch Auth Token for a Host
  641. // @Router /api/hosts/adm/authenticate [post]
  642. // @Tags Auth
  643. // @Accept json
  644. // @Param body body models.AuthParams true "Authentication parameters"
  645. // @Success 200 {object} models.SuccessResponse
  646. // @Failure 400 {object} models.ErrorResponse
  647. // @Failure 401 {object} models.ErrorResponse
  648. // @Failure 500 {object} models.ErrorResponse
  649. func authenticateHost(response http.ResponseWriter, request *http.Request) {
  650. var authRequest models.AuthParams
  651. var errorResponse = models.ErrorResponse{
  652. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  653. }
  654. decoder := json.NewDecoder(request.Body)
  655. decoderErr := decoder.Decode(&authRequest)
  656. defer request.Body.Close()
  657. if decoderErr != nil {
  658. errorResponse.Code = http.StatusBadRequest
  659. errorResponse.Message = decoderErr.Error()
  660. logger.Log(0, request.Header.Get("user"), "error decoding request body: ",
  661. decoderErr.Error())
  662. logic.ReturnErrorResponse(response, request, errorResponse)
  663. return
  664. }
  665. errorResponse.Code = http.StatusBadRequest
  666. if authRequest.ID == "" {
  667. errorResponse.Message = "W1R3: ID can't be empty"
  668. logger.Log(0, request.Header.Get("user"), errorResponse.Message)
  669. logic.ReturnErrorResponse(response, request, errorResponse)
  670. return
  671. } else if authRequest.Password == "" {
  672. errorResponse.Message = "W1R3: Password can't be empty"
  673. logger.Log(0, request.Header.Get("user"), errorResponse.Message)
  674. logic.ReturnErrorResponse(response, request, errorResponse)
  675. return
  676. }
  677. host, err := logic.GetHost(authRequest.ID)
  678. if err != nil {
  679. errorResponse.Code = http.StatusBadRequest
  680. errorResponse.Message = err.Error()
  681. logger.Log(0, request.Header.Get("user"),
  682. "error retrieving host: ", authRequest.ID, err.Error())
  683. logic.ReturnErrorResponse(response, request, errorResponse)
  684. return
  685. }
  686. err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password))
  687. if err != nil {
  688. errorResponse.Code = http.StatusUnauthorized
  689. errorResponse.Message = "unauthorized"
  690. logger.Log(0, request.Header.Get("user"),
  691. "error validating user password: ", err.Error())
  692. logic.ReturnErrorResponse(response, request, errorResponse)
  693. return
  694. }
  695. tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, "")
  696. if tokenString == "" {
  697. errorResponse.Code = http.StatusUnauthorized
  698. errorResponse.Message = "unauthorized"
  699. logger.Log(0, request.Header.Get("user"),
  700. fmt.Sprintf("%s: %v", errorResponse.Message, err))
  701. logic.ReturnErrorResponse(response, request, errorResponse)
  702. return
  703. }
  704. var successResponse = models.SuccessResponse{
  705. Code: http.StatusOK,
  706. Message: "W1R3: Host " + authRequest.ID + " Authorized",
  707. Response: models.SuccessfulLoginResponse{
  708. AuthToken: tokenString,
  709. ID: authRequest.ID,
  710. },
  711. }
  712. successJSONResponse, jsonError := json.Marshal(successResponse)
  713. if jsonError != nil {
  714. errorResponse.Code = http.StatusBadRequest
  715. errorResponse.Message = err.Error()
  716. logger.Log(0, request.Header.Get("user"),
  717. "error marshalling resp: ", err.Error())
  718. logic.ReturnErrorResponse(response, request, errorResponse)
  719. return
  720. }
  721. go func() {
  722. // Create EMQX creds
  723. if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
  724. if err := mq.GetEmqxHandler().CreateEmqxUser(host.ID.String(), authRequest.Password); err != nil {
  725. slog.Error("failed to create host credentials for EMQX: ", err.Error())
  726. }
  727. }
  728. }()
  729. response.WriteHeader(http.StatusOK)
  730. response.Header().Set("Content-Type", "application/json")
  731. response.Write(successJSONResponse)
  732. }
  733. // @Summary Send signal to peer
  734. // @Router /api/v1/host/{hostid}/signalpeer [post]
  735. // @Tags Hosts
  736. // @Security oauth
  737. // @Param hostid path string true "Host ID"
  738. // @Param body body models.Signal true "Signal data"
  739. // @Success 200 {object} models.Signal
  740. // @Failure 400 {object} models.ErrorResponse
  741. func signalPeer(w http.ResponseWriter, r *http.Request) {
  742. var params = mux.Vars(r)
  743. hostid := params["hostid"]
  744. // confirm host exists
  745. _, err := logic.GetHost(hostid)
  746. if err != nil {
  747. logger.Log(0, r.Header.Get("user"), "failed to get host:", err.Error())
  748. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  749. return
  750. }
  751. var signal models.Signal
  752. w.Header().Set("Content-Type", "application/json")
  753. err = json.NewDecoder(r.Body).Decode(&signal)
  754. if err != nil {
  755. logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
  756. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  757. return
  758. }
  759. if signal.ToHostPubKey == "" {
  760. msg := "insufficient data to signal peer"
  761. logger.Log(0, r.Header.Get("user"), msg)
  762. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New(msg), "badrequest"))
  763. return
  764. }
  765. signal.IsPro = servercfg.IsPro
  766. peerHost, err := logic.GetHost(signal.ToHostID)
  767. if err != nil {
  768. logic.ReturnErrorResponse(
  769. w,
  770. r,
  771. logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"),
  772. )
  773. return
  774. }
  775. err = mq.HostUpdate(&models.HostUpdate{
  776. Action: models.SignalHost,
  777. Host: *peerHost,
  778. Signal: signal,
  779. })
  780. if err != nil {
  781. logic.ReturnErrorResponse(
  782. w,
  783. r,
  784. logic.FormatError(
  785. errors.New("failed to publish signal to peer: "+err.Error()),
  786. "badrequest",
  787. ),
  788. )
  789. return
  790. }
  791. w.WriteHeader(http.StatusOK)
  792. json.NewEncoder(w).Encode(signal)
  793. }
  794. // @Summary Update keys for all hosts
  795. // @Router /api/hosts/keys [put]
  796. // @Tags Hosts
  797. // @Security oauth
  798. // @Success 200 {string} string "OK"
  799. // @Failure 400 {object} models.ErrorResponse
  800. func updateAllKeys(w http.ResponseWriter, r *http.Request) {
  801. var errorResponse = models.ErrorResponse{}
  802. w.Header().Set("Content-Type", "application/json")
  803. hosts, err := logic.GetAllHosts()
  804. if err != nil {
  805. errorResponse.Code = http.StatusBadRequest
  806. errorResponse.Message = err.Error()
  807. logger.Log(0, r.Header.Get("user"),
  808. "error retrieving hosts ", err.Error())
  809. logic.ReturnErrorResponse(w, r, errorResponse)
  810. return
  811. }
  812. go func() {
  813. hostUpdate := models.HostUpdate{}
  814. hostUpdate.Action = models.UpdateKeys
  815. for _, host := range hosts {
  816. hostUpdate.Host = host
  817. logger.Log(2, "updating host", host.ID.String(), " for a key update")
  818. if err = mq.HostUpdate(&hostUpdate); err != nil {
  819. logger.Log(
  820. 0,
  821. "failed to send update to node during a network wide key update",
  822. host.ID.String(),
  823. err.Error(),
  824. )
  825. }
  826. }
  827. }()
  828. logger.Log(2, r.Header.Get("user"), "updated keys for all hosts")
  829. w.WriteHeader(http.StatusOK)
  830. }
  831. // @Summary Update keys for a host
  832. // @Router /api/hosts/{hostid}/keys [put]
  833. // @Tags Hosts
  834. // @Security oauth
  835. // @Param hostid path string true "Host ID"
  836. // @Success 200 {string} string "OK"
  837. // @Failure 400 {object} models.ErrorResponse
  838. func updateKeys(w http.ResponseWriter, r *http.Request) {
  839. var errorResponse = models.ErrorResponse{}
  840. w.Header().Set("Content-Type", "application/json")
  841. var params = mux.Vars(r)
  842. hostid := params["hostid"]
  843. host, err := logic.GetHost(hostid)
  844. if err != nil {
  845. logger.Log(0, "failed to retrieve host", hostid, err.Error())
  846. errorResponse.Code = http.StatusBadRequest
  847. errorResponse.Message = err.Error()
  848. logger.Log(0, r.Header.Get("user"),
  849. "error retrieving hosts ", err.Error())
  850. logic.ReturnErrorResponse(w, r, errorResponse)
  851. return
  852. }
  853. go func() {
  854. hostUpdate := models.HostUpdate{
  855. Action: models.UpdateKeys,
  856. Host: *host,
  857. }
  858. if err = mq.HostUpdate(&hostUpdate); err != nil {
  859. logger.Log(0, "failed to send host key update", host.ID.String(), err.Error())
  860. }
  861. }()
  862. logger.Log(2, r.Header.Get("user"), "updated key on host", host.Name)
  863. w.WriteHeader(http.StatusOK)
  864. }
  865. // @Summary Requests all the hosts to pull
  866. // @Router /api/hosts/sync [post]
  867. // @Tags Hosts
  868. // @Security oauth
  869. // @Success 200 {string} string "sync all hosts request received"
  870. func syncHosts(w http.ResponseWriter, r *http.Request) {
  871. w.Header().Set("Content-Type", "application/json")
  872. user := r.Header.Get("user")
  873. go func() {
  874. slog.Info("requesting all hosts to sync", "user", user)
  875. hosts, err := logic.GetAllHosts()
  876. if err != nil {
  877. slog.Error("failed to retrieve all hosts", "user", user, "error", err)
  878. return
  879. }
  880. for _, host := range hosts {
  881. go func(host models.Host) {
  882. hostUpdate := models.HostUpdate{
  883. Action: models.RequestPull,
  884. Host: host,
  885. }
  886. if err = mq.HostUpdate(&hostUpdate); err != nil {
  887. slog.Error("failed to request host to sync", "user", user, "host", host.ID.String(), "error", err)
  888. } else {
  889. slog.Info("host sync requested", "user", user, "host", host.ID.String())
  890. }
  891. }(host)
  892. }
  893. }()
  894. slog.Info("sync all hosts request received", "user", user)
  895. logic.ReturnSuccessResponse(w, r, "sync all hosts request received")
  896. }
  897. // @Summary Requests a host to pull
  898. // @Router /api/hosts/{hostid}/sync [post]
  899. // @Tags Hosts
  900. // @Security oauth
  901. // @Param hostid path string true "Host ID"
  902. // @Success 200 {string} string "OK"
  903. // @Failure 400 {object} models.ErrorResponse
  904. func syncHost(w http.ResponseWriter, r *http.Request) {
  905. hostId := mux.Vars(r)["hostid"]
  906. var errorResponse = models.ErrorResponse{}
  907. w.Header().Set("Content-Type", "application/json")
  908. host, err := logic.GetHost(hostId)
  909. if err != nil {
  910. slog.Error("failed to retrieve host", "user", r.Header.Get("user"), "error", err)
  911. errorResponse.Code = http.StatusBadRequest
  912. errorResponse.Message = err.Error()
  913. logic.ReturnErrorResponse(w, r, errorResponse)
  914. return
  915. }
  916. go func() {
  917. hostUpdate := models.HostUpdate{
  918. Action: models.RequestPull,
  919. Host: *host,
  920. }
  921. if err = mq.HostUpdate(&hostUpdate); err != nil {
  922. slog.Error("failed to send host pull request", "host", host.ID.String(), "error", err)
  923. }
  924. }()
  925. slog.Info("requested host pull", "user", r.Header.Get("user"), "host", host.ID.String())
  926. w.WriteHeader(http.StatusOK)
  927. }
  928. // @Summary Deletes all EMQX hosts
  929. // @Router /api/emqx/hosts [delete]
  930. // @Tags Hosts
  931. // @Security oauth
  932. // @Success 200 {string} string "deleted hosts data on emqx"
  933. // @Failure 500 {object} models.ErrorResponse
  934. func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
  935. currentHosts, err := logic.GetAllHosts()
  936. if err != nil {
  937. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  938. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  939. return
  940. }
  941. for _, host := range currentHosts {
  942. // delete EMQX credentials for host
  943. if err := mq.GetEmqxHandler().DeleteEmqxUser(host.ID.String()); err != nil {
  944. slog.Error("failed to remove host credentials from EMQX", "id", host.ID, "error", err)
  945. }
  946. }
  947. err = mq.GetEmqxHandler().DeleteEmqxUser(servercfg.GetMqUserName())
  948. if err != nil {
  949. slog.Error(
  950. "failed to remove server credentials from EMQX",
  951. "user",
  952. servercfg.GetMqUserName(),
  953. "error",
  954. err,
  955. )
  956. }
  957. logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx")
  958. }