hosts.go 29 KB

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