mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-26 00:29:06 +02:00
support for GetPolicies in sqlite
Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
@@ -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"');
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"');
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"');
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user