Add network resources store implementation

Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>
This commit is contained in:
bcmmbaga
2024-12-10 16:42:11 +01:00
parent 6dd6992415
commit 382dba4a85
6 changed files with 187 additions and 12 deletions

View File

@ -278,8 +278,9 @@ type Account struct {
// Settings is a dictionary of Account settings // Settings is a dictionary of Account settings
Settings *Settings `gorm:"embedded;embeddedPrefix:settings_"` Settings *Settings `gorm:"embedded;embeddedPrefix:settings_"`
Networks []*networks.Network `gorm:"foreignKey:AccountID;references:id"` Networks []*networks.Network `gorm:"foreignKey:AccountID;references:id"`
NetworkRouters []*networks.NetworkRouter `gorm:"foreignKey:AccountID;references:id"` NetworkRouters []*networks.NetworkRouter `gorm:"foreignKey:AccountID;references:id"`
NetworkResources []*networks.NetworkResource `gorm:"foreignKey:AccountID;references:id"`
} }
// Subclass used in gorm to only load settings and not whole account // Subclass used in gorm to only load settings and not whole account

View File

@ -1704,22 +1704,54 @@ func (s *SqlStore) DeleteNetworkRouter(ctx context.Context, lockStrength Locking
return nil return nil
} }
func (s *SqlStore) GetAccountNetworkResourceByNetID(ctx context.Context, lockStrength LockingStrength, accountID, networkID string) (*networks.NetworkResource, error) { func (s *SqlStore) GetNetworkResourcesByNetID(ctx context.Context, lockStrength LockingStrength, accountID, networkID string) ([]*networks.NetworkResource, error) {
//TODO implement me var netResources []*networks.NetworkResource
panic("implement me") result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).
Find(&netResources, "account_id = ? AND network_id = ?", accountID, networkID)
if result.Error != nil {
log.WithContext(ctx).Errorf("failed to get network resources from store: %v", result.Error)
return nil, status.Errorf(status.Internal, "failed to get network resources from store")
}
return netResources, nil
} }
func (s *SqlStore) GetNetworkResourceByID(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) (*networks.NetworkResource, error) { func (s *SqlStore) GetNetworkResourceByID(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) (*networks.NetworkResource, error) {
//TODO implement me var netResources *networks.NetworkResource
panic("implement me") result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).
First(&netResources, accountAndIDQueryCondition, accountID, resourceID)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, status.NewNetworkResourceNotFoundError(resourceID)
}
log.WithContext(ctx).Errorf("failed to get network resource from store: %v", result.Error)
return nil, status.Errorf(status.Internal, "failed to get network resource from store")
}
return netResources, nil
} }
func (s *SqlStore) SaveNetworkResource(ctx context.Context, lockStrength LockingStrength, resource *networks.NetworkResource) error { func (s *SqlStore) SaveNetworkResource(ctx context.Context, lockStrength LockingStrength, resource *networks.NetworkResource) error {
//TODO implement me result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Save(resource)
panic("implement me") if result.Error != nil {
log.WithContext(ctx).Errorf("failed to save network resource to store: %v", result.Error)
return status.Errorf(status.Internal, "failed to save network resource to store")
}
return nil
} }
func (s *SqlStore) DeleteNetworkResource(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) error { func (s *SqlStore) DeleteNetworkResource(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) error {
//TODO implement me result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).
panic("implement me") Delete(&networks.NetworkResource{}, accountAndIDQueryCondition, accountID, resourceID)
if result.Error != nil {
log.WithContext(ctx).Errorf("failed to delete network resource from store: %v", result.Error)
return status.Errorf(status.Internal, "failed to delete network resource from store")
}
if result.RowsAffected == 0 {
return status.NewNetworkResourceNotFoundError(resourceID)
}
return nil
} }

View File

