move tags to node model

This commit is contained in:
abhishek9686
2024-09-22 13:37:58 +04:00
parent c64dc852ae
commit 04b8737a02
9 changed files with 183 additions and 134 deletions

View File

@@ -16,7 +16,7 @@ import (
)
func tagHandlers(r *mux.Router) {
r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(getAllTags))).
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)
@@ -27,21 +27,32 @@ func tagHandlers(r *mux.Router) {
}
// @Summary Get all Tag entries
// @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 getAllTags(w http.ResponseWriter, r *http.Request) {
tags, err := logic.ListTagsWithHosts()
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 {
logger.Log(0, r.Header.Get("user"), "failed to get all DNS entries: ", err.Error())
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")
logic.ReturnSuccessResponseWithJson(w, r, tags, "fetched all tags in the network "+netID)
}
// @Summary Create Tag
@@ -84,16 +95,16 @@ func createTag(w http.ResponseWriter, r *http.Request) {
return
}
go func() {
for _, hostID := range req.TaggedHosts {
h, err := logic.GetHost(hostID)
for _, nodeID := range req.TaggedNodes {
node, err := logic.GetNodeByID(nodeID)
if err != nil {
continue
}
if h.Tags == nil {
h.Tags = make(map[models.TagID]struct{})
if node.Tags == nil {
node.Tags = make(map[models.TagID]struct{})
}
h.Tags[tag.ID] = struct{}{}
logic.UpsertHost(h)
node.Tags[tag.ID] = struct{}{}
logic.UpsertNode(&node)
}
}()

View File

@@ -572,35 +572,3 @@ func SortApiHosts(unsortedHosts []models.ApiHost) {
return unsortedHosts[i].ID < unsortedHosts[j].ID
})
}
func GetTagMapWithHosts() (tagHostMap map[models.TagID][]models.Host) {
tagHostMap = make(map[models.TagID][]models.Host)
hosts, _ := GetAllHosts()
for _, hostI := range hosts {
if hostI.Tags == nil {
continue
}
for hostTagID := range hostI.Tags {
if _, ok := tagHostMap[hostTagID]; ok {
tagHostMap[hostTagID] = append(tagHostMap[hostTagID], hostI)
} else {
tagHostMap[hostTagID] = []models.Host{hostI}
}
}
}
return
}
func GetHostsWithTag(tagID models.TagID) map[string]models.Host {
hMap := make(map[string]models.Host)
hosts, _ := GetAllHosts()
for _, hostI := range hosts {
if hostI.Tags == nil {
continue
}
if _, ok := hostI.Tags[tagID]; ok {
hMap[hostI.ID.String()] = hostI
}
}
return hMap
}

View File

@@ -698,3 +698,40 @@ func GetAllFailOvers() ([]models.Node, error) {
}
return igs, nil
}
func GetTagMapWithNodes(netID models.NetworkID) (tagNodesMap map[models.TagID][]models.Node) {
tagNodesMap = make(map[models.TagID][]models.Node)
nodes, _ := GetNetworkNodes(netID.String())
for _, nodeI := range nodes {
if nodeI.Tags == nil {
continue
}
for nodeTagID := range nodeI.Tags {
if _, ok := tagNodesMap[nodeTagID]; ok {
tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI)
} else {
tagNodesMap[nodeTagID] = []models.Node{nodeI}
}
}
}
return
}
func GetNodesWithTag(tagID models.TagID) map[string]models.Node {
nMap := make(map[string]models.Node)
tag, err := GetTag(tagID)
if err != nil {
return nMap
}
nodes, _ := GetNetworkNodes(tag.Network.String())
for _, nodeI := range nodes {
if nodeI.Tags == nil {
continue
}
if _, ok := nodeI.Tags[tagID]; ok {
nMap[nodeI.ID.String()] = nodeI
}
}
return nMap
}

View File

