mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-01 22:56:41 +00:00
removed condition on 1 yop per account
This commit is contained in:
@@ -1,12 +1,9 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrAccountProxyAlreadyExists = errors.New("account already has a registered proxy")
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StatusConnected = "connected"
|
StatusConnected = "connected"
|
||||||
StatusDisconnected = "disconnected"
|
StatusDisconnected = "disconnected"
|
||||||
@@ -28,7 +25,7 @@ type Proxy struct {
|
|||||||
ID string `gorm:"primaryKey;type:varchar(255)"`
|
ID string `gorm:"primaryKey;type:varchar(255)"`
|
||||||
ClusterAddress string `gorm:"type:varchar(255);not null;index:idx_proxy_cluster_status"`
|
ClusterAddress string `gorm:"type:varchar(255);not null;index:idx_proxy_cluster_status"`
|
||||||
IPAddress string `gorm:"type:varchar(45)"`
|
IPAddress string `gorm:"type:varchar(45)"`
|
||||||
AccountID *string `gorm:"type:varchar(255);uniqueIndex:idx_proxy_account_id_unique"`
|
AccountID *string `gorm:"type:varchar(255);index:idx_proxy_account_id"`
|
||||||
LastSeen time.Time `gorm:"not null;index:idx_proxy_last_seen"`
|
LastSeen time.Time `gorm:"not null;index:idx_proxy_last_seen"`
|
||||||
ConnectedAt *time.Time
|
ConnectedAt *time.Time
|
||||||
DisconnectedAt *time.Time
|
DisconnectedAt *time.Time
|
||||||
|
|||||||
@@ -194,23 +194,6 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest
|
|||||||
if token != nil && token.AccountID != nil {
|
if token != nil && token.AccountID != nil {
|
||||||
accountID = token.AccountID
|
accountID = token.AccountID
|
||||||
|
|
||||||
existingProxy, err := s.proxyManager.GetAccountProxy(ctx, *accountID)
|
|
||||||
if err != nil {
|
|
||||||
if s, ok := nbstatus.FromError(err); ok && s.ErrorType == nbstatus.NotFound {
|
|
||||||
log.WithContext(ctx).Debugf("no existing BYOP proxy for account %s", *accountID)
|
|
||||||
} else {
|
|
||||||
return status.Errorf(codes.Internal, "failed to check existing proxy: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if existingProxy != nil && existingProxy.ID != proxyID {
|
|
||||||
if existingProxy.Status == proxy.StatusConnected {
|
|
||||||
return status.Errorf(codes.ResourceExhausted, "limit of 1 self-hosted proxy per account")
|
|
||||||
}
|
|
||||||
if err := s.proxyManager.DeleteProxy(ctx, existingProxy.ID); err != nil {
|
|
||||||
log.WithContext(ctx).Warnf("failed to cleanup disconnected proxy %s: %v", existingProxy.ID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
available, err := s.proxyManager.IsClusterAddressAvailable(ctx, proxyAddress, *accountID)
|
available, err := s.proxyManager.IsClusterAddressAvailable(ctx, proxyAddress, *accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.Errorf(codes.Internal, "check cluster address: %v", err)
|
return status.Errorf(codes.Internal, "check cluster address: %v", err)
|
||||||
@@ -248,9 +231,6 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest
|
|||||||
if err := s.proxyManager.Connect(ctx, proxyID, proxyAddress, peerInfo, accountID, caps); err != nil {
|
if err := s.proxyManager.Connect(ctx, proxyID, proxyAddress, peerInfo, accountID, caps); err != nil {
|
||||||
if accountID != nil {
|
if accountID != nil {
|
||||||
cancel()
|
cancel()
|
||||||
if errors.Is(err, proxy.ErrAccountProxyAlreadyExists) {
|
|
||||||
return status.Errorf(codes.ResourceExhausted, "limit of 1 self-hosted proxy per account")
|
|
||||||
}
|
|
||||||
return status.Errorf(codes.Internal, "failed to register BYOP proxy: %v", err)
|
return status.Errorf(codes.Internal, "failed to register BYOP proxy: %v", err)
|
||||||
}
|
}
|
||||||
log.WithContext(ctx).Warnf("Failed to register proxy %s in database: %v", proxyID, err)
|
log.WithContext(ctx).Warnf("Failed to register proxy %s in database: %v", proxyID, err)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/jackc/pgx/v5/pgconn"
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -5476,26 +5475,11 @@ func (s *SqlStore) SaveProxy(ctx context.Context, p *proxy.Proxy) error {
|
|||||||
result := s.db.WithContext(ctx).Save(p)
|
result := s.db.WithContext(ctx).Save(p)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
log.WithContext(ctx).Errorf("failed to save proxy: %v", result.Error)
|
log.WithContext(ctx).Errorf("failed to save proxy: %v", result.Error)
|
||||||
if isUniqueConstraintError(result.Error) {
|
|
||||||
return proxy.ErrAccountProxyAlreadyExists
|
|
||||||
}
|
|
||||||
return status.Errorf(status.Internal, "failed to save proxy")
|
return status.Errorf(status.Internal, "failed to save proxy")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUniqueConstraintError(err error) bool {
|
|
||||||
var pgErr *pgconn.PgError
|
|
||||||
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
errStr := err.Error()
|
|
||||||
return strings.Contains(errStr, "UNIQUE constraint") ||
|
|
||||||
strings.Contains(errStr, "duplicate key") ||
|
|
||||||
strings.Contains(errStr, "Duplicate entry") ||
|
|
||||||
strings.Contains(errStr, "Error 1062")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SqlStore) DisconnectProxy(ctx context.Context, proxyID string) error {
|
func (s *SqlStore) DisconnectProxy(ctx context.Context, proxyID string) error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
result := s.db.WithContext(ctx).
|
result := s.db.WithContext(ctx).
|
||||||
|
|||||||
@@ -502,6 +502,9 @@ func getMigrationsPostAuto(ctx context.Context) []migrationFunc {
|
|||||||
func(db *gorm.DB) error {
|
func(db *gorm.DB) error {
|
||||||
return migration.CreateIndexIfNotExists[nbpeer.Peer](ctx, db, "idx_peers_key_unique", "key")
|
return migration.CreateIndexIfNotExists[nbpeer.Peer](ctx, db, "idx_peers_key_unique", "key")
|
||||||
},
|
},
|
||||||
|
func(db *gorm.DB) error {
|
||||||
|
return migration.DropIndex[proxy.Proxy](ctx, db, "idx_proxy_account_id_unique")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ func TestIntegration_BYOPProxy_AccountBReceivesOnlyItsServices(t *testing.T) {
|
|||||||
assert.Equal(t, setup.accountB, mappings[0].GetAccountId())
|
assert.Equal(t, setup.accountB, mappings[0].GetAccountId())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIntegration_BYOPProxy_LimitOnePerAccount(t *testing.T) {
|
func TestIntegration_BYOPProxy_MultiplePerAccount(t *testing.T) {
|
||||||
setup := setupBYOPIntegrationTest(t)
|
setup := setupBYOPIntegrationTest(t)
|
||||||
defer setup.cleanup()
|
defer setup.cleanup()
|
||||||
|
|
||||||
@@ -269,7 +269,8 @@ func TestIntegration_BYOPProxy_LimitOnePerAccount(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_ = receiveBYOPMappings(t, stream1)
|
mappings1 := receiveBYOPMappings(t, stream1)
|
||||||
|
assert.Len(t, mappings1, 2, "first BYOP proxy should receive account A's 2 services")
|
||||||
|
|
||||||
ctx2, cancel2 := context.WithTimeout(byopContext(context.Background(), setup.accountAToken), 5*time.Second)
|
ctx2, cancel2 := context.WithTimeout(byopContext(context.Background(), setup.accountAToken), 5*time.Second)
|
||||||
defer cancel2()
|
defer cancel2()
|
||||||
@@ -281,13 +282,11 @@ func TestIntegration_BYOPProxy_LimitOnePerAccount(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = stream2.Recv()
|
mappings2 := receiveBYOPMappings(t, stream2)
|
||||||
require.Error(t, err)
|
assert.Len(t, mappings2, 2, "second BYOP proxy from same account should also receive the 2 services")
|
||||||
|
for _, m := range mappings2 {
|
||||||
st, ok := grpcstatus.FromError(err)
|
assert.Equal(t, setup.accountA, m.GetAccountId())
|
||||||
require.True(t, ok)
|
}
|
||||||
assert.Equal(t, codes.ResourceExhausted, st.Code(), "second BYOP proxy should be rejected with ResourceExhausted")
|
|
||||||
t.Logf("expected rejection: %s", st.Message())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIntegration_BYOPProxy_ClusterAddressConflict(t *testing.T) {
|
func TestIntegration_BYOPProxy_ClusterAddressConflict(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user