@ -325,6 +325,17 @@ func TestSqlite_DeleteAccount(t *testing.T) {
Metric: 1, Metric: 1,
}, },
} }
account.NetworkResources = []*networks.NetworkResource{
{
ID: "resource_id",
NetworkID: account.Networks[0].ID,
AccountID: account.Id,
Name: "Name",
Description: "Description",
Type: "Domain",
Address: "example.com",
},
}
err = store.SaveAccount(context.Background(), account) err = store.SaveAccount(context.Background(), account)
require.NoError(t, err) require.NoError(t, err)
@ -375,6 +386,10 @@ func TestSqlite_DeleteAccount(t *testing.T) {
routers, err := store.GetNetworkRoutersByNetID(context.Background(), LockingStrengthShare, account.Id, network.ID) routers, err := store.GetNetworkRoutersByNetID(context.Background(), LockingStrengthShare, account.Id, network.ID)
require.NoError(t, err, "expecting no error after removing DeleteAccount when searching for network routers") require.NoError(t, err, "expecting no error after removing DeleteAccount when searching for network routers")
require.Len(t, routers, 0, "expecting no network routers to be found after DeleteAccount") require.Len(t, routers, 0, "expecting no network routers to be found after DeleteAccount")
resources, err := store.GetNetworkResourcesByNetID(context.Background(), LockingStrengthShare, account.Id, network.ID)
require.NoError(t, err, "expecting no error after removing DeleteAccount when searching for network resources")
require.Len(t, resources, 0, "expecting no network resources to be found after DeleteAccount")
} }
} }
@ -2309,3 +2324,120 @@ func TestSqlStore_DeleteNetworkRouter(t *testing.T) {
require.Equal(t, status.NotFound, sErr.Type()) require.Equal(t, status.NotFound, sErr.Type())
require.Nil(t, netRouter) require.Nil(t, netRouter)
} }
func TestSqlStore_GetNetworkResourcesByNetID(t *testing.T) {
store, cleanup, err := NewTestStoreFromSQL(context.Background(), "testdata/store.sql", t.TempDir())
t.Cleanup(cleanup)
require.NoError(t, err)
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
tests := []struct {
name string
networkID string
expectedCount int
}{
{
name: "retrieve resources by existing network ID",
networkID: "ct286bi7qv930dsrrug0",
expectedCount: 1,
},
{
name: "retrieve resources by non-existing network ID",
networkID: "non-existent",
expectedCount: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resources, err := store.GetNetworkResourcesByNetID(context.Background(), LockingStrengthShare, accountID, tt.networkID)
require.NoError(t, err)
require.Len(t, resources, tt.expectedCount)
})
}
}
func TestSqlStore_GetNetworkResourceByID(t *testing.T) {
store, cleanup, err := NewTestStoreFromSQL(context.Background(), "testdata/store.sql", t.TempDir())
t.Cleanup(cleanup)
require.NoError(t, err)
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
tests := []struct {
name string
networkResourceID string
expectError bool
}{
{
name: "retrieve existing network resource ID",
networkResourceID: "ctc4nci7qv9061u6ilfg",
expectError: false,
},
{
name: "retrieve non-existing network resource ID",
networkResourceID: "non-existing",
expectError: true,
},
{
name: "retrieve network with empty resource ID",
networkResourceID: "",
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
networkResource, err := store.GetNetworkResourceByID(context.Background(), LockingStrengthShare, accountID, tt.networkResourceID)
if tt.expectError {
require.Error(t, err)
sErr, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, sErr.Type(), status.NotFound)
require.Nil(t, networkResource)
} else {
require.NoError(t, err)
require.NotNil(t, networkResource)
require.Equal(t, tt.networkResourceID, networkResource.ID)
}
})
}
}
func TestSqlStore_SaveNetworkResource(t *testing.T) {
store, cleanup, err := NewTestStoreFromSQL(context.Background(), "testdata/store.sql", t.TempDir())
t.Cleanup(cleanup)
require.NoError(t, err)
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
networkID := "ct286bi7qv930dsrrug0"
netResource, err := networks.NewNetworkResource(accountID, networkID, "resource-name", "resource-description", "example.com")
require.NoError(t, err)
err = store.SaveNetworkResource(context.Background(), LockingStrengthUpdate, netResource)
require.NoError(t, err)
savedNetResource, err := store.GetNetworkResourceByID(context.Background(), LockingStrengthShare, accountID, netResource.ID)
require.NoError(t, err)
require.Equal(t, netResource, savedNetResource)
}
func TestSqlStore_DeleteNetworkResource(t *testing.T) {
store, cleanup, err := NewTestStoreFromSQL(context.Background(), "testdata/store.sql", t.TempDir())
t.Cleanup(cleanup)
require.NoError(t, err)
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
netResourceID := "ctc4nci7qv9061u6ilfg"
err = store.DeleteNetworkResource(context.Background(), LockingStrengthUpdate, accountID, netResourceID)
require.NoError(t, err)
netRouter, err := store.GetNetworkByID(context.Background(), LockingStrengthShare, accountID, netResourceID)
require.Error(t, err)
sErr, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, status.NotFound, sErr.Type())
require.Nil(t, netRouter)
}

View File

