hosts.go 29 KB

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