-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Net 5875 - Create the Exported Services Resources (#19117)
* init * computed exported service * make proto * exported services resource * exported services test * added some tests and namespace exported service * partition exported services * computed service * computed services tests * register types * fix comment * make proto lint * fix proto format make proto * make codegen * Update proto-public/pbmulticluster/v1alpha1/computed_exported_services.proto Co-authored-by: Eric Haberkorn <[email protected]> * Update internal/multicluster/internal/types/computed_exported_services.go Co-authored-by: Eric Haberkorn <[email protected]> * using different way of resource creation in tests * make proto * fix computed exported services test * fix tests * differnet validation for computed services for ent and ce * Acls for exported services * added validations for enterprise features in ce * fix error * fix acls test * Update internal/multicluster/internal/types/validation_exported_services_ee.go Co-authored-by: Eric Haberkorn <[email protected]> * removed the create method * update proto * removed namespace * created seperate function for ce and ent * test files updated and validations fixed * added nil checks * fix tests * added comments * removed tenancy check * added mutation function * fix mutation method * fix list permissions in test * fix pr comments * fix tests * lisence * busl license * Update internal/multicluster/internal/types/helpers_ce.go Co-authored-by: Eric Haberkorn <[email protected]> * Update internal/multicluster/internal/types/helpers_ce.go Co-authored-by: Eric Haberkorn <[email protected]> * Update internal/multicluster/internal/types/helpers_ce.go Co-authored-by: Eric Haberkorn <[email protected]> * make proto * some pr comments addressed * some pr comments addressed * acls helper * some comment changes * removed unused files * fixes * fix function in file * caps * some positioing * added test for validation error * fix names * made valid a function * remvoed patch * removed mutations * v2 beta1 * v2beta1 * rmeoved v1alpha1 * validate error * merge ent * some nits * removed dup func * removed nil check --------- Co-authored-by: Eric Haberkorn <[email protected]>
- Loading branch information
1 parent
b5023b6
commit 0295b95
Showing
39 changed files
with
2,889 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package multicluster | ||
|
||
import ( | ||
"github.com/hashicorp/consul/internal/multicluster/internal/types" | ||
"github.com/hashicorp/consul/internal/resource" | ||
) | ||
|
||
var ( | ||
// API Group Information | ||
APIGroup = types.GroupName | ||
VersionV2Beta1 = types.VersionV2Beta1 | ||
CurrentVersion = types.CurrentVersion | ||
) | ||
|
||
// RegisterTypes adds all resource types within the "multicluster" API group | ||
// to the given type registry | ||
func RegisterTypes(r resource.Registry) { | ||
types.Register(r) | ||
} |
37 changes: 37 additions & 0 deletions
37
internal/multicluster/internal/types/computed_exported_services.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package types | ||
|
||
import ( | ||
"github.com/hashicorp/consul/acl" | ||
"github.com/hashicorp/consul/internal/resource" | ||
pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2beta1" | ||
"github.com/hashicorp/consul/proto-public/pbresource" | ||
) | ||
|
||
const ( | ||
ComputedExportedServicesName = "global" | ||
) | ||
|
||
func RegisterComputedExportedServices(r resource.Registry) { | ||
r.Register(resource.Registration{ | ||
Type: pbmulticluster.ComputedExportedServicesType, | ||
Proto: &pbmulticluster.ComputedExportedServices{}, | ||
Scope: resource.ScopePartition, | ||
Validate: ValidateComputedExportedServices, | ||
ACLs: &resource.ACLHooks{ | ||
Read: aclReadHookComputedExportedServices, | ||
Write: aclWriteHookComputedExportedServices, | ||
List: resource.NoOpACLListHook, | ||
}, | ||
}) | ||
} | ||
|
||
func aclReadHookComputedExportedServices(authorizer acl.Authorizer, authzContext *acl.AuthorizerContext, _ *pbresource.ID, res *pbresource.Resource) error { | ||
return authorizer.ToAllowAuthorizer().MeshReadAllowed(authzContext) | ||
} | ||
|
||
func aclWriteHookComputedExportedServices(authorizer acl.Authorizer, authzContext *acl.AuthorizerContext, _ *pbresource.Resource) error { | ||
return authorizer.ToAllowAuthorizer().MeshWriteAllowed(authzContext) | ||
} |
178 changes: 178 additions & 0 deletions
178
internal/multicluster/internal/types/computed_exported_services_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package types | ||
|
||
import ( | ||
"errors" | ||
"github.com/hashicorp/consul/agent/structs" | ||
"github.com/hashicorp/consul/internal/resource" | ||
"github.com/hashicorp/consul/internal/resource/resourcetest" | ||
pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2beta1" | ||
"github.com/hashicorp/consul/proto-public/pbresource" | ||
"github.com/stretchr/testify/require" | ||
"testing" | ||
) | ||
|
||
func computedExportedServicesWithPartition(partitionName string) *pbmulticluster.ComputedExportedServices { | ||
consumers := []*pbmulticluster.ComputedExportedService{ | ||
{ | ||
Consumers: []*pbmulticluster.ComputedExportedServicesConsumer{ | ||
{ | ||
ConsumerTenancy: &pbmulticluster.ComputedExportedServicesConsumer_Partition{ | ||
Partition: partitionName, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
return &pbmulticluster.ComputedExportedServices{ | ||
Consumers: consumers, | ||
} | ||
} | ||
|
||
func computedExportedServicesWithPeer(peerName string) *pbmulticluster.ComputedExportedServices { | ||
consumers := []*pbmulticluster.ComputedExportedService{ | ||
{ | ||
Consumers: []*pbmulticluster.ComputedExportedServicesConsumer{ | ||
{ | ||
ConsumerTenancy: &pbmulticluster.ComputedExportedServicesConsumer_Peer{ | ||
Peer: peerName, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
return &pbmulticluster.ComputedExportedServices{ | ||
Consumers: consumers, | ||
} | ||
} | ||
|
||
func TestComputedExportedServicesValidations_InvalidName(t *testing.T) { | ||
res := resourcetest.Resource(pbmulticluster.ComputedExportedServicesType, "computed-exported-services"). | ||
WithData(t, computedExportedServicesWithPeer("peer")). | ||
Build() | ||
|
||
err := ValidateComputedExportedServices(res) | ||
require.Error(t, err) | ||
expectedError := errors.New("invalid \"name\" field: name can only be \"global\"") | ||
require.ErrorAs(t, err, &expectedError) | ||
} | ||
|
||
func TestComputedExportedServicesACLs(t *testing.T) { | ||
// Wire up a registry to generically invoke hooks | ||
registry := resource.NewRegistry() | ||
Register(registry) | ||
|
||
type testcase struct { | ||
rules string | ||
readOK string | ||
writeOK string | ||
listOK string | ||
} | ||
|
||
const ( | ||
DENY = resourcetest.DENY | ||
ALLOW = resourcetest.ALLOW | ||
DEFAULT = resourcetest.DEFAULT | ||
) | ||
|
||
exportedServiceData := &pbmulticluster.ComputedExportedServices{} | ||
res := resourcetest.Resource(pbmulticluster.ComputedExportedServicesType, "global"). | ||
WithData(t, exportedServiceData). | ||
Build() | ||
resourcetest.ValidateAndNormalize(t, registry, res) | ||
|
||
cases := map[string]testcase{ | ||
"no rules": { | ||
rules: ``, | ||
readOK: DENY, | ||
writeOK: DENY, | ||
listOK: DEFAULT, | ||
}, | ||
"mesh read policy": { | ||
rules: `mesh = "read"`, | ||
readOK: ALLOW, | ||
writeOK: DENY, | ||
listOK: DEFAULT, | ||
}, | ||
"mesh write policy": { | ||
rules: `mesh = "write"`, | ||
readOK: ALLOW, | ||
writeOK: ALLOW, | ||
listOK: DEFAULT, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
aclTestCase := resourcetest.ACLTestCase{ | ||
Rules: tc.rules, | ||
Res: res, | ||
ReadOK: tc.readOK, | ||
WriteOK: tc.writeOK, | ||
ListOK: tc.listOK, | ||
} | ||
resourcetest.RunACLTestCase(t, aclTestCase, registry) | ||
} | ||
} | ||
|
||
func TestComputedExportedServicesValidations(t *testing.T) { | ||
type testcase struct { | ||
Resource *pbresource.Resource | ||
expectErrorCE []string | ||
expectErrorENT []string | ||
} | ||
|
||
isEnterprise := structs.NodeEnterpriseMetaInDefaultPartition().PartitionOrEmpty() == "default" | ||
|
||
run := func(t *testing.T, tc testcase) { | ||
expectError := tc.expectErrorCE | ||
if isEnterprise { | ||
expectError = tc.expectErrorENT | ||
} | ||
err := ValidateComputedExportedServices(tc.Resource) | ||
if len(expectError) == 0 { | ||
require.NoError(t, err) | ||
} else { | ||
require.Error(t, err) | ||
for _, er := range expectError { | ||
require.ErrorContains(t, err, er) | ||
} | ||
} | ||
} | ||
|
||
cases := map[string]testcase{ | ||
"computed exported services with peer": { | ||
Resource: resourcetest.Resource(pbmulticluster.ComputedExportedServicesType, ComputedExportedServicesName). | ||
WithData(t, computedExportedServicesWithPeer("peer")). | ||
Build(), | ||
}, | ||
"computed exported services with partition": { | ||
Resource: resourcetest.Resource(pbmulticluster.ComputedExportedServicesType, ComputedExportedServicesName). | ||
WithData(t, computedExportedServicesWithPartition("partition")). | ||
Build(), | ||
expectErrorCE: []string{`invalid element at index 0 of list "partition": can only be set in Enterprise`}, | ||
}, | ||
"computed exported services with peer empty": { | ||
Resource: resourcetest.Resource(pbmulticluster.ComputedExportedServicesType, ComputedExportedServicesName). | ||
WithData(t, computedExportedServicesWithPeer("")). | ||
Build(), | ||
expectErrorCE: []string{`invalid element at index 0 of list "peer": can not be empty`}, | ||
expectErrorENT: []string{`invalid element at index 0 of list "peer": can not be empty`}, | ||
}, | ||
"computed exported services with partition empty": { | ||
Resource: resourcetest.Resource(pbmulticluster.ComputedExportedServicesType, ComputedExportedServicesName). | ||
WithData(t, computedExportedServicesWithPartition("")). | ||
Build(), | ||
expectErrorCE: []string{`invalid element at index 0 of list "partition": can not be empty`, | ||
`invalid element at index 0 of list "partition": can only be set in Enterprise`}, | ||
expectErrorENT: []string{`invalid element at index 0 of list "partition": can not be empty`}, | ||
}, | ||
} | ||
|
||
for name, tc := range cases { | ||
t.Run(name, func(t *testing.T) { | ||
run(t, tc) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package types | ||
|
||
import ( | ||
"github.com/hashicorp/consul/acl" | ||
"github.com/hashicorp/consul/internal/resource" | ||
pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2beta1" | ||
"github.com/hashicorp/consul/proto-public/pbresource" | ||
) | ||
|
||
func RegisterExportedServices(r resource.Registry) { | ||
r.Register(resource.Registration{ | ||
Type: pbmulticluster.ExportedServicesType, | ||
Proto: &pbmulticluster.ExportedServices{}, | ||
Scope: resource.ScopeNamespace, | ||
Validate: ValidateExportedServices, | ||
ACLs: &resource.ACLHooks{ | ||
Read: aclReadHookExportedServices, | ||
Write: aclWriteHookExportedServices, | ||
List: resource.NoOpACLListHook, | ||
}, | ||
}) | ||
} | ||
|
||
func aclReadHookExportedServices(authorizer acl.Authorizer, authzContext *acl.AuthorizerContext, _ *pbresource.ID, res *pbresource.Resource) error { | ||
if res == nil { | ||
return resource.ErrNeedResource | ||
} | ||
|
||
var exportedService pbmulticluster.ExportedServices | ||
|
||
if err := res.Data.UnmarshalTo(&exportedService); err != nil { | ||
return resource.NewErrDataParse(&exportedService, err) | ||
} | ||
|
||
for _, serviceName := range exportedService.Services { | ||
if err := authorizer.ToAllowAuthorizer().ServiceReadAllowed(serviceName, authzContext); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func aclWriteHookExportedServices(authorizer acl.Authorizer, authzContext *acl.AuthorizerContext, res *pbresource.Resource) error { | ||
var exportedService pbmulticluster.ExportedServices | ||
|
||
if err := res.Data.UnmarshalTo(&exportedService); err != nil { | ||
return resource.NewErrDataParse(&exportedService, err) | ||
} | ||
|
||
for _, serviceName := range exportedService.Services { | ||
if err := authorizer.ToAllowAuthorizer().ServiceWriteAllowed(serviceName, authzContext); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.