diff --git a/integration_tests/management/network_map_db/pgsql/base_data.sql b/integration_tests/management/network_map_db/pgsql/base_data.sql index 0b9231b1b..135ab7f3e 100644 --- a/integration_tests/management/network_map_db/pgsql/base_data.sql +++ b/integration_tests/management/network_map_db/pgsql/base_data.sql @@ -20,33 +20,3 @@ insert into groups (id, account_id, name, resources, public_id) VALUES('group-no insert into group_peers (account_id, peer_id, group_id) VALUES('account-1','peer-id-1','group-one-resource-id'); insert into group_peers (account_id, peer_id, group_id) VALUES('account-1','peer-id-2','group-two-resources-id'); insert into group_peers (account_id, peer_id, group_id) VALUES('account-1','peer-id-3','group-two-resources-id'); -insert into peers (id, account_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) - values('peer-id-1','account-1','key-1','ssh-key-1','peer-1','["extra-peer-1"]','user-id-1',true,true,'2026-08-06 13:25:59.12999+00','"10.10.10.1"','"fdf4:ba80:6aa5:89f1:44d7:8701:8699:4940"', - false,true,true,'cluster-1.netbird.services', - '0.76.0','linux','26.4.1','6.8.0-134-generic','[{"NetIP":"fe80::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ac"},{"NetIP":"192.168.16.1/20","Mac":"00:15:5d:24:0c:ac"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', - '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',1, - 'DE','Berlin','"46.201.148.187"'); -insert into peers (id,account_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) - values('peer-id-2','account-1','key-2','ssh-key-2','peer-2','["extra-peer-2"]','user-id-2',true,true,'2026-08-06 14:25:59.12999+00','"10.10.100.1"','"fdf5:ba80:6aa5:89f1:44d7:8701:8699:4940"', - false,true,true,'cluster-2.netbird.services', - '0.76.1','linux','26.4.2','6.8.0-135-generic','[{"NetIP":"fe81::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ad"},{"NetIP":"192.168.17.1/20","Mac":"00:15:5d:24:0c:ad"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', - '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',0, - 'DE','Berlin','"46.201.149.187"'); -insert into peers (id,account_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) - values('peer-id-3','account-1','key-3','ssh-key-3','peer-3','["extra-peer-3"]','user-id-3',true,true,'2026-08-06 12:25:59.12999+00','"10.10.200.1"','"fdf6:ba80:6aa5:89f1:44d7:8701:8699:4940"', - false,true,true,'cluster-3.netbird.services', - '0.76.2','linux','26.4.3','6.8.0-136-generic','[{"NetIP":"fe82::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ae"},{"NetIP":"192.168.18.1/20","Mac":"00:15:5d:24:0c:ae"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', - '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',1, - 'DE','Berlin','"46.201.150.187"'); diff --git a/integration_tests/management/network_map_db/pgsql/main_test.go b/integration_tests/management/network_map_db/pgsql/main_test.go index 8176f7bd1..4fd4f226c 100644 --- a/integration_tests/management/network_map_db/pgsql/main_test.go +++ b/integration_tests/management/network_map_db/pgsql/main_test.go @@ -21,6 +21,12 @@ import ( //go:embed base_data.sql var baseData string +//go:embed pg_data.sql +var pgData string + +//go:embed sqlite_data.sql +var sqliteData string + var ( pgstore *networkmap_pgsql.PgStore sqlitestore *networkmap_sqlite.SqliteStore @@ -31,12 +37,12 @@ func TestMain(m *testing.M) { var cleanup func() kind, _ := os.LookupEnv("NETBIRD_STORE_ENGINE") switch kind { - case "", string(types.PostgresStoreEngine): - engine = kind - pgstore, cleanup = createPGTestStore(baseData) - case string(types.SqliteStoreEngine): - engine = kind - sqlitestore, cleanup = createSqliteTestStore(baseData) + case string(types.PostgresStoreEngine): + engine = string(types.PostgresStoreEngine) + pgstore, cleanup = createPGTestStore(baseData, pgData) + case "", string(types.SqliteStoreEngine): + engine = string(types.SqliteStoreEngine) + sqlitestore, cleanup = createSqliteTestStore(baseData, sqliteData) default: log.Fatalf("unsupported db '%s' in NETBIRD_STORE_ENGINE env var", kind) } @@ -75,11 +81,19 @@ func execQuery(t *testing.T, ctx context.Context, q string) { // use to parse time in time.RFC3339Nano format // returns the time in the local time zone, as that's what being returned from sql queries +// pgx returns time in the "local" timezone +// sql with sqlite driver returns time in UTC timezone func mustParseTime(t string) *time.Time { tt, err := time.Parse(time.RFC3339Nano, t) if err != nil { panic(err) } + + if engine == string(types.SqliteStoreEngine) { + utc := tt.UTC() + return &utc + } + local := tt.Local() return &local } diff --git a/integration_tests/management/network_map_db/pgsql/network_test.go b/integration_tests/management/network_map_db/pgsql/network_test.go index 3ade68123..fbccee504 100644 --- a/integration_tests/management/network_map_db/pgsql/network_test.go +++ b/integration_tests/management/network_map_db/pgsql/network_test.go @@ -8,15 +8,11 @@ import ( "net" "testing" - "github.com/netbirdio/netbird/management/server/types" "github.com/netbirdio/netbird/shared/management/networkmap/nmdata" "github.com/stretchr/testify/assert" ) func TestGetNetwork(t *testing.T) { - if engine == string(types.SqliteStoreEngine) { - t.Skip() - } ctx := context.TODO() network, err := conn(t, ctx).GetNetwork(ctx, "account-1") diff --git a/integration_tests/management/network_map_db/pgsql/networks_test.go b/integration_tests/management/network_map_db/pgsql/networks_test.go index 1c5649e5f..5af771522 100644 --- a/integration_tests/management/network_map_db/pgsql/networks_test.go +++ b/integration_tests/management/network_map_db/pgsql/networks_test.go @@ -6,14 +6,10 @@ import ( "context" "testing" - "github.com/netbirdio/netbird/management/server/types" "github.com/stretchr/testify/assert" ) func TestGetNetworks(t *testing.T) { - if engine == string(types.SqliteStoreEngine) { - t.Skip() - } ctx := context.TODO() execQuery(t, ctx, diff --git a/integration_tests/management/network_map_db/pgsql/peer_test.go b/integration_tests/management/network_map_db/pgsql/peer_test.go index a660e976c..af1dffdbd 100644 --- a/integration_tests/management/network_map_db/pgsql/peer_test.go +++ b/integration_tests/management/network_map_db/pgsql/peer_test.go @@ -8,15 +8,11 @@ import ( "net/netip" "testing" - "github.com/netbirdio/netbird/management/server/types" "github.com/netbirdio/netbird/shared/management/networkmap/nmdata" "github.com/stretchr/testify/assert" ) func TestGetPeers(t *testing.T) { - if engine == string(types.SqliteStoreEngine) { - t.Skip() - } ctx := context.TODO() peers, clusterToPeersIdx, err := conn(t, ctx).GetPeers(ctx, "account-1") diff --git a/integration_tests/management/network_map_db/pgsql/pg_data.sql b/integration_tests/management/network_map_db/pgsql/pg_data.sql new file mode 100644 index 000000000..d2043308c --- /dev/null +++ b/integration_tests/management/network_map_db/pgsql/pg_data.sql @@ -0,0 +1,30 @@ +insert into peers (id, account_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) + values('peer-id-1','account-1','key-1','ssh-key-1','peer-1','["extra-peer-1"]','user-id-1',true,true,'2026-08-06 13:25:59.12999+00','"10.10.10.1"','"fdf4:ba80:6aa5:89f1:44d7:8701:8699:4940"', + false,true,true,'cluster-1.netbird.services', + '0.76.0','linux','26.4.1','6.8.0-134-generic','[{"NetIP":"fe80::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ac"},{"NetIP":"192.168.16.1/20","Mac":"00:15:5d:24:0c:ac"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', + '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',1, + 'DE','Berlin','"46.201.148.187"'); +insert into peers (id,account_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) + values('peer-id-2','account-1','key-2','ssh-key-2','peer-2','["extra-peer-2"]','user-id-2',true,true,'2026-08-06 14:25:59.12999+00','"10.10.100.1"','"fdf5:ba80:6aa5:89f1:44d7:8701:8699:4940"', + false,true,true,'cluster-2.netbird.services', + '0.76.1','linux','26.4.2','6.8.0-135-generic','[{"NetIP":"fe81::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ad"},{"NetIP":"192.168.17.1/20","Mac":"00:15:5d:24:0c:ad"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', + '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',0, + 'DE','Berlin','"46.201.149.187"'); +insert into peers (id,account_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) + values('peer-id-3','account-1','key-3','ssh-key-3','peer-3','["extra-peer-3"]','user-id-3',true,true,'2026-08-06 12:25:59.12999+00','"10.10.200.1"','"fdf6:ba80:6aa5:89f1:44d7:8701:8699:4940"', + false,true,true,'cluster-3.netbird.services', + '0.76.2','linux','26.4.3','6.8.0-136-generic','[{"NetIP":"fe82::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ae"},{"NetIP":"192.168.18.1/20","Mac":"00:15:5d:24:0c:ae"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', + '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',1, + 'DE','Berlin','"46.201.150.187"'); diff --git a/integration_tests/management/network_map_db/pgsql/pg_test_store.go b/integration_tests/management/network_map_db/pgsql/pg_test_store.go index 1710747b5..d58ea5f6d 100644 --- a/integration_tests/management/network_map_db/pgsql/pg_test_store.go +++ b/integration_tests/management/network_map_db/pgsql/pg_test_store.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "regexp" + "slices" "strings" "time" @@ -19,7 +20,7 @@ import ( "gorm.io/gorm" ) -func createPGTestStore(baseData string) (*networkmap_pgsql.PgStore, func()) { +func createPGTestStore(baseData, pgData string) (*networkmap_pgsql.PgStore, func()) { _, tmpdsn, err := testutil.CreatePostgresTestContainer() if err != nil { log.Fatalf("error starting postres container %v", err) @@ -63,7 +64,7 @@ func createPGTestStore(baseData string) (*networkmap_pgsql.PgStore, func()) { log.Fatal("error creating postgres store %w", err) } - for _, query := range strings.Split(baseData, ";") { + for _, query := range slices.Concat(strings.Split(baseData, ";"), strings.Split(pgData, ";")) { if _, err := pgstore.Pool.Exec(ctx, query); err != nil { log.Fatalf("error initializing db: %s", err.Error()) } diff --git a/integration_tests/management/network_map_db/pgsql/policy_test.go b/integration_tests/management/network_map_db/pgsql/policy_test.go index b1f849b23..1f4c543da 100644 --- a/integration_tests/management/network_map_db/pgsql/policy_test.go +++ b/integration_tests/management/network_map_db/pgsql/policy_test.go @@ -6,15 +6,11 @@ import ( "context" "testing" - "github.com/netbirdio/netbird/management/server/types" "github.com/netbirdio/netbird/shared/management/networkmap/nmdata" "github.com/stretchr/testify/assert" ) func TestGetPolicies(t *testing.T) { - if engine == string(types.SqliteStoreEngine) { - t.Skip() - } ctx := context.TODO() execQuery(t, ctx, @@ -114,7 +110,7 @@ func TestGetPolicies(t *testing.T) { ID: "policy-3", PublicID: "policy-3-public", Enabled: true, - SourcePostureChecks: []string{}, + SourcePostureChecks: nil, Rules: []*nmdata.PolicyRule{ { ID: "policy-3", @@ -127,7 +123,7 @@ func TestGetPolicies(t *testing.T) { ID: "policy-4", PublicID: "policy-4-public", Enabled: true, - SourcePostureChecks: []string{}, + SourcePostureChecks: nil, Rules: []*nmdata.PolicyRule{ { ID: "policy-4", diff --git a/integration_tests/management/network_map_db/pgsql/sqlite_data.sql b/integration_tests/management/network_map_db/pgsql/sqlite_data.sql new file mode 100644 index 000000000..77b928446 --- /dev/null +++ b/integration_tests/management/network_map_db/pgsql/sqlite_data.sql @@ -0,0 +1,30 @@ +insert into peers (id, account_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) + values('peer-id-1','account-1','key-1','ssh-key-1','peer-1','["extra-peer-1"]','user-id-1',true,true,'2026-08-06 13:25:59.12999','"10.10.10.1"','"fdf4:ba80:6aa5:89f1:44d7:8701:8699:4940"', + false,true,true,'cluster-1.netbird.services', + '0.76.0','linux','26.4.1','6.8.0-134-generic','[{"NetIP":"fe80::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ac"},{"NetIP":"192.168.16.1/20","Mac":"00:15:5d:24:0c:ac"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', + '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',1, + 'DE','Berlin','"46.201.148.187"'); +insert into peers (id,account_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) + values('peer-id-2','account-1','key-2','ssh-key-2','peer-2','["extra-peer-2"]','user-id-2',true,true,'2026-08-06 14:25:59.12999','"10.10.100.1"','"fdf5:ba80:6aa5:89f1:44d7:8701:8699:4940"', + false,true,true,'cluster-2.netbird.services', + '0.76.1','linux','26.4.2','6.8.0-135-generic','[{"NetIP":"fe81::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ad"},{"NetIP":"192.168.17.1/20","Mac":"00:15:5d:24:0c:ad"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', + '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',0, + 'DE','Berlin','"46.201.149.187"'); +insert into peers (id,account_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) + values('peer-id-3','account-1','key-3','ssh-key-3','peer-3','["extra-peer-3"]','user-id-3',true,true,'2026-08-06 12:25:59.12999','"10.10.200.1"','"fdf6:ba80:6aa5:89f1:44d7:8701:8699:4940"', + false,true,true,'cluster-3.netbird.services', + '0.76.2','linux','26.4.3','6.8.0-136-generic','[{"NetIP":"fe82::8b4c:973f:a76b:3771/64","Mac":"00:15:5d:24:0c:ae"},{"NetIP":"192.168.18.1/20","Mac":"00:15:5d:24:0c:ae"}]','[{"Path":"/usr/bin/netbird","Exist":false,"ProcessIsRunning":false}]', + '[1,2]','{"RosenpassEnabled":false,"RosenpassPermissive":false,"ServerSSHAllowed":true,"DisableClientRoutes":false,"DisableServerRoutes":false,"DisableDNS":false,"DisableFirewall":false,"BlockLANAccess":false,"BlockInbound":false,"DisableIPv6":false,"LazyConnectionEnabled":false}',1, + 'DE','Berlin','"46.201.150.187"'); diff --git a/integration_tests/management/network_map_db/pgsql/sqlite_test_store.go b/integration_tests/management/network_map_db/pgsql/sqlite_test_store.go index 1c70c93d4..9291e6dbc 100644 --- a/integration_tests/management/network_map_db/pgsql/sqlite_test_store.go +++ b/integration_tests/management/network_map_db/pgsql/sqlite_test_store.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "runtime" + "slices" "strings" networkmap_sqlite "github.com/netbirdio/netbird/management/internals/network_map_db/sqlite" @@ -16,7 +17,7 @@ import ( "gorm.io/gorm" ) -func createSqliteTestStore(baseData string) (*networkmap_sqlite.SqliteStore, func()) { +func createSqliteTestStore(baseData, sqliteData string) (*networkmap_sqlite.SqliteStore, func()) { storeSqliteFileName := ":memory:" storeStr := fmt.Sprintf("%s?cache=shared", storeSqliteFileName) if runtime.GOOS == "windows" { @@ -38,7 +39,7 @@ func createSqliteTestStore(baseData string) (*networkmap_sqlite.SqliteStore, fun log.Fatalf("error initializing db: %s", err.Error()) } - for _, query := range strings.Split(baseData, ";") { + for _, query := range slices.Concat(strings.Split(baseData, ";"), strings.Split(sqliteData, ";")) { if _, err := sqldb.Exec(query); err != nil { log.Fatalf("error initializing db: %s", err.Error()) } diff --git a/management/internals/network_map_db/pgsql/policy.go b/management/internals/network_map_db/pgsql/policy.go index 535d95acf..45927d7a2 100644 --- a/management/internals/network_map_db/pgsql/policy.go +++ b/management/internals/network_map_db/pgsql/policy.go @@ -2,9 +2,6 @@ package networkmap_pgsql import ( "context" - "database/sql" - "encoding/json" - "reflect" "github.com/jackc/pgx/v5" networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db" @@ -13,7 +10,7 @@ import ( const ( GetPoliciesQuery = ` - select p.id, p.public_id, p.enabled, array (select json_array_elements_text(p.source_posture_checks::json)) as source_posture_checks, pr.enabled as rule_enabled, pr.action, pr.protocol, pr.bidirectional, + 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 @@ -28,133 +25,10 @@ func (pgc *PgStoreConn) GetPolicies(ctx context.Context, accountId string) ([]nm return nil, nil, nil, err } - policies, err := pgx.CollectRows(rows, pgx.RowToStructByName[policy]) + policies, err := pgx.CollectRows(rows, pgx.RowToStructByName[networkmapdb.Policy]) if err != nil { return nil, nil, nil, err } - toret := make([]nmdata.Policy, 0, len(policies)) - policyToDestinationResourceIdx := make(map[string]map[string]any) // policy id to destination resource id - policyToDestinationGroupIdx := make(map[string]map[string]any) // policy id to destination group id - for _, p := range policies { - policy := nmdata.Policy{} - err := networkmapdb.FromSqlTypesToSharedTypes( - reflect.ValueOf(&p), reflect.ValueOf(&policy)) - if err != nil { - return nil, nil, nil, err - } - - var policyRule *nmdata.PolicyRule - pr := func() *nmdata.PolicyRule { - if policyRule != nil { - return policyRule - } - - policyRule = &nmdata.PolicyRule{} - return policyRule - } - - if p.RuleEnabled.Valid { - pr().Enabled = p.RuleEnabled.Bool - } - if p.Action.Valid { - pr().Action = p.Action.String - } - if p.Protocol.Valid { - pr().Protocol = p.Protocol.String - } - if p.Bidirectional.Valid { - pr().Bidirectional = p.Bidirectional.Bool - } - if len(p.Sources) > 0 { - err := json.Unmarshal([]byte(p.Sources), &pr().Sources) - if err != nil { - return toret, nil, nil, err - } - } - if len(p.Destinations) > 0 { - err := json.Unmarshal([]byte(p.Destinations), &pr().Destinations) - if err != nil { - return toret, nil, nil, err - } - - if p.RuleEnabled.Valid && p.RuleEnabled.Bool { - for _, dst := range pr().Destinations { - if _, ok := policyToDestinationGroupIdx[p.ID]; !ok { - policyToDestinationGroupIdx[p.ID] = make(map[string]any) - } - policyToDestinationGroupIdx[p.ID][dst] = struct{}{} - } - } - } - if len(p.SourceResource) > 0 { - err := json.Unmarshal([]byte(p.SourceResource), &pr().SourceResource) - if err != nil { - return toret, nil, nil, err - } - } - if len(p.DestinationResource) > 0 { - err := json.Unmarshal([]byte(p.DestinationResource), &pr().DestinationResource) - if err != nil { - return toret, nil, nil, err - } - - if p.RuleEnabled.Valid && p.RuleEnabled.Bool { - if _, ok := policyToDestinationResourceIdx[p.ID]; !ok { - policyToDestinationResourceIdx[p.ID] = make(map[string]any) - } - policyToDestinationResourceIdx[p.ID][pr().DestinationResource.ID] = struct{}{} - } - } - if len(p.Ports) > 0 { - err := json.Unmarshal([]byte(p.Ports), &pr().Ports) - if err != nil { - return toret, nil, nil, err - } - } - if len(p.PortRanges) > 0 { - err := json.Unmarshal([]byte(p.PortRanges), &pr().PortRanges) - if err != nil { - return toret, nil, nil, err - } - } - if len(p.AuthorizedGroups) > 0 { - err := json.Unmarshal([]byte(p.AuthorizedGroups), &pr().AuthorizedGroups) - if err != nil { - return toret, nil, nil, err - } - } - if p.AuthorizedUser.Valid { - pr().AuthorizedUser = p.AuthorizedUser.String - } - - if policyRule != nil { - policyRule.ID = p.ID - policyRule.PolicyID = p.ID - policy.Rules = []*nmdata.PolicyRule{policyRule} - } - - toret = append(toret, policy) - } - - return toret, policyToDestinationResourceIdx, policyToDestinationGroupIdx, err -} - -type policy struct { - ID string - PublicID sql.NullString - SourcePostureChecks []string - Enabled sql.NullBool - RuleEnabled sql.NullBool `nmap:"skip"` - Bidirectional sql.NullBool `nmap:"skip"` - Action sql.NullString `nmap:"skip"` - Protocol sql.NullString `nmap:"skip"` - Sources json.RawMessage `nmap:"skip"` - Destinations json.RawMessage `nmap:"skip"` - SourceResource json.RawMessage `nmap:"skip"` - DestinationResource json.RawMessage `nmap:"skip"` - Ports json.RawMessage `nmap:"skip"` - PortRanges json.RawMessage `nmap:"skip"` - AuthorizedGroups json.RawMessage `nmap:"skip"` - AuthorizedUser sql.NullString `nmap:"skip"` + return networkmapdb.ConvertToNmdataPolicy(policies) } diff --git a/management/internals/network_map_db/shared_types.go b/management/internals/network_map_db/shared_types.go index ccedaafc4..836a95182 100644 --- a/management/internals/network_map_db/shared_types.go +++ b/management/internals/network_map_db/shared_types.go @@ -92,6 +92,28 @@ type Network struct { PublicID sql.NullString } +type Policy struct { + ID string + PublicID sql.NullString + Enabled sql.NullBool + SourcePostureChecks []byte `nmap:"json"` + RuleEnabled sql.NullBool `nmap:"skip"` + Action sql.NullString `nmap:"skip"` + Protocol sql.NullString `nmap:"skip"` + Bidirectional sql.NullBool `nmap:"skip"` + Sources []byte `nmap:"skip,json"` + Destinations []byte `nmap:"skip,json"` + SourceResource []byte `nmap:"skip,json"` + DestinationResource []byte `nmap:"skip,json"` + Ports []byte `nmap:"skip,json"` + PortRanges []byte `nmap:"skip,json"` + AuthorizedGroups []byte `nmap:"skip,json"` + AuthorizedUser sql.NullString `nmap:"skip"` +} + +// Depending on db interface LastLogin contains time in different formats: +// for sqlite/sql.NullTime the time in UTC +// for pgx the time is in the local timezone // TODO add support for creating struct fields from denormalized fields type Peer struct { ID string @@ -264,3 +286,111 @@ func ConvertToNmdataPeers(peers []Peer) ([]nmdata.Peer, map[string][]*nmdata.Pee return toret, clusterToPeerIdx, nil } + +func ConvertToNmdataPolicy(policies []Policy) ([]nmdata.Policy, map[string]map[string]any, map[string]map[string]any, error) { + toret := make([]nmdata.Policy, 0, len(policies)) + policyToDestinationResourceIdx := make(map[string]map[string]any) // policy id to destination resource id + policyToDestinationGroupIdx := make(map[string]map[string]any) // policy id to destination group id + for _, p := range policies { + policy := nmdata.Policy{} + err := FromSqlTypesToSharedTypes( + reflect.ValueOf(&p), reflect.ValueOf(&policy)) + if err != nil { + return nil, nil, nil, err + } + + var policyRule *nmdata.PolicyRule + pr := func() *nmdata.PolicyRule { + if policyRule != nil { + return policyRule + } + + policyRule = &nmdata.PolicyRule{} + return policyRule + } + + if p.RuleEnabled.Valid { + pr().Enabled = p.RuleEnabled.Bool + } + if p.Action.Valid { + pr().Action = p.Action.String + } + if p.Protocol.Valid { + pr().Protocol = p.Protocol.String + } + if p.Bidirectional.Valid { + pr().Bidirectional = p.Bidirectional.Bool + } + if len(p.Sources) > 0 { + err := json.Unmarshal([]byte(p.Sources), &pr().Sources) + if err != nil { + return toret, nil, nil, err + } + } + if len(p.Destinations) > 0 { + err := json.Unmarshal([]byte(p.Destinations), &pr().Destinations) + if err != nil { + return toret, nil, nil, err + } + + if p.RuleEnabled.Valid && p.RuleEnabled.Bool { + for _, dst := range pr().Destinations { + if _, ok := policyToDestinationGroupIdx[p.ID]; !ok { + policyToDestinationGroupIdx[p.ID] = make(map[string]any) + } + policyToDestinationGroupIdx[p.ID][dst] = struct{}{} + } + } + } + if len(p.SourceResource) > 0 { + err := json.Unmarshal([]byte(p.SourceResource), &pr().SourceResource) + if err != nil { + return toret, nil, nil, err + } + } + if len(p.DestinationResource) > 0 { + err := json.Unmarshal([]byte(p.DestinationResource), &pr().DestinationResource) + if err != nil { + return toret, nil, nil, err + } + + if p.RuleEnabled.Valid && p.RuleEnabled.Bool { + if _, ok := policyToDestinationResourceIdx[p.ID]; !ok { + policyToDestinationResourceIdx[p.ID] = make(map[string]any) + } + policyToDestinationResourceIdx[p.ID][pr().DestinationResource.ID] = struct{}{} + } + } + if len(p.Ports) > 0 { + err := json.Unmarshal([]byte(p.Ports), &pr().Ports) + if err != nil { + return toret, nil, nil, err + } + } + if len(p.PortRanges) > 0 { + err := json.Unmarshal([]byte(p.PortRanges), &pr().PortRanges) + if err != nil { + return toret, nil, nil, err + } + } + if len(p.AuthorizedGroups) > 0 { + err := json.Unmarshal([]byte(p.AuthorizedGroups), &pr().AuthorizedGroups) + if err != nil { + return toret, nil, nil, err + } + } + if p.AuthorizedUser.Valid { + pr().AuthorizedUser = p.AuthorizedUser.String + } + + if policyRule != nil { + policyRule.ID = p.ID + policyRule.PolicyID = p.ID + policy.Rules = []*nmdata.PolicyRule{policyRule} + } + + toret = append(toret, policy) + } + + return toret, policyToDestinationResourceIdx, policyToDestinationGroupIdx, nil +} diff --git a/management/internals/network_map_db/sqlite/policy.go b/management/internals/network_map_db/sqlite/policy.go new file mode 100644 index 000000000..1a11f6e20 --- /dev/null +++ b/management/internals/network_map_db/sqlite/policy.go @@ -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) +} diff --git a/management/internals/network_map_db/sqlite/sqlite_store.go b/management/internals/network_map_db/sqlite/sqlite_store.go index 4c9112c62..9d5d25c5b 100644 --- a/management/internals/network_map_db/sqlite/sqlite_store.go +++ b/management/internals/network_map_db/sqlite/sqlite_store.go @@ -120,9 +120,6 @@ func CollectRowsForSqlite[T any](rows *sql.Rows) ([]T, error) { return toret, nil } -func (s *SqliteStoreConn) GetPolicies(ctx context.Context, accountId string) ([]nmdata.Policy, map[string]map[string]any, map[string]map[string]any, error) { - return nil, nil, nil, nil -} func (s *SqliteStoreConn) GetRoutes(ctx context.Context, accountId string) ([]nmdata.Route, error) { return nil, nil }