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:
Dhia Ayachi 2023-09-18 12:25:05 -04:00 committed by GitHub
parent bf4e0b1aa9
commit 4435e4a420
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 89 additions and 32 deletions

View File

@ -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)

View File

@ -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}
}

View File

@ -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.

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -90,7 +90,7 @@ func testServer(t *testing.T) *Server {
Registry: resource.NewRegistry(),
Backend: backend,
ACLResolver: mockACLResolver,
V1TenancyBridge: mockTenancyBridge,
TenancyBridge: mockTenancyBridge,
})
}

View File

@ -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()

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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
}