mirror of https://github.com/status-im/consul.git
add v2 tenancy bridge Flag and v2 Tenancy Bridge initial implementation (#18830)
* add v2 tenancy bridge and a feature flag for v2 tenancy * move tenancy bridge v2 under resource package
This commit is contained in:
parent
bf4e0b1aa9
commit
4435e4a420
|
@ -137,6 +137,7 @@ const (
|
|||
LeaderTransferMinVersion = "1.6.0"
|
||||
|
||||
CatalogResourceExperimentName = "resource-apis"
|
||||
V2TenancyExperimentName = "v2tenancy"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -819,7 +820,7 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server,
|
|||
go s.reportingManager.Run(&lib.StopChannelContext{StopCh: s.shutdownCh})
|
||||
|
||||
// Setup insecure resource service client.
|
||||
if err := s.setupInsecureResourceServiceClient(flat.Registry, logger); err != nil {
|
||||
if err := s.setupInsecureResourceServiceClient(flat.Registry, logger, flat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -1393,29 +1394,38 @@ func (s *Server) setupExternalGRPC(config *Config, deps Deps, logger hclog.Logge
|
|||
})
|
||||
s.peerStreamServer.Register(s.externalGRPCServer)
|
||||
|
||||
tenancyBridge := NewV1TenancyBridge(s)
|
||||
if stringslice.Contains(deps.Experiments, V2TenancyExperimentName) {
|
||||
tenancyBridge = resource.NewV2TenancyBridge()
|
||||
}
|
||||
|
||||
s.resourceServiceServer = resourcegrpc.NewServer(resourcegrpc.Config{
|
||||
Registry: deps.Registry,
|
||||
Backend: s.raftStorageBackend,
|
||||
ACLResolver: s.ACLResolver,
|
||||
Logger: logger.Named("grpc-api.resource"),
|
||||
V1TenancyBridge: NewV1TenancyBridge(s),
|
||||
TenancyBridge: tenancyBridge,
|
||||
})
|
||||
s.resourceServiceServer.Register(s.externalGRPCServer)
|
||||
|
||||
reflection.Register(s.externalGRPCServer)
|
||||
}
|
||||
|
||||
func (s *Server) setupInsecureResourceServiceClient(typeRegistry resource.Registry, logger hclog.Logger) error {
|
||||
func (s *Server) setupInsecureResourceServiceClient(typeRegistry resource.Registry, logger hclog.Logger, deps Deps) error {
|
||||
if s.raftStorageBackend == nil {
|
||||
return fmt.Errorf("raft storage backend cannot be nil")
|
||||
}
|
||||
|
||||
tenancyBridge := NewV1TenancyBridge(s)
|
||||
if stringslice.Contains(deps.Experiments, V2TenancyExperimentName) {
|
||||
tenancyBridge = resource.NewV2TenancyBridge()
|
||||
}
|
||||
server := resourcegrpc.NewServer(resourcegrpc.Config{
|
||||
Registry: typeRegistry,
|
||||
Backend: s.raftStorageBackend,
|
||||
ACLResolver: resolver.DANGER_NO_AUTH{},
|
||||
Logger: logger.Named("grpc-api.resource"),
|
||||
V1TenancyBridge: NewV1TenancyBridge(s),
|
||||
TenancyBridge: tenancyBridge,
|
||||
})
|
||||
|
||||
conn, err := s.runInProcessGRPCServer(server.Register)
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
package consul
|
||||
|
||||
import "github.com/hashicorp/consul/agent/grpc-external/services/resource"
|
||||
|
||||
// V1TenancyBridge is used by the resource service to access V1 implementations of
|
||||
// partitions and namespaces. This bridge will be removed when V2 implemenations
|
||||
// of partitions and namespaces are available.
|
||||
|
@ -10,6 +12,6 @@ type V1TenancyBridge struct {
|
|||
server *Server
|
||||
}
|
||||
|
||||
func NewV1TenancyBridge(server *Server) *V1TenancyBridge {
|
||||
func NewV1TenancyBridge(server *Server) resource.TenancyBridge {
|
||||
return &V1TenancyBridge{server: server}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"github.com/hashicorp/consul/proto-public/pbresource"
|
||||
)
|
||||
|
||||
// Deletes a resource.
|
||||
// Delete deletes a resource.
|
||||
// - To delete a resource regardless of the stored version, set Version = ""
|
||||
// - Supports deleting a resource by name, hence Id.Uid may be empty.
|
||||
// - Delete of a previously deleted or non-existent resource is a no-op to support idempotency.
|
||||
|
|
|
@ -43,7 +43,7 @@ func (s *Server) ListByOwner(ctx context.Context, req *pbresource.ListByOwnerReq
|
|||
}
|
||||
|
||||
// Check v1 tenancy exists for the v2 resource.
|
||||
if err = v1TenancyExists(reg, s.V1TenancyBridge, req.Owner.Tenancy, codes.InvalidArgument); err != nil {
|
||||
if err = v1TenancyExists(reg, s.TenancyBridge, req.Owner.Tenancy, codes.InvalidArgument); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ func (s *Server) Read(ctx context.Context, req *pbresource.ReadRequest) (*pbreso
|
|||
}
|
||||
|
||||
// Check V1 tenancy exists for the V2 resource.
|
||||
if err = v1TenancyExists(reg, s.V1TenancyBridge, req.Id.Tenancy, codes.NotFound); err != nil {
|
||||
if err = v1TenancyExists(reg, s.TenancyBridge, req.Id.Tenancy, codes.NotFound); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ type Config struct {
|
|||
// Backend is the storage backend that will be used for resource persistence.
|
||||
Backend Backend
|
||||
ACLResolver ACLResolver
|
||||
// V1TenancyBridge temporarily allows us to use V1 implementations of
|
||||
// TenancyBridge temporarily allows us to use V1 implementations of
|
||||
// partitions and namespaces until V2 implementations are available.
|
||||
V1TenancyBridge TenancyBridge
|
||||
TenancyBridge TenancyBridge
|
||||
}
|
||||
|
||||
//go:generate mockery --name Registry --inpackage
|
||||
|
|
|
@ -90,7 +90,7 @@ func testServer(t *testing.T) *Server {
|
|||
Registry: resource.NewRegistry(),
|
||||
Backend: backend,
|
||||
ACLResolver: mockACLResolver,
|
||||
V1TenancyBridge: mockTenancyBridge,
|
||||
TenancyBridge: mockTenancyBridge,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ func RunResourceServiceWithACL(t *testing.T, aclResolver svc.ACLResolver, regist
|
|||
Registry: registry,
|
||||
Logger: testutil.Logger(t),
|
||||
ACLResolver: aclResolver,
|
||||
V1TenancyBridge: mockTenancyBridge,
|
||||
TenancyBridge: mockTenancyBridge,
|
||||
}).Register(server)
|
||||
|
||||
pipe := internal.NewPipeListener()
|
||||
|
|
|
@ -71,12 +71,12 @@ func (s *Server) Write(ctx context.Context, req *pbresource.WriteRequest) (*pbre
|
|||
}
|
||||
|
||||
// Check V1 tenancy exists for the V2 resource
|
||||
if err = v1TenancyExists(reg, s.V1TenancyBridge, req.Resource.Id.Tenancy, codes.InvalidArgument); err != nil {
|
||||
if err = v1TenancyExists(reg, s.TenancyBridge, req.Resource.Id.Tenancy, codes.InvalidArgument); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check V1 tenancy not marked for deletion.
|
||||
if err = v1TenancyMarkedForDeletion(reg, s.V1TenancyBridge, req.Resource.Id.Tenancy); err != nil {
|
||||
if err = v1TenancyMarkedForDeletion(reg, s.TenancyBridge, req.Resource.Id.Tenancy); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ func (s *Server) WriteStatus(ctx context.Context, req *pbresource.WriteStatusReq
|
|||
|
||||
// Check V1 tenancy exists for the V2 resource. Ignore "marked for deletion" since status updates
|
||||
// should still work regardless.
|
||||
if err = v1TenancyExists(reg, s.V1TenancyBridge, req.Id.Tenancy, codes.InvalidArgument); err != nil {
|
||||
if err = v1TenancyExists(reg, s.TenancyBridge, req.Id.Tenancy, codes.InvalidArgument); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -416,7 +416,7 @@ func TestWrite_Tenancy_MarkedForDeletion(t *testing.T) {
|
|||
mockTenancyBridge := &MockTenancyBridge{}
|
||||
mockTenancyBridge.On("PartitionExists", "part1").Return(true, nil)
|
||||
mockTenancyBridge.On("NamespaceExists", "part1", "ns1").Return(true, nil)
|
||||
server.V1TenancyBridge = mockTenancyBridge
|
||||
server.TenancyBridge = mockTenancyBridge
|
||||
|
||||
_, err = client.Write(testContext(t), &pbresource.WriteRequest{Resource: tc.modFn(artist, recordLabel, mockTenancyBridge)})
|
||||
require.Error(t, err)
|
||||
|
|
|
@ -12,11 +12,27 @@ import (
|
|||
"github.com/hashicorp/consul/proto-public/pbresource"
|
||||
)
|
||||
|
||||
type TenancyBridge interface {
|
||||
PartitionExists(partition string) (bool, error)
|
||||
IsPartitionMarkedForDeletion(partition string) (bool, error)
|
||||
NamespaceExists(partition, namespace string) (bool, error)
|
||||
IsNamespaceMarkedForDeletion(partition, namespace string) (bool, error)
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultPartitionName = "default"
|
||||
DefaultNamespaceName = "default"
|
||||
)
|
||||
|
||||
// V2TenancyBridge is used by the resource service to access V2 implementations of
|
||||
// partitions and namespaces.
|
||||
type V2TenancyBridge struct {
|
||||
}
|
||||
|
||||
func NewV2TenancyBridge() TenancyBridge {
|
||||
return &V2TenancyBridge{}
|
||||
}
|
||||
|
||||
// Scope describes the tenancy scope of a resource.
|
||||
type Scope int
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
//go:build !consulent
|
||||
// +build !consulent
|
||||
|
||||
package resource
|
||||
|
||||
func (b *V2TenancyBridge) PartitionExists(partition string) (bool, error) {
|
||||
if partition == "default" {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (b *V2TenancyBridge) IsPartitionMarkedForDeletion(partition string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (b *V2TenancyBridge) NamespaceExists(partition, namespace string) (bool, error) {
|
||||
if partition == "default" && namespace == "default" {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (b *V2TenancyBridge) IsNamespaceMarkedForDeletion(partition, namespace string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
Loading…
Reference in New Issue