123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- package controller
- import (
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "strings"
- "time"
- "github.com/gorilla/mux"
- "github.com/gravitl/netmaker/logger"
- "github.com/gravitl/netmaker/logic"
- "github.com/gravitl/netmaker/models"
- "github.com/gravitl/netmaker/mq"
- )
- func tagHandlers(r *mux.Router) {
- r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(getTags))).
- Methods(http.MethodGet)
- r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(createTag))).
- Methods(http.MethodPost)
- r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(updateTag))).
- Methods(http.MethodPut)
- r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(deleteTag))).
- Methods(http.MethodDelete)
- }
- // @Summary List Tags in a network
- // @Router /api/v1/tags [get]
- // @Tags TAG
- // @Accept json
- // @Success 200 {array} models.SuccessResponse
- // @Failure 500 {object} models.ErrorResponse
- func getTags(w http.ResponseWriter, r *http.Request) {
- netID, _ := url.QueryUnescape(r.URL.Query().Get("network"))
- if netID == "" {
- logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network id param is missing"), "badrequest"))
- return
- }
- // check if network exists
- _, err := logic.GetNetwork(netID)
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- tags, err := logic.ListTagsWithNodes(models.NetworkID(netID))
- if err != nil {
- logger.Log(0, r.Header.Get("user"), "failed to get all network tag entries: ", err.Error())
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
- return
- }
- logic.SortTagEntrys(tags[:])
- logic.ReturnSuccessResponseWithJson(w, r, tags, "fetched all tags in the network "+netID)
- }
- // @Summary Create Tag
- // @Router /api/v1/tags [post]
- // @Tags TAG
- // @Accept json
- // @Success 200 {array} models.SuccessResponse
- // @Failure 500 {object} models.ErrorResponse
- func createTag(w http.ResponseWriter, r *http.Request) {
- var req models.CreateTagReq
- err := json.NewDecoder(r.Body).Decode(&req)
- if err != nil {
- logger.Log(0, "error decoding request body: ",
- err.Error())
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- user, err := logic.GetUser(r.Header.Get("user"))
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- // check if tag network exists
- _, err = logic.GetNetwork(req.Network.String())
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to get network details for "+req.Network.String()), "badrequest"))
- return
- }
- // check if tag exists
- tag := models.Tag{
- ID: models.TagID(fmt.Sprintf("%s.%s", req.Network, req.TagName)),
- TagName: req.TagName,
- Network: req.Network,
- CreatedBy: user.UserName,
- CreatedAt: time.Now(),
- }
- _, err = logic.GetTag(tag.ID)
- if err == nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("tag with id %s exists already", tag.TagName), "badrequest"))
- return
- }
- // validate name
- err = logic.CheckIDSyntax(tag.TagName)
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- err = logic.InsertTag(tag)
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- go func() {
- for _, node := range req.TaggedNodes {
- if node.IsStatic {
- extclient, err := logic.GetExtClient(node.StaticNode.ClientID, node.StaticNode.Network)
- if err == nil && extclient.RemoteAccessClientID == "" {
- if extclient.Tags == nil {
- extclient.Tags = make(map[models.TagID]struct{})
- }
- extclient.Tags[tag.ID] = struct{}{}
- logic.SaveExtClient(&extclient)
- }
- continue
- }
- node, err := logic.GetNodeByID(node.ID)
- if err != nil {
- continue
- }
- if node.Tags == nil {
- node.Tags = make(map[models.TagID]struct{})
- }
- node.Tags[tag.ID] = struct{}{}
- logic.UpsertNode(&node)
- }
- }()
- go mq.PublishPeerUpdate(false)
- var res models.TagListRespNodes = models.TagListRespNodes{
- Tag: tag,
- UsedByCnt: len(req.TaggedNodes),
- TaggedNodes: req.TaggedNodes,
- }
- logic.ReturnSuccessResponseWithJson(w, r, res, "created tag successfully")
- }
- // @Summary Update Tag
- // @Router /api/v1/tags [put]
- // @Tags TAG
- // @Accept json
- // @Success 200 {array} models.SuccessResponse
- // @Failure 500 {object} models.ErrorResponse
- func updateTag(w http.ResponseWriter, r *http.Request) {
- var updateTag models.UpdateTagReq
- err := json.NewDecoder(r.Body).Decode(&updateTag)
- if err != nil {
- logger.Log(0, "error decoding request body: ",
- err.Error())
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- tag, err := logic.GetTag(updateTag.ID)
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- updateTag.NewName = strings.TrimSpace(updateTag.NewName)
- var newID models.TagID
- if updateTag.NewName != "" {
- // validate name
- err = logic.CheckIDSyntax(updateTag.NewName)
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- newID = models.TagID(fmt.Sprintf("%s.%s", tag.Network, updateTag.NewName))
- tag.ID = newID
- tag.TagName = updateTag.NewName
- err = logic.InsertTag(tag)
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- // delete old Tag entry
- logic.DeleteTag(updateTag.ID, false)
- }
- go func() {
- logic.UpdateTag(updateTag, newID)
- if updateTag.NewName != "" {
- logic.UpdateDeviceTag(updateTag.ID, newID, tag.Network)
- }
- mq.PublishPeerUpdate(false)
- }()
- var res models.TagListRespNodes = models.TagListRespNodes{
- Tag: tag,
- UsedByCnt: len(updateTag.TaggedNodes),
- TaggedNodes: updateTag.TaggedNodes,
- }
- logic.ReturnSuccessResponseWithJson(w, r, res, "updated tags")
- }
- // @Summary Delete Tag
- // @Router /api/v1/tags [delete]
- // @Tags TAG
- // @Accept json
- // @Success 200 {array} models.SuccessResponse
- // @Failure 500 {object} models.ErrorResponse
- func deleteTag(w http.ResponseWriter, r *http.Request) {
- tagID, _ := url.QueryUnescape(r.URL.Query().Get("tag_id"))
- if tagID == "" {
- logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
- return
- }
- tag, err := logic.GetTag(models.TagID(tagID))
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
- return
- }
- // check if active policy is using the tag
- if logic.CheckIfTagAsActivePolicy(tag.ID, tag.Network) {
- logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("tag is currently in use by an active policy"), "badrequest"))
- return
- }
- err = logic.DeleteTag(models.TagID(tagID), true)
- if err != nil {
- logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
- return
- }
- go func() {
- logic.RemoveDeviceTagFromAclPolicies(tag.ID, tag.Network)
- logic.RemoveTagFromEnrollmentKeys(tag.ID)
- mq.PublishPeerUpdate(false)
- }()
- logic.ReturnSuccessResponse(w, r, "deleted tag "+tagID)
- }
|