@@ -42,35 +42,39 @@ func InsertTag(tag models.Tag) error {
// DeleteTag - delete tag, will also untag hosts
func DeleteTag(tagID models.TagID) error {
// cleanUp tags on hosts
hosts, err := GetAllHosts()
tag, err := GetTag(tagID)
if err != nil {
return err
}
for _, hostI := range hosts {
hostI := hostI
if _, ok := hostI.Tags[tagID]; ok {
delete(hostI.Tags, tagID)
UpsertHost(&hostI)
nodes, err := GetNetworkNodes(tag.Network.String())
if err != nil {
return err
}
for _, nodeI := range nodes {
nodeI := nodeI
if _, ok := nodeI.Tags[tagID]; ok {
delete(nodeI.Tags, tagID)
UpsertNode(&nodeI)
}
}
return database.DeleteRecord(database.TAG_TABLE_NAME, tagID.String())
}
// ListTagsWithHosts - lists all tags with tagged hosts
func ListTagsWithHosts() ([]models.TagListResp, error) {
func ListTagsWithNodes(netID models.NetworkID) ([]models.TagListResp, error) {
tagMutex.RLock()
defer tagMutex.RUnlock()
tags, err := ListTags()
tags, err := ListNetworkTags(netID)
if err != nil {
return []models.TagListResp{}, err
}
tagsHostMap := GetTagMapWithHosts()
tagsNodeMap := GetTagMapWithNodes(netID)
resp := []models.TagListResp{}
for _, tagI := range tags {
tagRespI := models.TagListResp{
Tag: tagI,
UsedByCnt: len(tagsHostMap[tagI.ID]),
TaggedHosts: tagsHostMap[tagI.ID],
UsedByCnt: len(tagsNodeMap[tagI.ID]),
TaggedNodes: tagsNodeMap[tagI.ID],
}
resp = append(resp, tagRespI)
}
@@ -96,39 +100,62 @@ func ListTags() ([]models.Tag, error) {
return tags, nil
}
// ListTags - lists all tags from DB
func ListNetworkTags(netID models.NetworkID) ([]models.Tag, error) {
data, err := database.FetchRecords(database.TAG_TABLE_NAME)
if err != nil && !database.IsEmptyRecord(err) {
return []models.Tag{}, err
}
tags := []models.Tag{}
for _, dataI := range data {
tag := models.Tag{}
err := json.Unmarshal([]byte(dataI), &tag)
if err != nil {
continue
}
if tag.Network == netID {
tags = append(tags, tag)
}
}
return tags, nil
}
// UpdateTag - updates and syncs hosts with tag update
func UpdateTag(req models.UpdateTagReq, newID models.TagID) {
tagMutex.Lock()
defer tagMutex.Unlock()
tagHostsMap := GetHostsWithTag(req.ID)
for _, hostID := range req.TaggedHosts {
hostI, err := GetHost(hostID)
tagNodesMap := GetNodesWithTag(req.ID)
for _, nodeID := range req.TaggedNodes {
node, err := GetNodeByID(nodeID)
if err != nil {
continue
}
if _, ok := tagHostsMap[hostI.ID.String()]; !ok {
if hostI.Tags == nil {
hostI.Tags = make(map[models.TagID]struct{})
if _, ok := tagNodesMap[node.ID.String()]; !ok {
if node.Tags == nil {
node.Tags = make(map[models.TagID]struct{})
}
hostI.Tags[req.ID] = struct{}{}
UpsertHost(hostI)
node.Tags[req.ID] = struct{}{}
UpsertNode(&node)
} else {
delete(tagHostsMap, hostI.ID.String())
delete(tagNodesMap, node.ID.String())
}
}
for _, deletedTaggedHost := range tagHostsMap {
deletedTaggedHost := deletedTaggedHost
for _, deletedTaggedNode := range tagNodesMap {
deletedTaggedHost := deletedTaggedNode
delete(deletedTaggedHost.Tags, req.ID)
UpsertHost(&deletedTaggedHost)
UpsertNode(&deletedTaggedHost)
}
go func(req models.UpdateTagReq) {
if newID != "" {
tagHostsMap = GetHostsWithTag(req.ID)
for _, hostI := range tagHostsMap {
hostI := hostI
delete(hostI.Tags, req.ID)
hostI.Tags[newID] = struct{}{}
UpsertHost(&hostI)
tagNodesMap = GetNodesWithTag(req.ID)
for _, nodeI := range tagNodesMap {
nodeI := nodeI
delete(nodeI.Tags, req.ID)
nodeI.Tags[newID] = struct{}{}
UpsertNode(&nodeI)
}
}
}(req)

View File

@@ -8,30 +8,29 @@ import (
// ApiHost - the host struct for API usage
type ApiHost struct {
ID string `json:"id"`
Verbosity int `json:"verbosity"`
FirewallInUse string `json:"firewallinuse"`
Version string `json:"version"`
Name string `json:"name"`
OS string `json:"os"`
Debug bool `json:"debug"`
IsStaticPort bool `json:"isstaticport"`
IsStatic bool `json:"isstatic"`
ListenPort int `json:"listenport"`
WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"`
MTU int `json:"mtu" yaml:"mtu"`
Interfaces []ApiIface `json:"interfaces" yaml:"interfaces"`
DefaultInterface string `json:"defaultinterface" yaml:"defautlinterface"`
EndpointIP string `json:"endpointip" yaml:"endpointip"`
EndpointIPv6 string `json:"endpointipv6" yaml:"endpointipv6"`
PublicKey string `json:"publickey"`
MacAddress string `json:"macaddress"`
Nodes []string `json:"nodes"`
IsDefault bool `json:"isdefault" yaml:"isdefault"`
NatType string `json:"nat_type" yaml:"nat_type"`
PersistentKeepalive int `json:"persistentkeepalive" yaml:"persistentkeepalive"`
AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"`
Tags map[TagID]struct{} `json:"tags"`
ID string `json:"id"`
Verbosity int `json:"verbosity"`
FirewallInUse string `json:"firewallinuse"`
Version string `json:"version"`
Name string `json:"name"`
OS string `json:"os"`
Debug bool `json:"debug"`
IsStaticPort bool `json:"isstaticport"`
IsStatic bool `json:"isstatic"`
ListenPort int `json:"listenport"`
WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"`
MTU int `json:"mtu" yaml:"mtu"`
Interfaces []ApiIface `json:"interfaces" yaml:"interfaces"`
DefaultInterface string `json:"defaultinterface" yaml:"defautlinterface"`
EndpointIP string `json:"endpointip" yaml:"endpointip"`
EndpointIPv6 string `json:"endpointipv6" yaml:"endpointipv6"`
PublicKey string `json:"publickey"`
MacAddress string `json:"macaddress"`
Nodes []string `json:"nodes"`
IsDefault bool `json:"isdefault" yaml:"isdefault"`
NatType string `json:"nat_type" yaml:"nat_type"`
PersistentKeepalive int `json:"persistentkeepalive" yaml:"persistentkeepalive"`
AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"`
}
// ApiIface - the interface struct for API usage
@@ -79,7 +78,6 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost {
a.NatType = h.NatType
a.PersistentKeepalive = int(h.PersistentKeepalive.Seconds())
a.AutoUpdate = h.AutoUpdate
a.Tags = h.Tags
return &a
}
@@ -125,6 +123,5 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host {
h.TurnEndpoint = currentHost.TurnEndpoint
h.PersistentKeepalive = time.Duration(a.PersistentKeepalive) * time.Second
h.AutoUpdate = a.AutoUpdate
h.Tags = a.Tags
return &h
}

View File

@@ -48,6 +48,7 @@ type ApiNode struct {
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
AdditionalRagIps []string `json:"additional_rag_ips" yaml:"additional_rag_ips"`
Tags map[TagID]struct{} `json:"tags" yaml:"tags"`
}
// ApiNode.ConvertToServerNode - converts an api node to a server node
@@ -123,6 +124,7 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
}
convertedNode.AdditionalRagIps = append(convertedNode.AdditionalRagIps, ragIp)
}
convertedNode.Tags = a.Tags
return &convertedNode
}
@@ -180,6 +182,7 @@ func (nm *Node) ConvertToAPINode() *ApiNode {
apiNode.FailedOverBy = nm.FailedOverBy
apiNode.Metadata = nm.Metadata
apiNode.AdditionalRagIps = []string{}
apiNode.Tags = nm.Tags
for _, ip := range nm.AdditionalRagIps {
apiNode.AdditionalRagIps = append(apiNode.AdditionalRagIps, ip.String())
}

View File

@@ -41,38 +41,37 @@ const (
// Host - represents a host on the network
type Host struct {
ID uuid.UUID `json:"id" yaml:"id"`
Verbosity int `json:"verbosity" yaml:"verbosity"`
FirewallInUse string `json:"firewallinuse" yaml:"firewallinuse"`
Version string `json:"version" yaml:"version"`
IPForwarding bool `json:"ipforwarding" yaml:"ipforwarding"`
DaemonInstalled bool `json:"daemoninstalled" yaml:"daemoninstalled"`
AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"`
HostPass string `json:"hostpass" yaml:"hostpass"`
Name string `json:"name" yaml:"name"`
OS string `json:"os" yaml:"os"`
Interface string `json:"interface" yaml:"interface"`
Debug bool `json:"debug" yaml:"debug"`
ListenPort int `json:"listenport" yaml:"listenport"`
WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"`
MTU int `json:"mtu" yaml:"mtu"`
PublicKey wgtypes.Key `json:"publickey" yaml:"publickey"`
MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"`
TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"traffickeypublic"`
Nodes []string `json:"nodes" yaml:"nodes"`
Interfaces []Iface `json:"interfaces" yaml:"interfaces"`
DefaultInterface string `json:"defaultinterface" yaml:"defaultinterface"`
EndpointIP net.IP `json:"endpointip" yaml:"endpointip"`
EndpointIPv6 net.IP `json:"endpointipv6" yaml:"endpointipv6"`
IsDocker bool `json:"isdocker" yaml:"isdocker"`
IsK8S bool `json:"isk8s" yaml:"isk8s"`
IsStaticPort bool `json:"isstaticport" yaml:"isstaticport"`
IsStatic bool `json:"isstatic" yaml:"isstatic"`
IsDefault bool `json:"isdefault" yaml:"isdefault"`
NatType string `json:"nat_type,omitempty" yaml:"nat_type,omitempty"`
TurnEndpoint *netip.AddrPort `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"`
PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"`
Tags map[TagID]struct{} `json:"tags" yaml:"tags"`
ID uuid.UUID `json:"id" yaml:"id"`
Verbosity int `json:"verbosity" yaml:"verbosity"`
FirewallInUse string `json:"firewallinuse" yaml:"firewallinuse"`
Version string `json:"version" yaml:"version"`
IPForwarding bool `json:"ipforwarding" yaml:"ipforwarding"`
DaemonInstalled bool `json:"daemoninstalled" yaml:"daemoninstalled"`
AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"`
HostPass string `json:"hostpass" yaml:"hostpass"`
Name string `json:"name" yaml:"name"`
OS string `json:"os" yaml:"os"`
Interface string `json:"interface" yaml:"interface"`
Debug bool `json:"debug" yaml:"debug"`
ListenPort int `json:"listenport" yaml:"listenport"`
WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"`
MTU int `json:"mtu" yaml:"mtu"`
PublicKey wgtypes.Key `json:"publickey" yaml:"publickey"`
MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"`
TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"traffickeypublic"`
Nodes []string `json:"nodes" yaml:"nodes"`
Interfaces []Iface `json:"interfaces" yaml:"interfaces"`
DefaultInterface string `json:"defaultinterface" yaml:"defaultinterface"`
EndpointIP net.IP `json:"endpointip" yaml:"endpointip"`
EndpointIPv6 net.IP `json:"endpointipv6" yaml:"endpointipv6"`
IsDocker bool `json:"isdocker" yaml:"isdocker"`
IsK8S bool `json:"isk8s" yaml:"isk8s"`
IsStaticPort bool `json:"isstaticport" yaml:"isstaticport"`
IsStatic bool `json:"isstatic" yaml:"isstatic"`
IsDefault bool `json:"isdefault" yaml:"isdefault"`
NatType string `json:"nat_type,omitempty" yaml:"nat_type,omitempty"`
TurnEndpoint *netip.AddrPort `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"`
PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"`
}
// FormatBool converts a boolean to a [yes|no] string

View File

@@ -99,6 +99,7 @@ type Node struct {
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
AdditionalRagIps []net.IP `json:"additional_rag_ips" yaml:"additional_rag_ips" swaggertype:"array,number"`
Tags map[TagID]struct{} `json:"tags" yaml:"tags"`
}
// LegacyNode - legacy struct for node model

View File

@@ -26,17 +26,23 @@ type Tag struct {
type CreateTagReq struct {
TagName string `json:"tag_name"`
Network NetworkID `json:"network"`
TaggedHosts []string `json:"tagged_hosts"`
TaggedNodes []string `json:"tagged_nodes"`
}
type TagListResp struct {
Tag
UsedByCnt int `json:"used_by_count"`
TaggedHosts []Host `json:"tagged_hosts"`
TaggedNodes []Node `json:"tagged_nodes"`
}
type TagListRespNodes struct {
Tag
UsedByCnt int `json:"used_by_count"`
TaggedNodes []Node `json:"tagged_nodes"`
}
type UpdateTagReq struct {
Tag
NewName string `json:"new_name"`
TaggedHosts []string `json:"tagged_hosts"`
TaggedNodes []string `json:"tagged_nodes"`
}