hosts.go 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331
  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "time"
  8. "github.com/google/uuid"
  9. "github.com/gorilla/mux"
  10. "github.com/gravitl/netmaker/database"
  11. "github.com/gravitl/netmaker/db"
  12. "github.com/gravitl/netmaker/logger"
  13. "github.com/gravitl/netmaker/logic"
  14. "github.com/gravitl/netmaker/models"
  15. "github.com/gravitl/netmaker/mq"
  16. "github.com/gravitl/netmaker/schema"
  17. "github.com/gravitl/netmaker/servercfg"
  18. "golang.org/x/crypto/bcrypt"
  19. "golang.org/x/exp/slog"
  20. )
  21. func hostHandlers(r *mux.Router) {
  22. r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).
  23. Methods(http.MethodGet)
  24. r.HandleFunc("/api/hosts/keys", logic.SecurityCheck(true, http.HandlerFunc(updateAllKeys))).
  25. Methods(http.MethodPut)
  26. r.HandleFunc("/api/hosts/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHosts))).
  27. Methods(http.MethodPost)
  28. r.HandleFunc("/api/hosts/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHosts))).
  29. Methods(http.MethodPost)
  30. r.HandleFunc("/api/hosts/{hostid}/keys", logic.SecurityCheck(true, http.HandlerFunc(updateKeys))).
  31. Methods(http.MethodPut)
  32. r.HandleFunc("/api/hosts/{hostid}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncHost))).
  33. Methods(http.MethodPost)
  34. r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).
  35. Methods(http.MethodPut)
  36. r.HandleFunc("/api/hosts/{hostid}", Authorize(true, false, "all", http.HandlerFunc(deleteHost))).
  37. Methods(http.MethodDelete)
  38. r.HandleFunc("/api/hosts/{hostid}/upgrade", logic.SecurityCheck(true, http.HandlerFunc(upgradeHost))).
  39. Methods(http.MethodPut)
  40. r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).
  41. Methods(http.MethodPost)
  42. r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).
  43. Methods(http.MethodDelete)
  44. r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost)
  45. r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).
  46. Methods(http.MethodGet)
  47. r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).
  48. Methods(http.MethodPost)
  49. r.HandleFunc("/api/v1/fallback/host/{hostid}", Authorize(true, false, "host", http.HandlerFunc(hostUpdateFallback))).
  50. Methods(http.MethodPut)
  51. r.HandleFunc("/api/v1/host/{hostid}/peer_info", Authorize(true, false, "host", http.HandlerFunc(getHostPeerInfo))).
  52. Methods(http.MethodGet)
  53. r.HandleFunc("/api/v1/pending_hosts", logic.SecurityCheck(true, http.HandlerFunc(getPendingHosts))).
  54. Methods(http.MethodGet)
  55. r.HandleFunc("/api/v1/pending_hosts/approve/{id}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingHost))).
  56. Methods(http.MethodPost)
  57. r.HandleFunc("/api/v1/pending_hosts/reject/{id}", logic.SecurityCheck(true, http.HandlerFunc(rejectPendingHost))).
  58. Methods(http.MethodPost)
  59. r.HandleFunc("/api/emqx/hosts", logic.SecurityCheck(true, http.HandlerFunc(delEmqxHosts))).
  60. Methods(http.MethodDelete)
  61. r.HandleFunc("/api/v1/auth-register/host", socketHandler)
  62. }
  63. // @Summary Requests all the hosts to upgrade their version
  64. // @Router /api/hosts/upgrade [post]
  65. // @Tags Hosts
  66. // @Security oauth
  67. // @Param force query bool false "Force upgrade"
  68. // @Success 200 {string} string "upgrade all hosts request received"
  69. func upgradeHosts(w http.ResponseWriter, r *http.Request) {
  70. w.Header().Set("Content-Type", "application/json")
  71. action := models.Upgrade
  72. if r.URL.Query().Get("force") == "true" {
  73. action = models.ForceUpgrade
  74. }
  75. user := r.Header.Get("user")
  76. go func() {
  77. slog.Info("requesting all hosts to upgrade", "user", user)
  78. hosts, err := logic.GetAllHosts()
  79. if err != nil {
  80. slog.Error("failed to retrieve all hosts", "user", user, "error", err)
  81. return
  82. }
  83. for _, host := range hosts {
  84. go func(host models.Host) {
  85. hostUpdate := models.HostUpdate{
  86. Action: action,
  87. Host: host,
  88. }
  89. if err = mq.HostUpdate(&hostUpdate); err != nil {
  90. slog.Error("failed to request host to upgrade", "user", user, "host", host.ID.String(), "error", err)
  91. } else {
  92. slog.Info("host upgrade requested", "user", user, "host", host.ID.String())
  93. }
  94. }(host)
  95. }
  96. }()
  97. logic.LogEvent(&models.Event{
  98. Action: models.UpgradeAll,
  99. Source: models.Subject{
  100. ID: r.Header.Get("user"),
  101. Name: r.Header.Get("user"),
  102. Type: models.UserSub,
  103. },
  104. TriggeredBy: r.Header.Get("user"),
  105. Target: models.Subject{
  106. ID: "All Hosts",
  107. Name: "All Hosts",
  108. Type: models.DeviceSub,
  109. },
  110. Origin: models.Dashboard,
  111. })
  112. slog.Info("upgrade all hosts request received", "user", user)
  113. logic.ReturnSuccessResponse(w, r, "upgrade all hosts request received")
  114. }
  115. // @Summary Upgrade a host
  116. // @Router /api/hosts/{hostid}/upgrade [put]
  117. // @Tags Hosts
  118. // @Security oauth
  119. // @Param hostid path string true "Host ID"
  120. // @Param force query bool false "Force upgrade"
  121. // @Success 200 {string} string "passed message to upgrade host"
  122. // @Failure 500 {object} models.ErrorResponse
  123. // upgrade host is a handler to send upgrade message to a host
  124. func upgradeHost(w http.ResponseWriter, r *http.Request) {
  125. host, err := logic.GetHost(mux.Vars(r)["hostid"])
  126. if err != nil {
  127. slog.Error("failed to find host", "error", err)
  128. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "notfound"))
  129. return
  130. }
  131. action := models.Upgrade
  132. if r.URL.Query().Get("force") == "true" {
  133. action = models.ForceUpgrade
  134. }
  135. if err := mq.HostUpdate(&models.HostUpdate{Action: action, Host: *host}); err != nil {
  136. slog.Error("failed to upgrade host", "error", err)
  137. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  138. return
  139. }
  140. logic.ReturnSuccessResponse(w, r, "passed message to upgrade host")
  141. }
  142. // @Summary List all hosts
  143. // @Router /api/hosts [get]
  144. // @Tags Hosts
  145. // @Security oauth
  146. // @Success 200 {array} models.ApiHost
  147. // @Failure 500 {object} models.ErrorResponse
  148. func getHosts(w http.ResponseWriter, r *http.Request) {
  149. w.Header().Set("Content-Type", "application/json")
  150. currentHosts, err := logic.GetAllHosts()
  151. if err != nil {
  152. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  153. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  154. return
  155. }
  156. apiHosts := logic.GetAllHostsAPI(currentHosts[:])
  157. logger.Log(2, r.Header.Get("user"), "fetched all hosts")
  158. logic.SortApiHosts(apiHosts[:])
  159. w.WriteHeader(http.StatusOK)
  160. json.NewEncoder(w).Encode(apiHosts)
  161. }
  162. // @Summary Used by clients for "pull" command
  163. // @Router /api/v1/host [get]
  164. // @Tags Hosts
  165. // @Security oauth
  166. // @Success 200 {object} models.HostPull
  167. // @Failure 500 {object} models.ErrorResponse
  168. func pull(w http.ResponseWriter, r *http.Request) {
  169. hostID := r.Header.Get(hostIDHeader) // return JSON/API formatted keys
  170. if len(hostID) == 0 {
  171. logger.Log(0, "no host authorized to pull")
  172. logic.ReturnErrorResponse(
  173. w,
  174. r,
  175. logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal"),
  176. )
  177. return
  178. }
  179. host, err := logic.GetHost(hostID)
  180. if err != nil {
  181. logger.Log(0, "no host found during pull", hostID)
  182. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  183. return
  184. }
  185. sendPeerUpdate := false
  186. for _, nodeID := range host.Nodes {
  187. node, err := logic.GetNodeByID(nodeID)
  188. if err != nil {
  189. //slog.Error("failed to get node:", "id", node.ID, "error", err)
  190. continue
  191. }
  192. if r.URL.Query().Get("reset_failovered") == "true" {
  193. logic.ResetFailedOverPeer(&node)
  194. logic.ResetAutoRelayedPeer(&node)
  195. sendPeerUpdate = true
  196. }
  197. }
  198. if sendPeerUpdate {
  199. if err := mq.PublishPeerUpdate(false); err != nil {
  200. logger.Log(0, "fail to publish peer update: ", err.Error())
  201. }
  202. }
  203. allNodes, err := logic.GetAllNodes()
  204. if err != nil {
  205. logger.Log(0, "failed to get nodes: ", hostID)
  206. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  207. return
  208. }
  209. hPU, err := logic.GetPeerUpdateForHost("", host, allNodes, nil, nil)
  210. if err != nil {
  211. logger.Log(0, "could not pull peers for host", hostID, err.Error())
  212. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  213. return
  214. }
  215. _ = logic.CheckHostPorts(host)
  216. response := models.HostPull{
  217. Host: *host,
  218. Nodes: logic.GetHostNodes(host),
  219. ServerConfig: hPU.ServerConfig,
  220. Peers: hPU.Peers,
  221. PeerIDs: hPU.PeerIDs,
  222. HostNetworkInfo: hPU.HostNetworkInfo,
  223. EgressRoutes: hPU.EgressRoutes,
  224. FwUpdate: hPU.FwUpdate,
  225. ChangeDefaultGw: hPU.ChangeDefaultGw,
  226. DefaultGwIp: hPU.DefaultGwIp,
  227. IsInternetGw: hPU.IsInternetGw,
  228. NameServers: hPU.NameServers,
  229. EgressWithDomains: hPU.EgressWithDomains,
  230. EndpointDetection: logic.IsEndpointDetectionEnabled(),
  231. DnsNameservers: hPU.DnsNameservers,
  232. ReplacePeers: hPU.ReplacePeers,
  233. AutoRelayNodes: hPU.AutoRelayNodes,
  234. GwNodes: hPU.GwNodes,
  235. }
  236. logger.Log(1, hostID, host.Name, "completed a pull")
  237. w.WriteHeader(http.StatusOK)
  238. json.NewEncoder(w).Encode(&response)
  239. }
  240. // @Summary Updates a Netclient host on Netmaker server
  241. // @Router /api/hosts/{hostid} [put]
  242. // @Tags Hosts
  243. // @Security oauth
  244. // @Param hostid path string true "Host ID"
  245. // @Param body body models.ApiHost true "New host data"
  246. // @Success 200 {object} models.ApiHost
  247. // @Failure 500 {object} models.ErrorResponse
  248. func updateHost(w http.ResponseWriter, r *http.Request) {
  249. var newHostData models.ApiHost
  250. err := json.NewDecoder(r.Body).Decode(&newHostData)
  251. if err != nil {
  252. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  253. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  254. return
  255. }
  256. // confirm host exists
  257. currHost, err := logic.GetHost(newHostData.ID)
  258. if err != nil {
  259. logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error())
  260. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  261. return
  262. }
  263. newHost := newHostData.ConvertAPIHostToNMHost(currHost)
  264. logic.UpdateHost(newHost, currHost) // update the in memory struct values
  265. if newHost.DNS != "yes" {
  266. // check if any node is internet gw
  267. for _, nodeID := range newHost.Nodes {
  268. node, err := logic.GetNodeByID(nodeID)
  269. if err != nil {
  270. continue
  271. }
  272. if node.IsInternetGateway {
  273. newHost.DNS = "yes"
  274. break
  275. }
  276. }
  277. }
  278. if err = logic.UpsertHost(newHost); 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. // publish host update through MQ
  284. if err := mq.HostUpdate(&models.HostUpdate{
  285. Action: models.UpdateHost,
  286. Host: *newHost,
  287. }); err != nil {
  288. logger.Log(
  289. 0,
  290. r.Header.Get("user"),
  291. "failed to send host update: ",
  292. currHost.ID.String(),
  293. err.Error(),
  294. )
  295. }
  296. go func() {
  297. if err := mq.PublishPeerUpdate(false); err != nil {
  298. logger.Log(0, "fail to publish peer update: ", err.Error())
  299. }
  300. if newHost.Name != currHost.Name {
  301. if servercfg.IsDNSMode() {
  302. logic.SetDNS()
  303. }
  304. }
  305. }()
  306. logic.LogEvent(&models.Event{
  307. Action: models.Update,
  308. Source: models.Subject{
  309. ID: r.Header.Get("user"),
  310. Name: r.Header.Get("user"),
  311. Type: models.UserSub,
  312. },
  313. TriggeredBy: r.Header.Get("user"),
  314. Target: models.Subject{
  315. ID: currHost.ID.String(),
  316. Name: newHost.Name,
  317. Type: models.DeviceSub,
  318. },
  319. Diff: models.Diff{
  320. Old: currHost,
  321. New: newHost,
  322. },
  323. Origin: models.Dashboard,
  324. })
  325. apiHostData := newHost.ConvertNMHostToAPI()
  326. logger.Log(2, r.Header.Get("user"), "updated host", newHost.ID.String())
  327. w.WriteHeader(http.StatusOK)
  328. json.NewEncoder(w).Encode(apiHostData)
  329. }
  330. // @Summary Updates a Netclient host on Netmaker server
  331. // @Router /api/v1/fallback/host/{hostid} [put]
  332. // @Tags Hosts
  333. // @Security oauth
  334. // @Param hostid path string true "Host ID"
  335. // @Param body body models.HostUpdate true "Host update data"
  336. // @Success 200 {string} string "updated host data"
  337. // @Failure 500 {object} models.ErrorResponse
  338. func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
  339. var params = mux.Vars(r)
  340. hostid := params["hostid"]
  341. currentHost, err := logic.GetHost(hostid)
  342. if err != nil {
  343. slog.Error("error getting host", "id", hostid, "error", err)
  344. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  345. return
  346. }
  347. var sendPeerUpdate, sendDeletedNodeUpdate, replacePeers bool
  348. var hostUpdate models.HostUpdate
  349. err = json.NewDecoder(r.Body).Decode(&hostUpdate)
  350. if err != nil {
  351. slog.Error("failed to update a host:", "user", r.Header.Get("user"), "error", err.Error(), "host", currentHost.Name)
  352. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  353. return
  354. }
  355. slog.Info("recieved host update", "name", hostUpdate.Host.Name, "id", hostUpdate.Host.ID, "action", hostUpdate.Action)
  356. switch hostUpdate.Action {
  357. case models.CheckIn:
  358. sendPeerUpdate = mq.HandleHostCheckin(&hostUpdate.Host, currentHost)
  359. changed := logic.CheckHostPorts(currentHost)
  360. if changed {
  361. mq.HostUpdate(&models.HostUpdate{Action: models.UpdateHost, Host: *currentHost})
  362. }
  363. case models.UpdateHost:
  364. if hostUpdate.Host.PublicKey != currentHost.PublicKey {
  365. //remove old peer entry
  366. replacePeers = true
  367. }
  368. sendPeerUpdate = logic.UpdateHostFromClient(&hostUpdate.Host, currentHost)
  369. err := logic.UpsertHost(currentHost)
  370. if err != nil {
  371. slog.Error("failed to update host", "id", currentHost.ID, "error", err)
  372. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.Internal))
  373. return
  374. }
  375. case models.UpdateNode:
  376. sendDeletedNodeUpdate, sendPeerUpdate = logic.UpdateHostNode(&hostUpdate.Host, &hostUpdate.Node)
  377. case models.UpdateMetrics:
  378. mq.UpdateMetricsFallBack(hostUpdate.Node.ID.String(), hostUpdate.NewMetrics)
  379. case models.EgressUpdate:
  380. e := schema.Egress{ID: hostUpdate.EgressDomain.ID}
  381. err = e.Get(db.WithContext(r.Context()))
  382. if err != nil {
  383. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
  384. return
  385. }
  386. if len(hostUpdate.Node.EgressGatewayRanges) > 0 {
  387. e.DomainAns = hostUpdate.Node.EgressGatewayRanges
  388. e.Update(db.WithContext(r.Context()))
  389. }
  390. sendPeerUpdate = true
  391. case models.SignalHost:
  392. mq.SignalPeer(hostUpdate.Signal)
  393. case models.DeleteHost:
  394. go mq.DeleteAndCleanupHost(currentHost)
  395. }
  396. go func() {
  397. if sendDeletedNodeUpdate {
  398. mq.PublishDeletedNodePeerUpdate(&hostUpdate.Node)
  399. }
  400. if sendPeerUpdate {
  401. err := mq.PublishPeerUpdate(replacePeers)
  402. if err != nil {
  403. slog.Error("failed to publish peer update", "error", err)
  404. }
  405. }
  406. }()
  407. logic.ReturnSuccessResponse(w, r, "updated host data")
  408. }
  409. // @Summary Deletes a Netclient host from Netmaker server
  410. // @Router /api/hosts/{hostid} [delete]
  411. // @Tags Hosts
  412. // @Security oauth
  413. // @Param hostid path string true "Host ID"
  414. // @Param force query bool false "Force delete"
  415. // @Success 200 {object} models.ApiHost
  416. // @Failure 500 {object} models.ErrorResponse
  417. func deleteHost(w http.ResponseWriter, r *http.Request) {
  418. var params = mux.Vars(r)
  419. hostid := params["hostid"]
  420. forceDelete := r.URL.Query().Get("force") == "true"
  421. // confirm host exists
  422. currHost, err := logic.GetHost(hostid)
  423. if err != nil {
  424. logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
  425. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  426. return
  427. }
  428. for _, nodeID := range currHost.Nodes {
  429. node, err := logic.GetNodeByID(nodeID)
  430. if err != nil {
  431. slog.Error("failed to get node", "nodeid", nodeID, "error", err)
  432. continue
  433. }
  434. go mq.PublishMqUpdatesForDeletedNode(node, false)
  435. }
  436. if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
  437. // delete EMQX credentials for host
  438. if err := mq.GetEmqxHandler().DeleteEmqxUser(currHost.ID.String()); err != nil {
  439. slog.Error(
  440. "failed to remove host credentials from EMQX",
  441. "id",
  442. currHost.ID,
  443. "error",
  444. err,
  445. )
  446. }
  447. }
  448. if err = mq.HostUpdate(&models.HostUpdate{
  449. Action: models.DeleteHost,
  450. Host: *currHost,
  451. }); err != nil {
  452. logger.Log(
  453. 0,
  454. r.Header.Get("user"),
  455. "failed to send delete host update: ",
  456. currHost.ID.String(),
  457. err.Error(),
  458. )
  459. }
  460. if err = logic.RemoveHost(currHost, forceDelete); err != nil {
  461. logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
  462. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  463. return
  464. }
  465. // delete if any pending reqs
  466. (&schema.PendingHost{
  467. HostID: currHost.ID.String(),
  468. }).DeleteAllPendingHosts(db.WithContext(r.Context()))
  469. logic.LogEvent(&models.Event{
  470. Action: models.Delete,
  471. Source: models.Subject{
  472. ID: r.Header.Get("user"),
  473. Name: r.Header.Get("user"),
  474. Type: models.UserSub,
  475. },
  476. TriggeredBy: r.Header.Get("user"),
  477. Target: models.Subject{
  478. ID: currHost.ID.String(),
  479. Name: currHost.Name,
  480. Type: models.DeviceSub,
  481. },
  482. Origin: models.Dashboard,
  483. Diff: models.Diff{
  484. Old: currHost,
  485. New: nil,
  486. },
  487. })
  488. apiHostData := currHost.ConvertNMHostToAPI()
  489. logger.Log(2, r.Header.Get("user"), "removed host", currHost.Name)
  490. w.WriteHeader(http.StatusOK)
  491. json.NewEncoder(w).Encode(apiHostData)
  492. }
  493. // @Summary To Add Host To Network
  494. // @Router /api/hosts/{hostid}/networks/{network} [post]
  495. // @Tags Hosts
  496. // @Security oauth
  497. // @Param hostid path string true "Host ID"
  498. // @Param network path string true "Network name"
  499. // @Success 200 {string} string "OK"
  500. // @Failure 500 {object} models.ErrorResponse
  501. func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
  502. var params = mux.Vars(r)
  503. hostid := params["hostid"]
  504. network := params["network"]
  505. if hostid == "" || network == "" {
  506. logic.ReturnErrorResponse(
  507. w,
  508. r,
  509. logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
  510. )
  511. return
  512. }
  513. // confirm host exists
  514. currHost, err := logic.GetHost(hostid)
  515. if err != nil {
  516. logger.Log(0, r.Header.Get("user"), "failed to find host:", hostid, err.Error())
  517. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  518. return
  519. }
  520. newNode, err := logic.UpdateHostNetwork(currHost, network, true)
  521. if err != nil {
  522. logger.Log(
  523. 0,
  524. r.Header.Get("user"),
  525. "failed to add host to network:",
  526. hostid,
  527. network,
  528. err.Error(),
  529. )
  530. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  531. return
  532. }
  533. logger.Log(1, "added new node", newNode.ID.String(), "to host", currHost.Name)
  534. if currHost.IsDefault {
  535. // make host failover
  536. logic.CreateFailOver(*newNode)
  537. // make host remote access gateway
  538. logic.CreateIngressGateway(network, newNode.ID.String(), models.IngressRequest{})
  539. logic.CreateRelay(models.RelayRequest{
  540. NodeID: newNode.ID.String(),
  541. NetID: network,
  542. })
  543. }
  544. go func() {
  545. mq.HostUpdate(&models.HostUpdate{
  546. Action: models.JoinHostToNetwork,
  547. Host: *currHost,
  548. Node: *newNode,
  549. })
  550. mq.PublishPeerUpdate(false)
  551. if servercfg.IsDNSMode() {
  552. logic.SetDNS()
  553. }
  554. }()
  555. logger.Log(
  556. 2,
  557. r.Header.Get("user"),
  558. fmt.Sprintf("added host %s to network %s", currHost.Name, network),
  559. )
  560. logic.LogEvent(&models.Event{
  561. Action: models.JoinHostToNet,
  562. Source: models.Subject{
  563. ID: r.Header.Get("user"),
  564. Name: r.Header.Get("user"),
  565. Type: models.UserSub,
  566. },
  567. TriggeredBy: r.Header.Get("user"),
  568. Target: models.Subject{
  569. ID: currHost.ID.String(),
  570. Name: currHost.Name,
  571. Type: models.DeviceSub,
  572. },
  573. NetworkID: models.NetworkID(network),
  574. Origin: models.Dashboard,
  575. })
  576. w.WriteHeader(http.StatusOK)
  577. }
  578. // @Summary To Remove Host from Network
  579. // @Router /api/hosts/{hostid}/networks/{network} [delete]
  580. // @Tags Hosts
  581. // @Security oauth
  582. // @Param hostid path string true "Host ID"
  583. // @Param network path string true "Network name"
  584. // @Param force query bool false "Force delete"
  585. // @Success 200 {string} string "OK"
  586. // @Failure 500 {object} models.ErrorResponse
  587. func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
  588. var params = mux.Vars(r)
  589. hostid := params["hostid"]
  590. network := params["network"]
  591. forceDelete := r.URL.Query().Get("force") == "true"
  592. if hostid == "" || network == "" {
  593. logic.ReturnErrorResponse(
  594. w,
  595. r,
  596. logic.FormatError(errors.New("hostid or network cannot be empty"), "badrequest"),
  597. )
  598. return
  599. }
  600. // confirm host exists
  601. currHost, err := logic.GetHost(hostid)
  602. if err != nil {
  603. if database.IsEmptyRecord(err) {
  604. // check if there is any daemon nodes that needs to be deleted
  605. node, err := logic.GetNodeByHostRef(hostid, network)
  606. if err != nil {
  607. slog.Error(
  608. "couldn't get node for host",
  609. "hostid",
  610. hostid,
  611. "network",
  612. network,
  613. "error",
  614. err,
  615. )
  616. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  617. return
  618. }
  619. if err = logic.DeleteNodeByID(&node); err != nil {
  620. slog.Error("failed to force delete daemon node",
  621. "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
  622. logic.ReturnErrorResponse(
  623. w,
  624. r,
  625. logic.FormatError(
  626. fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
  627. "internal",
  628. ),
  629. )
  630. return
  631. }
  632. logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
  633. return
  634. }
  635. logger.Log(0, r.Header.Get("user"), "failed to find host:", err.Error())
  636. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  637. return
  638. }
  639. node, err := logic.UpdateHostNetwork(currHost, network, false)
  640. if err != nil {
  641. if node == nil && forceDelete {
  642. // force cleanup the node
  643. node, err := logic.GetNodeByHostRef(hostid, network)
  644. if err != nil {
  645. slog.Error(
  646. "couldn't get node for host",
  647. "hostid",
  648. hostid,
  649. "network",
  650. network,
  651. "error",
  652. err,
  653. )
  654. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  655. return
  656. }
  657. if err = logic.DeleteNodeByID(&node); err != nil {
  658. slog.Error("failed to force delete daemon node",
  659. "nodeid", node.ID.String(), "hostid", hostid, "network", network, "error", err)
  660. logic.ReturnErrorResponse(
  661. w,
  662. r,
  663. logic.FormatError(
  664. fmt.Errorf("failed to force delete daemon node: %s", err.Error()),
  665. "internal",
  666. ),
  667. )
  668. return
  669. }
  670. logic.ReturnSuccessResponse(w, r, "force deleted daemon node successfully")
  671. return
  672. }
  673. logger.Log(
  674. 0,
  675. r.Header.Get("user"),
  676. "failed to remove host from network:",
  677. hostid,
  678. network,
  679. err.Error(),
  680. )
  681. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  682. return
  683. }
  684. logger.Log(1, "deleting node", node.ID.String(), "from host", currHost.Name)
  685. if err := logic.DeleteNode(node, forceDelete); err != nil {
  686. logic.ReturnErrorResponse(
  687. w,
  688. r,
  689. logic.FormatError(fmt.Errorf("failed to delete node"), "internal"),
  690. )
  691. return
  692. }
  693. go func() {
  694. mq.PublishMqUpdatesForDeletedNode(*node, true)
  695. if servercfg.IsDNSMode() {
  696. logic.SetDNS()
  697. }
  698. }()
  699. logic.LogEvent(&models.Event{
  700. Action: models.RemoveHostFromNet,
  701. Source: models.Subject{
  702. ID: r.Header.Get("user"),
  703. Name: r.Header.Get("user"),
  704. Type: models.UserSub,
  705. },
  706. TriggeredBy: r.Header.Get("user"),
  707. Target: models.Subject{
  708. ID: currHost.ID.String(),
  709. Name: currHost.Name,
  710. Type: models.DeviceSub,
  711. },
  712. NetworkID: models.NetworkID(network),
  713. Origin: models.Dashboard,
  714. })
  715. logger.Log(
  716. 2,
  717. r.Header.Get("user"),
  718. fmt.Sprintf("removed host %s from network %s", currHost.Name, network),
  719. )
  720. w.WriteHeader(http.StatusOK)
  721. }
  722. // @Summary To Fetch Auth Token for a Host
  723. // @Router /api/hosts/adm/authenticate [post]
  724. // @Tags Auth
  725. // @Accept json
  726. // @Param body body models.AuthParams true "Authentication parameters"
  727. // @Success 200 {object} models.SuccessResponse
  728. // @Failure 400 {object} models.ErrorResponse
  729. // @Failure 401 {object} models.ErrorResponse
  730. // @Failure 500 {object} models.ErrorResponse
  731. func authenticateHost(response http.ResponseWriter, request *http.Request) {
  732. var authRequest models.AuthParams
  733. var errorResponse = models.ErrorResponse{
  734. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  735. }
  736. decoder := json.NewDecoder(request.Body)
  737. decoderErr := decoder.Decode(&authRequest)
  738. defer request.Body.Close()
  739. if decoderErr != nil {
  740. errorResponse.Code = http.StatusBadRequest
  741. errorResponse.Message = decoderErr.Error()
  742. logger.Log(0, request.Header.Get("user"), "error decoding request body: ",
  743. decoderErr.Error())
  744. logic.ReturnErrorResponse(response, request, errorResponse)
  745. return
  746. }
  747. errorResponse.Code = http.StatusBadRequest
  748. if authRequest.ID == "" {
  749. errorResponse.Message = "W1R3: ID can't be empty"
  750. logger.Log(0, request.Header.Get("user"), errorResponse.Message)
  751. logic.ReturnErrorResponse(response, request, errorResponse)
  752. return
  753. } else if authRequest.Password == "" {
  754. errorResponse.Message = "W1R3: Password can't be empty"
  755. logger.Log(0, request.Header.Get("user"), errorResponse.Message)
  756. logic.ReturnErrorResponse(response, request, errorResponse)
  757. return
  758. }
  759. host, err := logic.GetHost(authRequest.ID)
  760. if err != nil {
  761. errorResponse.Code = http.StatusBadRequest
  762. errorResponse.Message = err.Error()
  763. logger.Log(0, request.Header.Get("user"),
  764. "error retrieving host: ", authRequest.ID, err.Error())
  765. logic.ReturnErrorResponse(response, request, errorResponse)
  766. return
  767. }
  768. err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password))
  769. if err != nil {
  770. errorResponse.Code = http.StatusUnauthorized
  771. errorResponse.Message = "unauthorized"
  772. logger.Log(0, request.Header.Get("user"),
  773. "error validating user password: ", err.Error())
  774. logic.ReturnErrorResponse(response, request, errorResponse)
  775. return
  776. }
  777. tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, "")
  778. if tokenString == "" {
  779. errorResponse.Code = http.StatusUnauthorized
  780. errorResponse.Message = "unauthorized"
  781. logger.Log(0, request.Header.Get("user"),
  782. fmt.Sprintf("%s: %v", errorResponse.Message, err))
  783. logic.ReturnErrorResponse(response, request, errorResponse)
  784. return
  785. }
  786. var successResponse = models.SuccessResponse{
  787. Code: http.StatusOK,
  788. Message: "W1R3: Host " + authRequest.ID + " Authorized",
  789. Response: models.SuccessfulLoginResponse{
  790. AuthToken: tokenString,
  791. ID: authRequest.ID,
  792. },
  793. }
  794. successJSONResponse, jsonError := json.Marshal(successResponse)
  795. if jsonError != nil {
  796. errorResponse.Code = http.StatusBadRequest
  797. errorResponse.Message = err.Error()
  798. logger.Log(0, request.Header.Get("user"),
  799. "error marshalling resp: ", err.Error())
  800. logic.ReturnErrorResponse(response, request, errorResponse)
  801. return
  802. }
  803. go func() {
  804. // Create EMQX creds
  805. if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
  806. if err := mq.GetEmqxHandler().CreateEmqxUser(host.ID.String(), authRequest.Password); err != nil {
  807. slog.Error("failed to create host credentials for EMQX: ", err.Error())
  808. }
  809. }
  810. }()
  811. response.WriteHeader(http.StatusOK)
  812. response.Header().Set("Content-Type", "application/json")
  813. response.Write(successJSONResponse)
  814. }
  815. // @Summary Send signal to peer
  816. // @Router /api/v1/host/{hostid}/signalpeer [post]
  817. // @Tags Hosts
  818. // @Security oauth
  819. // @Param hostid path string true "Host ID"
  820. // @Param body body models.Signal true "Signal data"
  821. // @Success 200 {object} models.Signal
  822. // @Failure 400 {object} models.ErrorResponse
  823. func signalPeer(w http.ResponseWriter, r *http.Request) {
  824. var params = mux.Vars(r)
  825. hostid := params["hostid"]
  826. // confirm host exists
  827. _, err := logic.GetHost(hostid)
  828. if err != nil {
  829. logger.Log(0, r.Header.Get("user"), "failed to get host:", err.Error())
  830. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  831. return
  832. }
  833. var signal models.Signal
  834. w.Header().Set("Content-Type", "application/json")
  835. err = json.NewDecoder(r.Body).Decode(&signal)
  836. if err != nil {
  837. logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
  838. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  839. return
  840. }
  841. if signal.ToHostPubKey == "" {
  842. msg := "insufficient data to signal peer"
  843. logger.Log(0, r.Header.Get("user"), msg)
  844. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New(msg), "badrequest"))
  845. return
  846. }
  847. signal.IsPro = servercfg.IsPro
  848. peerHost, err := logic.GetHost(signal.ToHostID)
  849. if err != nil {
  850. logic.ReturnErrorResponse(
  851. w,
  852. r,
  853. logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"),
  854. )
  855. return
  856. }
  857. err = mq.HostUpdate(&models.HostUpdate{
  858. Action: models.SignalHost,
  859. Host: *peerHost,
  860. Signal: signal,
  861. })
  862. if err != nil {
  863. logic.ReturnErrorResponse(
  864. w,
  865. r,
  866. logic.FormatError(
  867. errors.New("failed to publish signal to peer: "+err.Error()),
  868. "badrequest",
  869. ),
  870. )
  871. return
  872. }
  873. w.WriteHeader(http.StatusOK)
  874. json.NewEncoder(w).Encode(signal)
  875. }
  876. // @Summary Update keys for all hosts
  877. // @Router /api/hosts/keys [put]
  878. // @Tags Hosts
  879. // @Security oauth
  880. // @Success 200 {string} string "OK"
  881. // @Failure 400 {object} models.ErrorResponse
  882. func updateAllKeys(w http.ResponseWriter, r *http.Request) {
  883. var errorResponse = models.ErrorResponse{}
  884. w.Header().Set("Content-Type", "application/json")
  885. hosts, err := logic.GetAllHosts()
  886. if err != nil {
  887. errorResponse.Code = http.StatusBadRequest
  888. errorResponse.Message = err.Error()
  889. logger.Log(0, r.Header.Get("user"),
  890. "error retrieving hosts ", err.Error())
  891. logic.ReturnErrorResponse(w, r, errorResponse)
  892. return
  893. }
  894. go func() {
  895. hostUpdate := models.HostUpdate{}
  896. hostUpdate.Action = models.UpdateKeys
  897. for _, host := range hosts {
  898. hostUpdate.Host = host
  899. logger.Log(2, "updating host", host.ID.String(), " for a key update")
  900. if err = mq.HostUpdate(&hostUpdate); err != nil {
  901. logger.Log(
  902. 0,
  903. "failed to send update to node during a network wide key update",
  904. host.ID.String(),
  905. err.Error(),
  906. )
  907. }
  908. }
  909. }()
  910. logic.LogEvent(&models.Event{
  911. Action: models.RefreshAllKeys,
  912. Source: models.Subject{
  913. ID: r.Header.Get("user"),
  914. Name: r.Header.Get("user"),
  915. Type: models.UserSub,
  916. },
  917. TriggeredBy: r.Header.Get("user"),
  918. Target: models.Subject{
  919. ID: "All Devices",
  920. Name: "All Devices",
  921. Type: models.DeviceSub,
  922. },
  923. Origin: models.Dashboard,
  924. })
  925. logger.Log(2, r.Header.Get("user"), "updated keys for all hosts")
  926. w.WriteHeader(http.StatusOK)
  927. }
  928. // @Summary Update keys for a host
  929. // @Router /api/hosts/{hostid}/keys [put]
  930. // @Tags Hosts
  931. // @Security oauth
  932. // @Param hostid path string true "Host ID"
  933. // @Success 200 {string} string "OK"
  934. // @Failure 400 {object} models.ErrorResponse
  935. func updateKeys(w http.ResponseWriter, r *http.Request) {
  936. var errorResponse = models.ErrorResponse{}
  937. w.Header().Set("Content-Type", "application/json")
  938. var params = mux.Vars(r)
  939. hostid := params["hostid"]
  940. host, err := logic.GetHost(hostid)
  941. if err != nil {
  942. logger.Log(0, "failed to retrieve host", hostid, err.Error())
  943. errorResponse.Code = http.StatusBadRequest
  944. errorResponse.Message = err.Error()
  945. logger.Log(0, r.Header.Get("user"),
  946. "error retrieving hosts ", err.Error())
  947. logic.ReturnErrorResponse(w, r, errorResponse)
  948. return
  949. }
  950. go func() {
  951. hostUpdate := models.HostUpdate{
  952. Action: models.UpdateKeys,
  953. Host: *host,
  954. }
  955. if err = mq.HostUpdate(&hostUpdate); err != nil {
  956. logger.Log(0, "failed to send host key update", host.ID.String(), err.Error())
  957. }
  958. }()
  959. logic.LogEvent(&models.Event{
  960. Action: models.RefreshKey,
  961. Source: models.Subject{
  962. ID: r.Header.Get("user"),
  963. Name: r.Header.Get("user"),
  964. Type: models.UserSub,
  965. },
  966. TriggeredBy: r.Header.Get("user"),
  967. Target: models.Subject{
  968. ID: host.ID.String(),
  969. Name: host.Name,
  970. Type: models.DeviceSub,
  971. },
  972. Origin: models.Dashboard,
  973. })
  974. logger.Log(2, r.Header.Get("user"), "updated key on host", host.Name)
  975. w.WriteHeader(http.StatusOK)
  976. }
  977. // @Summary Requests all the hosts to pull
  978. // @Router /api/hosts/sync [post]
  979. // @Tags Hosts
  980. // @Security oauth
  981. // @Success 200 {string} string "sync all hosts request received"
  982. func syncHosts(w http.ResponseWriter, r *http.Request) {
  983. w.Header().Set("Content-Type", "application/json")
  984. user := r.Header.Get("user")
  985. go func() {
  986. slog.Info("requesting all hosts to sync", "user", user)
  987. hosts, err := logic.GetAllHosts()
  988. if err != nil {
  989. slog.Error("failed to retrieve all hosts", "user", user, "error", err)
  990. return
  991. }
  992. for _, host := range hosts {
  993. go func(host models.Host) {
  994. hostUpdate := models.HostUpdate{
  995. Action: models.RequestPull,
  996. Host: host,
  997. }
  998. if err = mq.HostUpdate(&hostUpdate); err != nil {
  999. slog.Error("failed to request host to sync", "user", user, "host", host.ID.String(), "error", err)
  1000. } else {
  1001. slog.Info("host sync requested", "user", user, "host", host.ID.String())
  1002. }
  1003. }(host)
  1004. time.Sleep(time.Millisecond * 100)
  1005. }
  1006. }()
  1007. logic.LogEvent(&models.Event{
  1008. Action: models.SyncAll,
  1009. Source: models.Subject{
  1010. ID: r.Header.Get("user"),
  1011. Name: r.Header.Get("user"),
  1012. Type: models.UserSub,
  1013. },
  1014. TriggeredBy: r.Header.Get("user"),
  1015. Target: models.Subject{
  1016. ID: "All Devices",
  1017. Name: "All Devices",
  1018. Type: models.DeviceSub,
  1019. },
  1020. Origin: models.Dashboard,
  1021. })
  1022. slog.Info("sync all hosts request received", "user", user)
  1023. logic.ReturnSuccessResponse(w, r, "sync all hosts request received")
  1024. }
  1025. // @Summary Requests a host to pull
  1026. // @Router /api/hosts/{hostid}/sync [post]
  1027. // @Tags Hosts
  1028. // @Security oauth
  1029. // @Param hostid path string true "Host ID"
  1030. // @Success 200 {string} string "OK"
  1031. // @Failure 400 {object} models.ErrorResponse
  1032. func syncHost(w http.ResponseWriter, r *http.Request) {
  1033. hostId := mux.Vars(r)["hostid"]
  1034. var errorResponse = models.ErrorResponse{}
  1035. w.Header().Set("Content-Type", "application/json")
  1036. host, err := logic.GetHost(hostId)
  1037. if err != nil {
  1038. slog.Error("failed to retrieve host", "user", r.Header.Get("user"), "error", err)
  1039. errorResponse.Code = http.StatusBadRequest
  1040. errorResponse.Message = err.Error()
  1041. logic.ReturnErrorResponse(w, r, errorResponse)
  1042. return
  1043. }
  1044. go func() {
  1045. hostUpdate := models.HostUpdate{
  1046. Action: models.RequestPull,
  1047. Host: *host,
  1048. }
  1049. if err = mq.HostUpdate(&hostUpdate); err != nil {
  1050. slog.Error("failed to send host pull request", "host", host.ID.String(), "error", err)
  1051. }
  1052. }()
  1053. logic.LogEvent(&models.Event{
  1054. Action: models.Sync,
  1055. Source: models.Subject{
  1056. ID: r.Header.Get("user"),
  1057. Name: r.Header.Get("user"),
  1058. Type: models.UserSub,
  1059. },
  1060. TriggeredBy: r.Header.Get("user"),
  1061. Target: models.Subject{
  1062. ID: host.ID.String(),
  1063. Name: host.Name,
  1064. Type: models.DeviceSub,
  1065. },
  1066. Origin: models.Dashboard,
  1067. })
  1068. slog.Info("requested host pull", "user", r.Header.Get("user"), "host", host.ID.String())
  1069. w.WriteHeader(http.StatusOK)
  1070. }
  1071. // @Summary Deletes all EMQX hosts
  1072. // @Router /api/emqx/hosts [delete]
  1073. // @Tags Hosts
  1074. // @Security oauth
  1075. // @Success 200 {string} string "deleted hosts data on emqx"
  1076. // @Failure 500 {object} models.ErrorResponse
  1077. func delEmqxHosts(w http.ResponseWriter, r *http.Request) {
  1078. currentHosts, err := logic.GetAllHosts()
  1079. if err != nil {
  1080. logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
  1081. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1082. return
  1083. }
  1084. for _, host := range currentHosts {
  1085. // delete EMQX credentials for host
  1086. if err := mq.GetEmqxHandler().DeleteEmqxUser(host.ID.String()); err != nil {
  1087. slog.Error("failed to remove host credentials from EMQX", "id", host.ID, "error", err)
  1088. }
  1089. }
  1090. err = mq.GetEmqxHandler().DeleteEmqxUser(servercfg.GetMqUserName())
  1091. if err != nil {
  1092. slog.Error(
  1093. "failed to remove server credentials from EMQX",
  1094. "user",
  1095. servercfg.GetMqUserName(),
  1096. "error",
  1097. err,
  1098. )
  1099. }
  1100. logic.ReturnSuccessResponse(w, r, "deleted hosts data on emqx")
  1101. }
  1102. // @Summary Fetches host peerinfo
  1103. // @Router /api/host/{hostid}/peer_info [get]
  1104. // @Tags Hosts
  1105. // @Security oauth
  1106. // @Param hostid path string true "Host ID"
  1107. // @Success 200 {object} models.SuccessResponse
  1108. // @Failure 500 {object} models.ErrorResponse
  1109. func getHostPeerInfo(w http.ResponseWriter, r *http.Request) {
  1110. hostId := mux.Vars(r)["hostid"]
  1111. var errorResponse = models.ErrorResponse{}
  1112. host, err := logic.GetHost(hostId)
  1113. if err != nil {
  1114. slog.Error("failed to retrieve host", "error", err)
  1115. errorResponse.Code = http.StatusBadRequest
  1116. errorResponse.Message = err.Error()
  1117. logic.ReturnErrorResponse(w, r, errorResponse)
  1118. return
  1119. }
  1120. peerInfo, err := logic.GetHostPeerInfo(host)
  1121. if err != nil {
  1122. slog.Error("failed to retrieve host peerinfo", "error", err)
  1123. errorResponse.Code = http.StatusBadRequest
  1124. errorResponse.Message = err.Error()
  1125. logic.ReturnErrorResponse(w, r, errorResponse)
  1126. return
  1127. }
  1128. logic.ReturnSuccessResponseWithJson(w, r, peerInfo, "fetched host peer info")
  1129. }
  1130. // @Summary List pending hosts in a network
  1131. // @Router /api/v1/pending_hosts [get]
  1132. // @Tags Hosts
  1133. // @Security oauth
  1134. // @Success 200 {array} schema.PendingHost
  1135. // @Failure 500 {object} models.ErrorResponse
  1136. func getPendingHosts(w http.ResponseWriter, r *http.Request) {
  1137. netID := r.URL.Query().Get("network")
  1138. if netID == "" {
  1139. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network id param is missing"), "badrequest"))
  1140. return
  1141. }
  1142. pendingHosts, err := (&schema.PendingHost{
  1143. Network: netID,
  1144. }).List(db.WithContext(r.Context()))
  1145. if err != nil {
  1146. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1147. Code: http.StatusBadRequest,
  1148. Message: err.Error(),
  1149. })
  1150. return
  1151. }
  1152. logger.Log(2, r.Header.Get("user"), "fetched all hosts")
  1153. logic.ReturnSuccessResponseWithJson(w, r, pendingHosts, "returned pending hosts in "+netID)
  1154. }
  1155. // @Summary approve pending hosts in a network
  1156. // @Router /api/v1/pending_hosts/approve/{id} [post]
  1157. // @Tags Hosts
  1158. // @Security oauth
  1159. // @Success 200 {array} models.ApiNode
  1160. // @Failure 500 {object} models.ErrorResponse
  1161. func approvePendingHost(w http.ResponseWriter, r *http.Request) {
  1162. id := mux.Vars(r)["id"]
  1163. p := &schema.PendingHost{ID: id}
  1164. err := p.Get(db.WithContext(r.Context()))
  1165. if err != nil {
  1166. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1167. Code: http.StatusBadRequest,
  1168. Message: err.Error(),
  1169. })
  1170. return
  1171. }
  1172. h, err := logic.GetHost(p.HostID)
  1173. if err != nil {
  1174. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1175. Code: http.StatusBadRequest,
  1176. Message: err.Error(),
  1177. })
  1178. return
  1179. }
  1180. key := models.EnrollmentKey{}
  1181. json.Unmarshal(p.EnrollmentKey, &key)
  1182. newNode, err := logic.UpdateHostNetwork(h, p.Network, true)
  1183. if err != nil {
  1184. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1185. Code: http.StatusBadRequest,
  1186. Message: err.Error(),
  1187. })
  1188. return
  1189. }
  1190. if key.AutoAssignGateway {
  1191. newNode.AutoAssignGateway = true
  1192. }
  1193. if len(key.Groups) > 0 {
  1194. newNode.Tags = make(map[models.TagID]struct{})
  1195. for _, tagI := range key.Groups {
  1196. newNode.Tags[tagI] = struct{}{}
  1197. }
  1198. logic.UpsertNode(newNode)
  1199. }
  1200. if key.Relay != uuid.Nil && !newNode.IsRelayed {
  1201. // check if relay node exists and acting as relay
  1202. relaynode, err := logic.GetNodeByID(key.Relay.String())
  1203. if err == nil && relaynode.IsGw && relaynode.Network == newNode.Network {
  1204. slog.Error(fmt.Sprintf("adding relayed node %s to relay %s on network %s", newNode.ID.String(), key.Relay.String(), p.Network))
  1205. newNode.IsRelayed = true
  1206. newNode.RelayedBy = key.Relay.String()
  1207. updatedRelayNode := relaynode
  1208. updatedRelayNode.RelayedNodes = append(updatedRelayNode.RelayedNodes, newNode.ID.String())
  1209. logic.UpdateRelayed(&relaynode, &updatedRelayNode)
  1210. if err := logic.UpsertNode(&updatedRelayNode); err != nil {
  1211. slog.Error("failed to update node", "nodeid", key.Relay.String())
  1212. }
  1213. if err := logic.UpsertNode(newNode); err != nil {
  1214. slog.Error("failed to update node", "nodeid", key.Relay.String())
  1215. }
  1216. } else {
  1217. slog.Error("failed to relay node. maybe specified relay node is actually not a relay? Or the relayed node is not in the same network with relay?", "err", err)
  1218. }
  1219. }
  1220. logger.Log(1, "added new node", newNode.ID.String(), "to host", h.Name)
  1221. mq.HostUpdate(&models.HostUpdate{
  1222. Action: models.JoinHostToNetwork,
  1223. Host: *h,
  1224. Node: *newNode,
  1225. })
  1226. if h.IsDefault {
  1227. // make host failover
  1228. logic.CreateFailOver(*newNode)
  1229. // make host remote access gateway
  1230. logic.CreateIngressGateway(p.Network, newNode.ID.String(), models.IngressRequest{})
  1231. logic.CreateRelay(models.RelayRequest{
  1232. NodeID: newNode.ID.String(),
  1233. NetID: p.Network,
  1234. })
  1235. }
  1236. p.Delete(db.WithContext(r.Context()))
  1237. go mq.PublishPeerUpdate(false)
  1238. logic.ReturnSuccessResponseWithJson(w, r, newNode.ConvertToAPINode(), "added pending host to "+p.Network)
  1239. }
  1240. // @Summary reject pending hosts in a network
  1241. // @Router /api/v1/pending_hosts/reject/{id} [post]
  1242. // @Tags Hosts
  1243. // @Security oauth
  1244. // @Success 200 {array} models.ApiNode
  1245. // @Failure 500 {object} models.ErrorResponse
  1246. func rejectPendingHost(w http.ResponseWriter, r *http.Request) {
  1247. id := mux.Vars(r)["id"]
  1248. p := &schema.PendingHost{ID: id}
  1249. err := p.Get(db.WithContext(r.Context()))
  1250. if err != nil {
  1251. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1252. Code: http.StatusBadRequest,
  1253. Message: err.Error(),
  1254. })
  1255. return
  1256. }
  1257. err = p.Delete(db.WithContext(r.Context()))
  1258. if err != nil {
  1259. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1260. Code: http.StatusBadRequest,
  1261. Message: err.Error(),
  1262. })
  1263. return
  1264. }
  1265. logic.ReturnSuccessResponseWithJson(w, r, p, "deleted pending host from "+p.Network)
  1266. }