2
0

hosts.go 35 KB

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