Skip to content

Commit

Permalink
v2tenancy: add optional LicenseFeature to type Registration struct (h…
Browse files Browse the repository at this point in the history
  • Loading branch information
analogue authored Feb 20, 2024
1 parent 53afd8f commit 943426b
Show file tree
Hide file tree
Showing 43 changed files with 448 additions and 83 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GO_MODULES := $(shell find . -name go.mod -exec dirname {} \; | grep -v "proto-g
# or the string @DEV to imply use what is currently installed locally.
###
GOLANGCI_LINT_VERSION='v1.55.2'
MOCKERY_VERSION='v2.37.1'
MOCKERY_VERSION='v2.41.0'
BUF_VERSION='v1.26.0'

PROTOC_GEN_GO_GRPC_VERSION='v1.2.0'
Expand Down
15 changes: 15 additions & 0 deletions agent/consul/server_ce.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import (

"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/consul/reporting"
resourcegrpc "github.com/hashicorp/consul/agent/grpc-external/services/resource"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/logging"
)

// runEnterpriseRateLimiterConfigEntryController start the rate limiter config controller
Expand Down Expand Up @@ -193,3 +196,15 @@ func getEnterpriseReportingDeps(deps Deps) reporting.EntDeps {
// no-op
return reporting.EntDeps{}
}

// CE version without LicenseManager
func (s *Server) newResourceServiceConfig(typeRegistry resource.Registry, resolver resourcegrpc.ACLResolver, tenancyBridge resourcegrpc.TenancyBridge) resourcegrpc.Config {
return resourcegrpc.Config{
Registry: typeRegistry,
Backend: s.storageBackend,
ACLResolver: resolver,
Logger: s.loggers.Named(logging.GRPCAPI).Named(logging.Resource),
TenancyBridge: tenancyBridge,
UseV2Tenancy: s.useV2Tenancy,
}
}
9 changes: 1 addition & 8 deletions agent/consul/server_grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,14 +360,7 @@ func (s *Server) registerResourceServiceServer(typeRegistry resource.Registry, r
}

// Create the Resource Service Server
srv := resourcegrpc.NewServer(resourcegrpc.Config{
Registry: typeRegistry,
Backend: s.storageBackend,
ACLResolver: resolver,
Logger: s.loggers.Named(logging.GRPCAPI).Named(logging.Resource),
TenancyBridge: tenancyBridge,
UseV2Tenancy: s.useV2Tenancy,
})
srv := resourcegrpc.NewServer(s.newResourceServiceConfig(typeRegistry, resolver, tenancyBridge))

// Register the server to all the desired interfaces
for _, reg := range registrars {
Expand Down
5 changes: 5 additions & 0 deletions agent/grpc-external/services/resource/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
// - Delete of a previously deleted or non-existent resource is a no-op to support idempotency.
// - Errors with Aborted if the requested Version does not match the stored Version.
// - Errors with PermissionDenied if ACL check fails
// - Errors with PermissionDenied if a license feature tied to the resource type is not allowed.
func (s *Server) Delete(ctx context.Context, req *pbresource.DeleteRequest) (*pbresource.DeleteResponse, error) {
reg, err := s.ensureDeleteRequestValid(req)
if err != nil {
Expand Down Expand Up @@ -195,6 +196,10 @@ func (s *Server) ensureDeleteRequestValid(req *pbresource.DeleteRequest) (*resou
return nil, err
}

if err = s.FeatureCheck(reg); err != nil {
return nil, err
}

if err = checkV2Tenancy(s.UseV2Tenancy, req.Id.Type); err != nil {
return nil, err
}
Expand Down
4 changes: 4 additions & 0 deletions agent/grpc-external/services/resource/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ func (s *Server) ensureListRequestValid(req *pbresource.ListRequest) (*resource.
return nil, err
}

// Ignore return value since read ops are allowed but will log a warning if the feature is
// not enabled in the license.
_ = s.FeatureCheck(reg)

if err = checkV2Tenancy(s.UseV2Tenancy, req.Type); err != nil {
return nil, err
}
Expand Down
16 changes: 16 additions & 0 deletions agent/grpc-external/services/resource/mock_Registry.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions agent/grpc-external/services/resource/mutate_and_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
)

func (s *Server) MutateAndValidate(ctx context.Context, req *pbresource.MutateAndValidateRequest) (*pbresource.MutateAndValidateResponse, error) {
tenancyMarkedForDeletion, err := s.mutateAndValidate(ctx, req.Resource)
tenancyMarkedForDeletion, err := s.mutateAndValidate(ctx, req.Resource, false)
if err != nil {
return nil, err
}
Expand All @@ -33,8 +33,8 @@ func (s *Server) MutateAndValidate(ctx context.Context, req *pbresource.MutateAn
}

// private DRY impl that is used by both the Write and MutateAndValidate RPCs.
func (s *Server) mutateAndValidate(ctx context.Context, res *pbresource.Resource) (tenancyMarkedForDeletion bool, err error) {
reg, err := s.ensureResourceValid(res)
func (s *Server) mutateAndValidate(ctx context.Context, res *pbresource.Resource, enforceLicenseCheck bool) (tenancyMarkedForDeletion bool, err error) {
reg, err := s.ensureResourceValid(res, enforceLicenseCheck)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -92,7 +92,7 @@ func (s *Server) mutateAndValidate(ctx context.Context, res *pbresource.Resource
return false, nil
}

func (s *Server) ensureResourceValid(res *pbresource.Resource) (*resource.Registration, error) {
func (s *Server) ensureResourceValid(res *pbresource.Resource, enforceLicenseCheck bool) (*resource.Registration, error) {
var field string
switch {
case res == nil:
Expand Down Expand Up @@ -121,6 +121,12 @@ func (s *Server) ensureResourceValid(res *pbresource.Resource) (*resource.Regist
return nil, err
}

// Since this is shared by Write and MutateAndValidate, only fail the operation
// if it's a write operation and the feature is not allowed by the license.
if err = s.FeatureCheck(reg); err != nil && enforceLicenseCheck {
return nil, err
}

if err = checkV2Tenancy(s.UseV2Tenancy, res.Id.Type); err != nil {
return nil, err
}
Expand Down
6 changes: 5 additions & 1 deletion agent/grpc-external/services/resource/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (s *Server) Read(ctx context.Context, req *pbresource.ReadRequest) (*pbreso
}

// acl.EnterpriseMeta acl.AuthorizerContext follow rules for V1 resources since they integrate with the V1 acl subsystem.
// pbresource.Tenacy follows rules for V2 resources and the Resource service.
// pbresource.Tenancy follows rules for V2 resources and the Resource service.
// Example:
//
// A CE namespace scoped resource:
Expand Down Expand Up @@ -102,6 +102,10 @@ func (s *Server) ensureReadRequestValid(req *pbresource.ReadRequest) (*resource.
return nil, err
}

// Ignore return value since read ops are allowed but will log a warning if the feature is
// not enabled in the license.
_ = s.FeatureCheck(reg)

if err = checkV2Tenancy(s.UseV2Tenancy, req.Id.Type); err != nil {
return nil, err
}
Expand Down
21 changes: 1 addition & 20 deletions agent/grpc-external/services/resource/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"

"github.com/hashicorp/go-hclog"

"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/acl/resolver"
"github.com/hashicorp/consul/internal/resource"
Expand All @@ -29,23 +27,6 @@ type Server struct {
Config
}

type Config struct {
Logger hclog.Logger
Registry Registry

// Backend is the storage backend that will be used for resource persistence.
Backend Backend
ACLResolver ACLResolver
// TenancyBridge temporarily allows us to use V1 implementations of
// partitions and namespaces until V2 implementations are available.
TenancyBridge TenancyBridge

// UseV2Tenancy is true if the "v2tenancy" experiement is active, false otherwise.
// Attempts to create v2 tenancy resources (partition or namespace) will fail when the
// flag is false.
UseV2Tenancy bool
}

//go:generate mockery --name Registry --inpackage
type Registry interface {
resource.Registry
Expand Down Expand Up @@ -79,7 +60,7 @@ func (s *Server) Register(registrar grpc.ServiceRegistrar) {
pbresource.RegisterResourceServiceServer(registrar, s)
}

// Get token from grpc metadata or AnonymounsTokenId if not found
// Get token from grpc metadata or AnonymousTokenId if not found
func tokenFromContext(ctx context.Context) string {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
Expand Down
24 changes: 24 additions & 0 deletions agent/grpc-external/services/resource/server_ce.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/hashicorp/go-hclog"

"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/proto-public/pbresource"
Expand Down Expand Up @@ -37,3 +39,25 @@ func checkV2Tenancy(useV2Tenancy bool, rtype *pbresource.Type) error {
}
return nil
}

type Config struct {
Logger hclog.Logger
Registry Registry

// Backend is the storage backend that will be used for resource persistence.
Backend Backend
ACLResolver ACLResolver
// TenancyBridge temporarily allows us to use V1 implementations of
// partitions and namespaces until V2 implementations are available.
TenancyBridge TenancyBridge

// UseV2Tenancy is true if the "v2tenancy" experiment is active, false otherwise.
// Attempts to create v2 tenancy resources (partition or namespace) will fail when the
// flag is false.
UseV2Tenancy bool
}

// FeatureCheck does not apply to the community edition.
func (s *Server) FeatureCheck(reg *resource.Registration) error {
return nil
}
2 changes: 1 addition & 1 deletion agent/grpc-external/services/resource/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func tenancyCases() map[string]func(artistId, recordlabelId *pbresource.ID) *pbr
id.Tenancy.Namespace = ""
return id
},
"namespaced resource inherits tokens partition and namespace when tenacy nil": func(artistId, _ *pbresource.ID) *pbresource.ID {
"namespaced resource inherits tokens partition and namespace when tenancy nil": func(artistId, _ *pbresource.ID) *pbresource.ID {
id := clone(artistId)
id.Tenancy = nil
return id
Expand Down
26 changes: 6 additions & 20 deletions agent/grpc-external/services/resource/testing/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,6 @@ import (
"github.com/hashicorp/consul/sdk/testutil"
)

type Builder struct {
registry resource.Registry
registerFns []func(resource.Registry)
useV2Tenancy bool
tenancies []*pbresource.Tenancy
aclResolver svc.ACLResolver
serviceImpl *svc.Server
cloning bool
}

// NewResourceServiceBuilder is the preferred way to configure and run
// an isolated in-process instance of the resource service for unit
// testing. The final call to `Run()` returns a client you can use for
Expand Down Expand Up @@ -61,7 +51,7 @@ func (b *Builder) Registry() resource.Registry {
return b.registry
}

// ServiceImpl provides access to the actual server side implemenation of the resource service. This should never be used
// ServiceImpl provides access to the actual server side implementation of the resource service. This should never be
// used/accessed without good reason. The current justifying use case is to monkeypatch the ACL resolver post-creation
// to allow unfettered writes which some ACL related tests require to put test data in place.
func (b *Builder) ServiceImpl() *svc.Server {
Expand Down Expand Up @@ -167,16 +157,12 @@ func (b *Builder) Run(t testutil.TestingTB) pbresource.ResourceServiceClient {
b.aclResolver = mockACLResolver
}

config := svc.Config{
Logger: testutil.Logger(t),
Registry: b.registry,
Backend: backend,
ACLResolver: b.aclResolver,
TenancyBridge: tenancyBridge,
UseV2Tenancy: b.useV2Tenancy,
}
// ent only
b.ensureLicenseManager()

config := b.newConfig(testutil.Logger(t), backend, tenancyBridge)

b.serviceImpl = svc.NewServer(config)
b.serviceImpl = svc.NewServer(*config)
ch := &inprocgrpc.Channel{}
pbresource.RegisterResourceServiceServer(ch, b.serviceImpl)
client := pbresource.NewResourceServiceClient(ch)
Expand Down
38 changes: 38 additions & 0 deletions agent/grpc-external/services/resource/testing/builder_ce.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

//go:build !consulent

package testing

import (
"github.com/hashicorp/go-hclog"

svc "github.com/hashicorp/consul/agent/grpc-external/services/resource"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/proto-public/pbresource"
)

type Builder struct {
registry resource.Registry
registerFns []func(resource.Registry)
useV2Tenancy bool
tenancies []*pbresource.Tenancy
aclResolver svc.ACLResolver
serviceImpl *svc.Server
cloning bool
}

func (b *Builder) ensureLicenseManager() {
}

func (b *Builder) newConfig(logger hclog.Logger, backend svc.Backend, tenancyBridge resource.TenancyBridge) *svc.Config {
return &svc.Config{
Logger: logger,
Registry: b.registry,
Backend: backend,
ACLResolver: b.aclResolver,
TenancyBridge: tenancyBridge,
UseV2Tenancy: b.useV2Tenancy,
}
}
4 changes: 4 additions & 0 deletions agent/grpc-external/services/resource/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ func (s *Server) ensureWatchListRequestValid(req *pbresource.WatchListRequest) (
return nil, err
}

// Ignore return value since read ops are allowed but will log a warning if the feature is
// not enabled in the license.
_ = s.FeatureCheck(reg)

// if no tenancy is passed defaults to wildcard
if req.Tenancy == nil {
req.Tenancy = wildcardTenancyFor(reg.Scope)
Expand Down
2 changes: 1 addition & 1 deletion agent/grpc-external/services/resource/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
var errUseWriteStatus = status.Error(codes.InvalidArgument, "resource.status can only be set using the WriteStatus endpoint")

func (s *Server) Write(ctx context.Context, req *pbresource.WriteRequest) (*pbresource.WriteResponse, error) {
tenancyMarkedForDeletion, err := s.mutateAndValidate(ctx, req.Resource)
tenancyMarkedForDeletion, err := s.mutateAndValidate(ctx, req.Resource, true)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion agent/grpc-external/services/resource/write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ func TestWrite_Update_StatusModified(t *testing.T) {
require.NoError(t, err)
res = statusRsp.Resource

// Passing the staus unmodified should be fine.
// Passing the status unmodified should be fine.
rsp2, err := client.Write(testContext(t), &pbresource.WriteRequest{Resource: res})
require.NoError(t, err)

Expand Down
10 changes: 9 additions & 1 deletion grpcmocks/proto-public/pbacl/mock_ACLServiceClient.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 943426b

Please sign in to comment.