@ -164,3 +164,8 @@ func NewNetworkNotFoundError(networkID string) error {
func NewNetworkRouterNotFoundError(routerID string) error { func NewNetworkRouterNotFoundError(routerID string) error {
return Errorf(NotFound, "network router: %s not found", routerID) return Errorf(NotFound, "network router: %s not found", routerID)
} }
// NewNetworkResourceNotFoundError creates a new Error with NotFound type for a missing network resource.
func NewNetworkResourceNotFoundError(resourceID string) error {
return Errorf(NotFound, "network resource: %s not found", resourceID)
}

View File

@ -152,7 +152,7 @@ type Store interface {
SaveNetworkRouter(ctx context.Context, lockStrength LockingStrength, router *networks.NetworkRouter) error SaveNetworkRouter(ctx context.Context, lockStrength LockingStrength, router *networks.NetworkRouter) error
DeleteNetworkRouter(ctx context.Context, lockStrength LockingStrength, accountID, routerID string) error DeleteNetworkRouter(ctx context.Context, lockStrength LockingStrength, accountID, routerID string) error
GetAccountNetworkResourceByNetID(ctx context.Context, lockStrength LockingStrength, accountID, netID string) (*networks.NetworkResource, error) GetNetworkResourcesByNetID(ctx context.Context, lockStrength LockingStrength, accountID, netID string) ([]*networks.NetworkResource, error)
GetNetworkResourceByID(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) (*networks.NetworkResource, error) GetNetworkResourceByID(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) (*networks.NetworkResource, error)
SaveNetworkResource(ctx context.Context, lockStrength LockingStrength, resource *networks.NetworkResource) error SaveNetworkResource(ctx context.Context, lockStrength LockingStrength, resource *networks.NetworkResource) error
DeleteNetworkResource(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) error DeleteNetworkResource(ctx context.Context, lockStrength LockingStrength, accountID, resourceID string) error

View File

@ -13,6 +13,7 @@ CREATE TABLE `extra_settings` (`peer_approval_enabled` numeric,`integrated_valid
CREATE TABLE `posture_checks` (`id` text,`name` text,`description` text,`account_id` text,`checks` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_posture_checks` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`)); CREATE TABLE `posture_checks` (`id` text,`name` text,`description` text,`account_id` text,`checks` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_posture_checks` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text); CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
CREATE TABLE `network_routers` (`id` text,`network_id` text,`account_id` text,`peer` text,`peer_groups` text,`masquerade` numeric,`metric` integer,PRIMARY KEY (`id`)); CREATE TABLE `network_routers` (`id` text,`network_id` text,`account_id` text,`peer` text,`peer_groups` text,`masquerade` numeric,`metric` integer,PRIMARY KEY (`id`));
CREATE TABLE `network_resources` (`id` text,`network_id` text,`account_id` text,`type` text,`address` text,PRIMARY KEY (`id`));
CREATE TABLE `networks` (`id` text,`account_id` text,`name` text,`description` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_networks` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`)); CREATE TABLE `networks` (`id` text,`account_id` text,`name` text,`description` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_networks` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`); CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`); CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
@ -29,6 +30,9 @@ CREATE INDEX `idx_posture_checks_account_id` ON `posture_checks`(`account_id`);
CREATE INDEX `idx_network_routers_id` ON `network_routers`(`id`); CREATE INDEX `idx_network_routers_id` ON `network_routers`(`id`);
CREATE INDEX `idx_network_routers_account_id` ON `network_routers`(`account_id`); CREATE INDEX `idx_network_routers_account_id` ON `network_routers`(`account_id`);
CREATE INDEX `idx_network_routers_network_id` ON `network_routers`(`network_id`); CREATE INDEX `idx_network_routers_network_id` ON `network_routers`(`network_id`);
CREATE INDEX `idx_network_resources_account_id` ON `network_resources`(`account_id`);
CREATE INDEX `idx_network_resources_network_id` ON `network_resources`(`network_id`);
CREATE INDEX `idx_network_resources_id` ON `network_resources`(`id`);
CREATE INDEX `idx_networks_id` ON `networks`(`id`); CREATE INDEX `idx_networks_id` ON `networks`(`id`);
CREATE INDEX `idx_networks_account_id` ON `networks`(`account_id`); CREATE INDEX `idx_networks_account_id` ON `networks`(`account_id`);
@ -42,4 +46,5 @@ INSERT INTO installations VALUES(1,'');
INSERT INTO policies VALUES('cs1tnh0hhcjnqoiuebf0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Default','This is a default rule that allows connections between all the resources',1,'[]'); INSERT INTO policies VALUES('cs1tnh0hhcjnqoiuebf0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Default','This is a default rule that allows connections between all the resources',1,'[]');
INSERT INTO policy_rules VALUES('cs387mkv2d4bgq41b6n0','cs1tnh0hhcjnqoiuebf0','Default','This is a default rule that allows connections between all the resources',1,'accept','["cs1tnh0hhcjnqoiuebeg"]','["cs1tnh0hhcjnqoiuebeg"]',1,'all',NULL,NULL); INSERT INTO policy_rules VALUES('cs387mkv2d4bgq41b6n0','cs1tnh0hhcjnqoiuebf0','Default','This is a default rule that allows connections between all the resources',1,'accept','["cs1tnh0hhcjnqoiuebeg"]','["cs1tnh0hhcjnqoiuebeg"]',1,'all',NULL,NULL);
INSERT INTO network_routers VALUES('ctc20ji7qv9ck2sebc80','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','cs1tnh0hhcjnqoiuebeg',NULL,0,0); INSERT INTO network_routers VALUES('ctc20ji7qv9ck2sebc80','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','cs1tnh0hhcjnqoiuebeg',NULL,0,0);
INSERT INTO network_resources VALUES ('ctc4nci7qv9061u6ilfg','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Host','192.168.1.1');
INSERT INTO networks VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Test Network','Test Network'); INSERT INTO networks VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Test Network','Test Network');