feat(handlers/host_catalogs): Support plugin host catalog worker filter

This commit is contained in:
Hugo committed 2024-09-30 21:24:18 +01:00
1 parent 7449fd6f2a
commit b8046a3ef3
12 files changed
+368 -174

No files matched your search

@@ -72,15 +72,22 @@ var (
),
},
}
validateWorkerFilterFn = validateWorkerFilterUnsupported
workerFilterToProto = false
)
func validateWorkerFilterUnsupported(_ string) error {
return fmt.Errorf("Worker filter on host catalogs is an Enterprise-only feature")
}
const domain = "host"
func init() {
var err error
if staticMaskManager, err = handlers.NewMaskManager(
context.Background(),
handlers.MaskDestination{&store.HostCatalog{}},
handlers.MaskDestination{&store.HostCatalog{}, &store.UnimplementedCatalogFields{}},
handlers.MaskSource{&pb.HostCatalog{}},
); err != nil {
panic(err)
@@ -871,6 +878,11 @@ func toProto(ctx context.Context, in host.Catalog, opt ...handlers.Option) (*pb.
if outputFields.Has(globals.SecretsHmacField) {
out.SecretsHmac = base58.Encode(h.GetSecretsHmac())
}
if outputFields.Has(globals.WorkerFilterField) && h.GetWorkerFilter() != "" {
if workerFilterToProto {
out.WorkerFilter = wrapperspb.String(h.GetWorkerFilter())
}
}
if outputFields.Has(globals.AttributesField) {
attrs := &structpb.Struct{}
err := proto.Unmarshal(h.Attributes, attrs)
@@ -918,6 +930,9 @@ func toStoragePluginCatalog(ctx context.Context, projectId, plgId string, item *
if secrets := item.GetSecrets(); secrets != nil {
opts = append(opts, hostplugin.WithSecrets(secrets))
}
if workerFilter := item.GetWorkerFilter(); workerFilter != nil {
opts = append(opts, hostplugin.WithWorkerFilter(workerFilter.GetValue()))
}
hc, err := hostplugin.NewHostCatalog(ctx, projectId, plgId, opts...)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("Unable to build host set for creation"))
@@ -959,6 +974,12 @@ func validateCreateRequest(req *pbs.CreateHostCatalogRequest) error {
badFields[globals.PluginIdField] = "Can't set the plugin name field along with this field."
badFields[globals.PluginNameField] = "Can't set the plugin id field along with this field."
}
if req.GetItem().GetWorkerFilter() != nil {
err := validateWorkerFilterFn(req.GetItem().GetWorkerFilter().GetValue())
if err != nil {
badFields[globals.WorkerFilterField] = err.Error()
}
}
default:
badFields[globals.TypeField] = fmt.Sprintf("This is a required field and must be either %q or %q.", static.Subtype.String(), hostplugin.Subtype.String())
}
@@ -987,6 +1008,12 @@ func validateUpdateRequest(req *pbs.UpdateHostCatalogRequest) error {
if req.GetItem().GetPlugin() != nil {
badFields[globals.PluginField] = "This is a read only field."
}
if req.GetItem().GetWorkerFilter() != nil {
err := validateWorkerFilterFn(req.GetItem().GetWorkerFilter().GetValue())
if err != nil {
badFields[globals.WorkerFilterField] = err.Error()
}
}
}
return badFields
}, globals.StaticHostCatalogPrefix, globals.PluginHostCatalogPrefix, globals.PluginHostCatalogPreviousPrefix)
@@ -1,7 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package host_catalogs_test
package host_catalogs
import (
"context"
@@ -18,7 +18,6 @@ import (
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_catalogs"
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
@@ -187,7 +186,7 @@ func TestGet_Static(t *testing.T) {
req := proto.Clone(toMerge).(*pbs.GetHostCatalogRequest)
proto.Merge(req, tc.req)
s, err := host_catalogs.NewService(ctx, staticRepoFn, pluginHostRepoFn, pluginRepoFn, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, staticRepoFn, pluginHostRepoFn, pluginRepoFn, iamRepoFn, catalogServiceFn, 1000)
require.NoError(err, "Couldn't create a new host catalog service.")
got, gErr := s.GetHostCatalog(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), req)
@@ -296,7 +295,7 @@ func TestGet_Plugin(t *testing.T) {
req := proto.Clone(toMerge).(*pbs.GetHostCatalogRequest)
proto.Merge(req, tc.req)
s, err := host_catalogs.NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(err, "Couldn't create a new host catalog service.")
got, gErr := s.GetHostCatalog(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), req)
@@ -483,7 +482,7 @@ func TestList(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
s, err := host_catalogs.NewService(ctx, repoFn, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, repoFn, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(err, "Couldn't create new auth_method service.")
// Test with non-anon user
@@ -578,7 +577,7 @@ func TestListPagination(t *testing.T) {
gr := iam.TestRole(t, conn, "global")
_ = iam.TestUserRole(t, conn, gr.GetPublicId(), at.GetIamUserId())
_ = iam.TestRoleGrant(t, conn, gr.GetPublicId(), "ids=*;type=*;actions=*")
s, err := host_catalogs.NewService(ctx, staticRepoFn, pluginHostRepoFn, pluginRepoFn, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, staticRepoFn, pluginHostRepoFn, pluginRepoFn, iamRepoFn, catalogServiceFn, 1000)
require.NoError(t, err)
var allCatalogs []*pb.HostCatalog
@@ -937,7 +936,7 @@ func TestDelete_Static(t *testing.T) {
}
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
s, err := host_catalogs.NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(t, err, "Couldn't create a new host catalog service.")
cases := []struct {
@@ -1012,7 +1011,7 @@ func TestDelete_Plugin(t *testing.T) {
plg := plugin.TestPlugin(t, conn, "test")
hc := hostplugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
s, err := host_catalogs.NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(t, err, "Couldn't create a new host catalog service.")
cases := []struct {
@@ -1087,7 +1086,7 @@ func TestDelete_twice(t *testing.T) {
}
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
s, err := host_catalogs.NewService(testCtx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(testCtx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(err, "Couldn't create a new host catalog service.")
req := &pbs.DeleteHostCatalogRequest{
Id: hc.GetPublicId(),
@@ -1224,7 +1223,7 @@ func TestCreate_Static(t *testing.T) {
req := proto.Clone(toMerge).(*pbs.CreateHostCatalogRequest)
proto.Merge(req, tc.req)
s, err := host_catalogs.NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(err, "Failed to create a new host catalog service.")
got, gErr := s.CreateHostCatalog(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), req)
@@ -1267,7 +1266,6 @@ func TestCreate_Static(t *testing.T) {
}
func TestCreate_Plugin(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
@@ -1289,6 +1287,12 @@ func TestCreate_Plugin(t *testing.T) {
return host.NewCatalogRepository(ctx, rw, rw)
}
currentValidateWorkerFilterFn := validateWorkerFilterFn
validateWorkerFilterFn = validateWorkerFilterUnsupported
t.Cleanup(func() {
validateWorkerFilterFn = currentValidateWorkerFilterFn
})
name := "test"
plg := plugin.TestPlugin(t, conn, name)
pluginHostRepo := func() (*hostplugin.Repository, error) {
@@ -1406,6 +1410,17 @@ func TestCreate_Plugin(t *testing.T) {
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Unsupported worker filter field",
req: &pbs.CreateHostCatalogRequest{Item: &pb.HostCatalog{
ScopeId: proj.GetPublicId(),
Type: hostplugin.Subtype.String(),
PluginId: plg.GetPublicId(),
WorkerFilter: wrapperspb.String(`"dev" in "/tags/type"`),
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
@@ -1413,7 +1428,7 @@ func TestCreate_Plugin(t *testing.T) {
req := proto.Clone(toMerge).(*pbs.CreateHostCatalogRequest)
proto.Merge(req, tc.req)
s, err := host_catalogs.NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
s, err := NewService(ctx, repo, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(err, "Failed to create a new host catalog service.")
got, gErr := s.CreateHostCatalog(auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId()), req)
@@ -1482,7 +1497,7 @@ func TestUpdate_Static(t *testing.T) {
catalogServiceFn := func() (*host.CatalogRepository, error) {
return host.NewCatalogRepository(ctx, rw, rw)
}
tested, err := host_catalogs.NewService(ctx, repoFn, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
tested, err := NewService(ctx, repoFn, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(t, err, "Failed to create a new host catalog service.")
hc, err := static.NewHostCatalog(ctx, proj.GetPublicId(), static.WithName("default"), static.WithDescription("default"))
@@ -1840,7 +1855,6 @@ func TestUpdate_Static(t *testing.T) {
}
func TestUpdate_Plugin(t *testing.T) {
t.Parallel()
testCtx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
@@ -1873,7 +1887,14 @@ func TestUpdate_Plugin(t *testing.T) {
catalogServiceFn := func() (*host.CatalogRepository, error) {
return host.NewCatalogRepository(testCtx, rw, rw)
}
tested, err := host_catalogs.NewService(testCtx, repoFn, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
currentValidateWorkerFilterFn := validateWorkerFilterFn
validateWorkerFilterFn = validateWorkerFilterUnsupported
t.Cleanup(func() {
validateWorkerFilterFn = currentValidateWorkerFilterFn
})
tested, err := NewService(testCtx, repoFn, pluginHostRepo, pluginRepo, iamRepoFn, catalogServiceFn, 1000)
require.NoError(t, err, "Failed to create a new host catalog service.")
ctx := auth.DisabledAuthTestContext(iamRepoFn, proj.GetPublicId())
@@ -1936,6 +1957,12 @@ func TestUpdate_Plugin(t *testing.T) {
}
}
updateWorkerFilter := func(i *wrappers.StringValue) updateFn {
return func(c *pb.HostCatalog) {
c.WorkerFilter = i
}
}
cases := []struct {
name string
masks []string
@@ -2058,6 +2085,15 @@ func TestUpdate_Plugin(t *testing.T) {
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Add worker filter",
masks: []string{"worker_filter"},
changes: []updateFn{
clearReadOnlyFields(),
updateWorkerFilter(wrapperspb.String(`"dev" in "/tags/type"`)),
},
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Unset Name",
masks: []string{"name"},