diff --git a/management/internals/modules/reverseproxy/service/manager/manager.go b/management/internals/modules/reverseproxy/service/manager/manager.go index ea1f5af91..547922982 100644 --- a/management/internals/modules/reverseproxy/service/manager/manager.go +++ b/management/internals/modules/reverseproxy/service/manager/manager.go @@ -15,7 +15,6 @@ import ( "github.com/netbirdio/netbird/management/server/permissions/modules" "github.com/netbirdio/netbird/management/server/permissions/operations" "github.com/netbirdio/netbird/management/server/store" - "github.com/netbirdio/netbird/shared/management/proto" "github.com/netbirdio/netbird/shared/management/status" ) @@ -345,22 +344,6 @@ func (m *Manager) sendServiceUpdateNotifications(ctx context.Context, accountID } } -func (m *managerImpl) sendServiceUpdate(service *reverseproxy.Service, operation reverseproxy.Operation, cluster, oldService string) { - oidcCfg := m.proxyGRPCServer.GetOIDCValidationConfig() - mapping := service.ToProtoMapping(operation, oldService, oidcCfg) - m.sendMappingsToCluster([]*proto.ProxyMapping{mapping}, cluster) -} - -func (m *managerImpl) sendMappingsToCluster(mappings []*proto.ProxyMapping, cluster string) { - if len(mappings) == 0 { - return - } - update := &proto.GetMappingUpdateResponse{ - Mapping: mappings, - } - m.proxyGRPCServer.SendServiceUpdateToCluster(update, cluster) -} - // validateTargetReferences checks that all target IDs reference existing peers or resources in the account. func validateTargetReferences(ctx context.Context, transaction store.Store, accountID string, targets []*service.Target) error { for _, target := range targets { @@ -420,6 +403,47 @@ func (m *Manager) DeleteService(ctx context.Context, accountID, userID, serviceI return nil } +func (m *Manager) DeleteAllServices(ctx context.Context, accountID, userID string) error { + ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Services, operations.Delete) + if err != nil { + return status.NewPermissionValidationError(err) + } + if !ok { + return status.NewPermissionDeniedError() + } + + var services []*service.Service + err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error { + var err error + services, err = transaction.GetAccountServices(ctx, store.LockingStrengthUpdate, accountID) + if err != nil { + return err + } + + for _, svc := range services { + if err = transaction.DeleteService(ctx, accountID, svc.ID); err != nil { + return fmt.Errorf("failed to delete service: %w", err) + } + } + + return nil + }) + if err != nil { + return err + } + + oidcCfg := m.proxyController.GetOIDCValidationConfig() + + for _, svc := range services { + m.accountManager.StoreEvent(ctx, userID, svc.ID, accountID, activity.ServiceDeleted, svc.EventMeta()) + m.proxyController.SendServiceUpdateToCluster(ctx, accountID, svc.ToProtoMapping(service.Delete, "", oidcCfg), svc.ProxyCluster) + } + + m.accountManager.UpdateAccountPeers(ctx, accountID) + + return nil +} + // SetCertificateIssuedAt sets the certificate issued timestamp to the current time. // Call this when receiving a gRPC notification that the certificate was issued. func (m *Manager) SetCertificateIssuedAt(ctx context.Context, accountID, serviceID string) error { diff --git a/management/internals/shared/grpc/proxy.go b/management/internals/shared/grpc/proxy.go index 6f75a4d39..7588790b5 100644 --- a/management/internals/shared/grpc/proxy.go +++ b/management/internals/shared/grpc/proxy.go @@ -458,8 +458,12 @@ func (s *ProxyServiceServer) GetConnectedProxyURLs() []string { // For create/update operations a unique one-time auth token is generated per // proxy so that every replica can independently authenticate with management. func (s *ProxyServiceServer) SendServiceUpdateToCluster(ctx context.Context, update *proto.ProxyMapping, clusterAddr string) { + updateResponse := &proto.GetMappingUpdateResponse{ + Mapping: []*proto.ProxyMapping{update}, + } + if clusterAddr == "" { - s.SendServiceUpdate(update) + s.SendServiceUpdate(updateResponse) return } @@ -478,7 +482,7 @@ func (s *ProxyServiceServer) SendServiceUpdateToCluster(ctx context.Context, upd for _, proxyID := range proxyIDs { if connVal, ok := s.connectedProxies.Load(proxyID); ok { conn := connVal.(*proxyConnection) - msg := s.perProxyMessage(update, proxyID) + msg := s.perProxyMessage(updateResponse, proxyID) if msg == nil { continue } diff --git a/management/server/account.go b/management/server/account.go index 42aa5d144..86e110b76 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -714,7 +714,7 @@ func (am *DefaultAccountManager) DeleteAccount(ctx context.Context, accountID, u return status.Errorf(status.Internal, "failed to build user infos for account %s: %v", accountID, err) } - err = am.reverseProxyManager.DeleteAllServices(ctx, accountID, userID) + err = am.serviceManager.DeleteAllServices(ctx, accountID, userID) if err != nil { return status.Errorf(status.Internal, "failed to delete service %s: %v", accountID, err) } diff --git a/management/server/store/store_mock.go b/management/server/store/store_mock.go index a382907a7..42bc94921 100644 --- a/management/server/store/store_mock.go +++ b/management/server/store/store_mock.go @@ -1124,21 +1124,6 @@ func (mr *MockStoreMockRecorder) GetAccountServices(ctx, lockStrength, accountID return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountServices", reflect.TypeOf((*MockStore)(nil).GetAccountServices), ctx, lockStrength, accountID) } -// GetServicesByAccountID mocks base method. -func (m *MockStore) GetServicesByAccountID(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*reverseproxy.Service, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetServicesByAccountID", ctx, lockStrength, accountID) - ret0, _ := ret[0].([]*reverseproxy.Service) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetServicesByAccountID indicates an expected call of GetServicesByAccountID. -func (mr *MockStoreMockRecorder) GetServicesByAccountID(ctx, lockStrength, accountID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServicesByAccountID", reflect.TypeOf((*MockStore)(nil).GetServicesByAccountID), ctx, lockStrength, accountID) -} - // GetAccountSettings mocks base method. func (m *MockStore) GetAccountSettings(ctx context.Context, lockStrength LockingStrength, accountID string) (*types2.Settings, error) { m.ctrl.T.Helper()