mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-28 09:39:05 +02:00
[management] network map from nmap data type (#6919)
Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io> Co-authored-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
co-authored by
Dmitri Dolguikh
parent
473392a935
commit
e06c17cf59
@@ -0,0 +1,47 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetAccountSettingsQuery = `
|
||||
select settings_peer_login_expiration_enabled as peer_login_expiration_enabled,
|
||||
settings_peer_login_expiration as peer_login_expiration,
|
||||
settings_peer_inactivity_expiration_enabled as peer_inactivity_expiration_enabled,
|
||||
settings_peer_inactivity_expiration as peer_inactivity_expiration,
|
||||
settings_dns_domain as dns_domain,
|
||||
settings_ipv6_enabled_groups as ipv6_enabled_groups,
|
||||
settings_routing_peer_dns_resolution_enabled as routing_peer_dns_resolution_enabled,
|
||||
settings_lazy_connection_enabled as lazy_connection_enabled,
|
||||
settings_auto_update_version as auto_update_version,
|
||||
settings_auto_update_always as auto_update_always,
|
||||
settings_metrics_push_enabled as metrics_push_enabled
|
||||
from accounts
|
||||
where id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetAccountSettings(ctx context.Context, accountId string) (nmdata.AccountSettingsInfo, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetAccountSettingsQuery, accountId)
|
||||
if err != nil {
|
||||
return nmdata.AccountSettingsInfo{}, err
|
||||
}
|
||||
|
||||
a, err := CollectOneRowForSqlite[networkmapdb.Account](rows)
|
||||
if err != nil {
|
||||
return nmdata.AccountSettingsInfo{}, err
|
||||
}
|
||||
|
||||
settingsInfo := nmdata.AccountSettingsInfo{}
|
||||
err = networkmapdb.FromSqlTypesToSharedTypes(reflect.ValueOf(&a), reflect.ValueOf(&settingsInfo))
|
||||
if err != nil {
|
||||
return nmdata.AccountSettingsInfo{}, err
|
||||
}
|
||||
|
||||
return settingsInfo, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap"
|
||||
)
|
||||
|
||||
const (
|
||||
GetAccountZonesQuery = `
|
||||
select zones.id as id, domain, not enable_search_domain as search_domain_disabled, distribution_groups,
|
||||
r.name as record_name, r.type as record_type, 'IN' record_class, r.ttl as record_ttl, r.content as record_rdata
|
||||
from zones
|
||||
left join records as r on r.zone_id = zones.id
|
||||
where zones.account_id=? and zones.enabled
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetAppliedZoneCandidates(ctx context.Context, accountId string) ([]networkmap.AppliedZoneCandidate, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetAccountZonesQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zones, err := CollectRowsForSqlite[networkmapdb.Zone](rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return networkmapdb.ZonesToAppliedZoneCandidates(zones)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetDnsSettingsQuery = `
|
||||
select dns_settings_disabled_management_groups
|
||||
from accounts
|
||||
where id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetDnsSettings(ctx context.Context, accountId string) (nmdata.DNSSettings, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetDnsSettingsQuery, accountId)
|
||||
if err != nil {
|
||||
return nmdata.DNSSettings{}, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var value nmdata.DNSSettings
|
||||
var settings []byte
|
||||
|
||||
rows.Next()
|
||||
if err := rows.Scan(&settings); err != nil {
|
||||
return value, err
|
||||
}
|
||||
|
||||
if settings == nil {
|
||||
return nmdata.DNSSettings{}, nil
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(settings, &value.DisabledManagementGroups); err != nil {
|
||||
return value, err
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
)
|
||||
|
||||
const (
|
||||
GetDomainsQuery = `
|
||||
select domain, target_cluster
|
||||
from domains
|
||||
where account_id=? and domain<>'' and target_cluster<>''
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetDomains(ctx context.Context, accountId string) ([]networkmapdb.Domain, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetDomainsQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return CollectRowsForSqlite[networkmapdb.Domain](rows)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"reflect"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetGroupsQuery = `
|
||||
select groups.id, groups.name, groups.public_id, groups.resources, gp.peer_id
|
||||
from groups
|
||||
left join group_peers gp on gp.group_id=groups.id and gp.account_id=?
|
||||
where groups.account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
// we also return a resource-to-group index.
|
||||
// an alternative is to add json indexes, query this directly. Not sure how expensive
|
||||
// json indexes are. TODO (dmitri) verify and maybe change the implementation here.
|
||||
func (sc *SqliteStoreConn) GetGroups(ctx context.Context, accountId string) ([]nmdata.Group, map[string]map[string]any, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetGroupsQuery, accountId, accountId)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
groups, err := CollectRowsForSqlite[group](rows)
|
||||
|
||||
toret := make([]nmdata.Group, 0, len(groups))
|
||||
resourceToGroupIdx := make(map[string]map[string]any)
|
||||
|
||||
for _, g := range groups {
|
||||
if len(toret) > 0 && toret[len(toret)-1].ID == g.ID && g.PeerID.Valid {
|
||||
toret[len(toret)-1].Peers = append(toret[len(toret)-1].Peers, g.PeerID.String)
|
||||
continue
|
||||
}
|
||||
|
||||
dg := nmdata.Group{}
|
||||
err := networkmapdb.FromSqlTypesToSharedTypes(
|
||||
reflect.ValueOf(&g), reflect.ValueOf(&dg))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if g.PeerID.Valid {
|
||||
dg.Peers = append(dg.Peers, g.PeerID.String)
|
||||
}
|
||||
toret = append(toret, dg)
|
||||
|
||||
for _, resource := range dg.Resources {
|
||||
if _, ok := resourceToGroupIdx[resource.ID]; !ok {
|
||||
resourceToGroupIdx[resource.ID] = make(map[string]any)
|
||||
}
|
||||
resourceToGroupIdx[resource.ID][g.ID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return toret, resourceToGroupIdx, err
|
||||
}
|
||||
|
||||
type group struct {
|
||||
ID string
|
||||
Name sql.NullString
|
||||
PublicID sql.NullString
|
||||
Resources []byte `nmap:"json"`
|
||||
PeerID sql.NullString `nmap:"skip"`
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetNameserversQuery = `
|
||||
select id, public_id, name, description, name_servers, groups, "primary", domains, enabled, search_domains_enabled
|
||||
from name_server_groups
|
||||
where account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetNameServerGroups(ctx context.Context, accountId string) ([]nmdata.NameServerGroup, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetNameserversQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nsgroups, err := CollectRowsForSqlite[networkmapdb.NameserverGroup](rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return networkmapdb.ConvertAllToSharedTypes[networkmapdb.NameserverGroup, nmdata.NameServerGroup](nsgroups)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetNetworkQuery = `
|
||||
select network_identifier as identifier, network_net as net, network_net_v6 as net_v6, network_dns as dns, network_serial as serial
|
||||
from accounts
|
||||
where id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetNetwork(ctx context.Context, accountId string) (nmdata.Network, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetNetworkQuery, accountId)
|
||||
if err != nil {
|
||||
return nmdata.Network{}, err
|
||||
}
|
||||
|
||||
n, err := CollectOneRowForSqlite[networkmapdb.AccountNetwork](rows)
|
||||
if err != nil {
|
||||
return nmdata.Network{}, err
|
||||
}
|
||||
|
||||
toret := nmdata.Network{}
|
||||
err = networkmapdb.FromSqlTypesToSharedTypes(
|
||||
reflect.ValueOf(&n), reflect.ValueOf(&toret))
|
||||
if err != nil {
|
||||
return nmdata.Network{}, err
|
||||
}
|
||||
|
||||
return toret, nil
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetNetworkResourcesQuery = `
|
||||
select id, network_id, account_id, public_id, name, description, type, domain, prefix, enabled
|
||||
from network_resources
|
||||
where account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetNetworkResources(ctx context.Context, accountId string) ([]nmdata.NetworkResource, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetNetworkResourcesQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
netresorces, err := CollectRowsForSqlite[networkmapdb.Networkresource](rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return networkmapdb.ConvertAllToSharedTypes[networkmapdb.Networkresource, nmdata.NetworkResource](netresorces)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetNetworkRouterQuery = `
|
||||
select public_id, peer, network_id, masquerade, metric, enabled, peer_groups, group_peers.peer_id
|
||||
from network_routers, json_each(peer_groups)
|
||||
left join group_peers on group_peers.account_id=? and group_peers.group_id=json_each.value
|
||||
where network_routers.account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetNetworkRouters(ctx context.Context, accountId string) (map[string]map[string]*nmdata.NetworkRouter, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetNetworkRouterQuery, accountId, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
routers, err := CollectRowsForSqlite[networkrouter](rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
toret := make(map[string]map[string]*nmdata.NetworkRouter)
|
||||
for _, router := range routers {
|
||||
if !router.Enabled.Bool {
|
||||
continue
|
||||
}
|
||||
|
||||
networkId := router.NetworkID.String
|
||||
if networkId == "" {
|
||||
return nil, fmt.Errorf("router with public_id %s doesn't have network_id set", router.PublicID.String)
|
||||
}
|
||||
|
||||
nmdatarouter := nmdata.NetworkRouter{}
|
||||
err := networkmapdb.FromSqlTypesToSharedTypes(reflect.ValueOf(&router), reflect.ValueOf(&nmdatarouter))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if toret[networkId] == nil {
|
||||
toret[networkId] = make(map[string]*nmdata.NetworkRouter)
|
||||
}
|
||||
if router.Peer.String != "" {
|
||||
toret[networkId][router.Peer.String] = &nmdatarouter
|
||||
continue
|
||||
}
|
||||
if router.PeerViaGroups.String != "" {
|
||||
toret[networkId][router.PeerViaGroups.String] = &nmdatarouter
|
||||
}
|
||||
}
|
||||
|
||||
return toret, nil
|
||||
}
|
||||
|
||||
type networkrouter struct {
|
||||
PublicID sql.NullString
|
||||
Peer sql.NullString `nmap:"skip"`
|
||||
NetworkID sql.NullString `nmap:"skip"`
|
||||
Masquerade sql.NullBool
|
||||
Metric sql.NullInt64
|
||||
Enabled sql.NullBool
|
||||
PeerGroups []byte `nmap:"json"`
|
||||
PeerViaGroups sql.NullString `nmap:"skip"`
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
)
|
||||
|
||||
const (
|
||||
GetNetworksQuery = `
|
||||
select id, public_id
|
||||
from networks where account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetNetworkXIDToPublicIdMap(ctx context.Context, accountId string) (map[string]string, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetNetworksQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
networks, err := CollectRowsForSqlite[networkmapdb.Network](rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
toret := make(map[string]string)
|
||||
for _, n := range networks {
|
||||
if n.PublicID.Valid {
|
||||
toret[n.ID] = n.PublicID.String
|
||||
}
|
||||
}
|
||||
|
||||
return toret, nil
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetPeersQuery = `
|
||||
select id, key, ssh_key, dns_label, extra_dns_labels, user_id, ssh_enabled, login_expiration_enabled, last_login, ip, ipv6,
|
||||
peer_status_requires_approval, peer_status_connected, proxy_meta_embedded, proxy_meta_cluster,
|
||||
meta_wt_version, meta_go_os, meta_os_version, meta_kernel_version, meta_network_addresses, meta_files, meta_capabilities, meta_flags, meta_sync_message_version,
|
||||
location_country_code, location_city_name, location_connection_ip
|
||||
from peers
|
||||
where account_id = ?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetPeers(ctx context.Context, accountId string) ([]nmdata.Peer, map[string][]*nmdata.Peer, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetPeersQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
peers, err := CollectRowsForSqlite[networkmapdb.Peer](rows)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return networkmapdb.ConvertToNmdataPeers(peers)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetPoliciesQuery = `
|
||||
select p.id, p.public_id, p.enabled, p.source_posture_checks, pr.enabled as rule_enabled, pr.action, pr.protocol, pr.bidirectional,
|
||||
pr.sources, pr.destinations, pr.source_resource, pr.destination_resource, pr.ports, pr.port_ranges,
|
||||
pr.authorized_groups, pr.authorized_user
|
||||
from policies as p
|
||||
left join policy_rules as pr on p.id = pr.policy_id
|
||||
where account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetPolicies(ctx context.Context, accountId string) ([]nmdata.Policy, map[string]map[string]any, map[string]map[string]any, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetPoliciesQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
policies, err := CollectRowsForSqlite[networkmapdb.Policy](rows)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return networkmapdb.ConvertToNmdataPolicy(policies)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetPostureChecksQuery = `
|
||||
select id, public_id, checks
|
||||
from posture_checks
|
||||
where account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetPostureChecks(ctx context.Context, accountId string) ([]nmdata.PostureChecks, map[string]string, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetPostureChecksQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
checks, err := CollectRowsForSqlite[networkmapdb.PostureChecks](rows)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
toret := make([]nmdata.PostureChecks, 0, len(checks))
|
||||
idToPublicIDIdx := make(map[string]string)
|
||||
for _, c := range checks {
|
||||
checks := nmdata.PostureChecks{}
|
||||
err := networkmapdb.FromSqlTypesToSharedTypes(reflect.ValueOf(&c), reflect.ValueOf(&checks))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
toret = append(toret, checks)
|
||||
idToPublicIDIdx[checks.ID] = c.PublicID.String
|
||||
}
|
||||
|
||||
return toret, idToPublicIDIdx, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
const (
|
||||
GetRoutesQuery = `
|
||||
select id, account_id, public_id, network, domains, keep_route, net_id, description,
|
||||
peer, peer as peer_id, peer_groups, network_type, masquerade, metric, enabled,
|
||||
groups, access_control_groups, skip_auto_apply
|
||||
from routes
|
||||
where account_id=?
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetRoutes(ctx context.Context, accountId string) ([]nmdata.Route, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetRoutesQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
routes, err := CollectRowsForSqlite[networkmapdb.Route](rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return networkmapdb.ConvertAllToSharedTypes[networkmapdb.Route, nmdata.Route](routes)
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
)
|
||||
|
||||
const (
|
||||
GetServicesQuery = `
|
||||
select enabled, private, access_groups, proxy_cluster, domain
|
||||
from services
|
||||
where account_id=?
|
||||
`
|
||||
|
||||
GetProxyTargetedDomainResourcesQuery = `
|
||||
select t.target_id
|
||||
from targets as t
|
||||
join services as s on s.id = t.service_id
|
||||
where s.account_id=? and s.enabled and not coalesce(s.terminated, false)
|
||||
and t.enabled and t.target_type='domain' and t.target_id is not null
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetPrivateServices(ctx context.Context, accountId string) ([]networkmapdb.Service, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetServicesQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
services, err := CollectRowsForSqlite[service](rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
toret := make([]networkmapdb.Service, 0, len(services))
|
||||
for _, service := range services {
|
||||
acg := []string{}
|
||||
if service.AccessGroups != nil {
|
||||
if err := json.Unmarshal(service.AccessGroups, &acg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
s := networkmapdb.Service{
|
||||
Enabled: service.Enabled,
|
||||
Private: service.Private,
|
||||
AccessGroups: acg,
|
||||
ProxyCluster: service.ProxyCluster,
|
||||
Domain: service.Domain,
|
||||
}
|
||||
|
||||
toret = append(toret, s)
|
||||
}
|
||||
return toret, nil
|
||||
}
|
||||
|
||||
func (sc *SqliteStoreConn) GetProxyTargetedDomainResourceIDs(ctx context.Context, accountId string) (map[string]struct{}, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetProxyTargetedDomainResourcesQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
toret := make(map[string]struct{})
|
||||
for rows.Next() {
|
||||
var id string
|
||||
err := rows.Scan(&id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
toret[id] = struct{}{}
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return toret, nil
|
||||
}
|
||||
|
||||
type service struct {
|
||||
Enabled sql.NullBool
|
||||
Private sql.NullBool
|
||||
AccessGroups []byte
|
||||
ProxyCluster sql.NullString
|
||||
Domain sql.NullString
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"database/sql"
|
||||
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
)
|
||||
|
||||
var ErrNoRows = errors.New("no rows in result set")
|
||||
|
||||
type SqliteStore struct {
|
||||
Db *sql.DB
|
||||
}
|
||||
|
||||
type sqliteInterface interface {
|
||||
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
|
||||
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
|
||||
}
|
||||
|
||||
type SqliteStoreConn struct {
|
||||
Conn sqliteInterface
|
||||
}
|
||||
|
||||
func NewSqliteStore(storeFile, dataDir string) (*SqliteStore, error) {
|
||||
dbfile := storeFile
|
||||
if envFile, ok := os.LookupEnv("NB_STORE_ENGINE_SQLITE_FILE"); ok && envFile != "" {
|
||||
dbfile = envFile
|
||||
}
|
||||
|
||||
// Separate file path from any SQLite URI query parameters (e.g., "store.db?mode=rwc")
|
||||
filePath, query, hasQuery := strings.Cut(dbfile, "?")
|
||||
|
||||
connStr := filePath
|
||||
if filePath != ":memory:" && !filepath.IsAbs(filePath) {
|
||||
connStr = filepath.Join(dataDir, filePath)
|
||||
}
|
||||
|
||||
// Compose query parameters. User-provided ?_busy_timeout (or its mattn alias
|
||||
// ?_timeout) overrides our default; otherwise inject 30s so SQLite waits at
|
||||
// most that long on a lock instead of blocking the only Go-side connection.
|
||||
// mattn/go-sqlite3 applies PRAGMA from the DSN on every fresh connection, so
|
||||
// the value survives ConnMaxIdleTime/ConnMaxLifetime recycling. cache=shared
|
||||
// stays the default on non-Windows for the same reason as before.
|
||||
parsed, _ := url.ParseQuery(query)
|
||||
var defaults []string
|
||||
if parsed.Get("_busy_timeout") == "" && parsed.Get("_timeout") == "" {
|
||||
defaults = append(defaults, "_busy_timeout=30000")
|
||||
}
|
||||
if !hasQuery && runtime.GOOS != "windows" {
|
||||
// To avoid `The process cannot access the file because it is being used by another process` on Windows
|
||||
defaults = append(defaults, "cache=shared")
|
||||
}
|
||||
parts := defaults
|
||||
if hasQuery {
|
||||
parts = append(parts, query)
|
||||
}
|
||||
if len(parts) > 0 {
|
||||
connStr += "?" + strings.Join(parts, "&")
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", connStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SqliteStore{Db: db}, nil
|
||||
}
|
||||
|
||||
func (s *SqliteStore) BeginTx(ctx context.Context) (networkmapdb.NetworkMapDBStoreConn, error) {
|
||||
tx, err := s.Db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true, Isolation: sql.LevelRepeatableRead})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SqliteStoreConn{Conn: tx}, nil
|
||||
}
|
||||
|
||||
func (s *SqliteStore) Exec(_ context.Context, query string, args ...any) error {
|
||||
_, err := s.Db.Exec(query, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (sc *SqliteStoreConn) RollbackTx(ctx context.Context) error {
|
||||
tx, ok := sc.Conn.(*sql.Tx)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an sql.Tx got %s", reflect.TypeOf(sc.Conn).Kind())
|
||||
}
|
||||
return tx.Rollback()
|
||||
}
|
||||
|
||||
func (sc *SqliteStoreConn) CommitTx(ctx context.Context) error {
|
||||
tx, ok := sc.Conn.(*sql.Tx)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an sql.Tx got %s", reflect.TypeOf(sc.Conn).Kind())
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *SqliteStore) UsingConn() *SqliteStoreConn {
|
||||
return &SqliteStoreConn{Conn: s.Db}
|
||||
}
|
||||
|
||||
func CollectOneRowForSqlite[T any](rows *sql.Rows) (T, error) {
|
||||
defer rows.Close()
|
||||
var r T
|
||||
|
||||
if !rows.Next() {
|
||||
if err := rows.Err(); err != nil {
|
||||
return r, err
|
||||
}
|
||||
return r, ErrNoRows
|
||||
}
|
||||
err := rows.Scan(networkmapdb.StructFields(&r)...)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func CollectRowsForSqlite[T any](rows *sql.Rows) ([]T, error) {
|
||||
defer rows.Close()
|
||||
toret := make([]T, 0)
|
||||
|
||||
for rows.Next() {
|
||||
var r T
|
||||
err := rows.Scan(networkmapdb.StructFields(&r)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
toret = append(toret, r)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return toret, nil
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package networkmap_sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
const (
|
||||
GetAllowedUserIdsQuery = `
|
||||
select id, auto_groups
|
||||
from users
|
||||
where account_id=? and not blocked and not is_service_user
|
||||
`
|
||||
|
||||
GetAllGroupIdQuery = `
|
||||
select id from groups
|
||||
where account_id=? and name='All'
|
||||
`
|
||||
)
|
||||
|
||||
func (sc *SqliteStoreConn) GetAllowedUsers(ctx context.Context, accountId string) (map[string]struct{}, map[string][]string, error) {
|
||||
rows, err := sc.Conn.QueryContext(ctx, GetAllowedUserIdsQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
users, err := CollectRowsForSqlite[user](rows)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rows, err = sc.Conn.QueryContext(ctx, GetAllGroupIdQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
allGroupIds, err := collectAllGroupIds(rows)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
userIdIdx := make(map[string]struct{})
|
||||
groupIdToUserIds := make(map[string][]string)
|
||||
for _, user := range users {
|
||||
autogroups := make([]string, 0)
|
||||
if err := json.Unmarshal(user.AutoGroups, &autogroups); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
userIdIdx[user.ID] = struct{}{}
|
||||
for _, groupId := range autogroups {
|
||||
groupIdToUserIds[groupId] = append(groupIdToUserIds[groupId], user.ID)
|
||||
}
|
||||
for _, allgid := range allGroupIds {
|
||||
groupIdToUserIds[allgid] = append(groupIdToUserIds[allgid], user.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return userIdIdx, groupIdToUserIds, nil
|
||||
}
|
||||
|
||||
func collectAllGroupIds(rows *sql.Rows) ([]string, error) {
|
||||
defer rows.Close()
|
||||
var toret []string
|
||||
|
||||
for rows.Next() {
|
||||
var id string
|
||||
err := rows.Scan(&id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
toret = append(toret, id)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return toret, nil
|
||||
}
|
||||
|
||||
type user struct {
|
||||
ID string
|
||||
AutoGroups []byte
|
||||
}
|
||||
Reference in New Issue
Block a user