feat(storage): Add support for Storage Bucket API
This commit is contained in:
1 parent
feb87e717e
commit
8ea61054cd
27 files changed
+3380
-142
No files matched your search
@@ -15,22 +15,24 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/plugin"
|
||||
"github.com/hashicorp/boundary/internal/server"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
pluginstorage "github.com/hashicorp/boundary/internal/storage/plugin"
|
||||
)
|
||||
|
||||
type (
|
||||
AuthTokenRepoFactory = oidc.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFactory = func() (*vault.Repository, error)
|
||||
StaticCredentialRepoFactory = func() (*credstatic.Repository, error)
|
||||
IamRepoFactory = iam.IamRepoFactory
|
||||
OidcAuthRepoFactory = oidc.OidcRepoFactory
|
||||
LdapAuthRepoFactory = ldap.RepoFactory
|
||||
PasswordAuthRepoFactory func() (*password.Repository, error)
|
||||
ServersRepoFactory func() (*server.Repository, error)
|
||||
StaticRepoFactory func() (*static.Repository, error)
|
||||
PluginHostRepoFactory func() (*pluginhost.Repository, error)
|
||||
HostPluginRepoFactory func() (*plugin.Repository, error)
|
||||
ConnectionRepoFactory func() (*session.ConnectionRepository, error)
|
||||
WorkerAuthRepoStorageFactory func() (*server.WorkerAuthRepositoryStorage, error)
|
||||
AuthTokenRepoFactory = oidc.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFactory = func() (*vault.Repository, error)
|
||||
StaticCredentialRepoFactory = func() (*credstatic.Repository, error)
|
||||
IamRepoFactory = iam.IamRepoFactory
|
||||
OidcAuthRepoFactory = oidc.OidcRepoFactory
|
||||
LdapAuthRepoFactory = ldap.RepoFactory
|
||||
PasswordAuthRepoFactory func() (*password.Repository, error)
|
||||
ServersRepoFactory func() (*server.Repository, error)
|
||||
StaticRepoFactory func() (*static.Repository, error)
|
||||
PluginHostRepoFactory func() (*pluginhost.Repository, error)
|
||||
PluginRepoFactory func() (*plugin.Repository, error)
|
||||
ConnectionRepoFactory func() (*session.ConnectionRepository, error)
|
||||
WorkerAuthRepoStorageFactory func() (*server.WorkerAuthRepositoryStorage, error)
|
||||
PluginStorageBucketRepoFactory func() (*pluginstorage.Repository, error)
|
||||
)
|
||||
|
||||
// Downstreamers provides at least a minimum interface that must be met by a
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/server"
|
||||
serversjob "github.com/hashicorp/boundary/internal/server/job"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
pluginstorage "github.com/hashicorp/boundary/internal/storage/plugin"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
host_plugin_assets "github.com/hashicorp/boundary/plugins/host"
|
||||
@@ -118,21 +119,22 @@ type Controller struct {
|
||||
apiGrpcGatewayTicket string
|
||||
|
||||
// Repo factory methods
|
||||
AuthTokenRepoFn common.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFn common.VaultCredentialRepoFactory
|
||||
StaticCredentialRepoFn common.StaticCredentialRepoFactory
|
||||
IamRepoFn common.IamRepoFactory
|
||||
OidcRepoFn common.OidcAuthRepoFactory
|
||||
LdapRepoFn common.LdapAuthRepoFactory
|
||||
PasswordAuthRepoFn common.PasswordAuthRepoFactory
|
||||
ServersRepoFn common.ServersRepoFactory
|
||||
SessionRepoFn session.RepositoryFactory
|
||||
ConnectionRepoFn common.ConnectionRepoFactory
|
||||
StaticHostRepoFn common.StaticRepoFactory
|
||||
PluginHostRepoFn common.PluginHostRepoFactory
|
||||
HostPluginRepoFn common.HostPluginRepoFactory
|
||||
TargetRepoFn target.RepositoryFactory
|
||||
WorkerAuthRepoStorageFn common.WorkerAuthRepoStorageFactory
|
||||
AuthTokenRepoFn common.AuthTokenRepoFactory
|
||||
VaultCredentialRepoFn common.VaultCredentialRepoFactory
|
||||
StaticCredentialRepoFn common.StaticCredentialRepoFactory
|
||||
IamRepoFn common.IamRepoFactory
|
||||
OidcRepoFn common.OidcAuthRepoFactory
|
||||
LdapRepoFn common.LdapAuthRepoFactory
|
||||
PasswordAuthRepoFn common.PasswordAuthRepoFactory
|
||||
ServersRepoFn common.ServersRepoFactory
|
||||
SessionRepoFn session.RepositoryFactory
|
||||
ConnectionRepoFn common.ConnectionRepoFactory
|
||||
StaticHostRepoFn common.StaticRepoFactory
|
||||
PluginHostRepoFn common.PluginHostRepoFactory
|
||||
PluginStorageBucketRepoFn common.PluginStorageBucketRepoFactory
|
||||
PluginRepoFn common.PluginRepoFactory
|
||||
TargetRepoFn target.RepositoryFactory
|
||||
WorkerAuthRepoStorageFn common.WorkerAuthRepoStorageFactory
|
||||
|
||||
scheduler *scheduler.Scheduler
|
||||
|
||||
@@ -261,8 +263,7 @@ func New(ctx context.Context, conf *Config) (*Controller, error) {
|
||||
plugin.WithDescription("Provides an initial loopback storage and host plugin in Boundary"),
|
||||
plugin.WithPublicId(conf.DevLoopbackPluginId),
|
||||
}
|
||||
// TODO(storage): Register loopback as storage supported
|
||||
if _, err = conf.RegisterPlugin(ctx, "loopback", plg, []plugin.PluginType{plugin.PluginTypeHost}, opts...); err != nil {
|
||||
if _, err = conf.RegisterPlugin(ctx, "loopback", plg, []plugin.PluginType{plugin.PluginTypeHost, plugin.PluginTypeStorage}, opts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case base.EnabledPluginHostAzure:
|
||||
@@ -376,9 +377,12 @@ func New(ctx context.Context, conf *Config) (*Controller, error) {
|
||||
c.PluginHostRepoFn = func() (*pluginhost.Repository, error) {
|
||||
return pluginhost.NewRepository(dbase, dbase, c.kms, c.scheduler, c.conf.HostPlugins)
|
||||
}
|
||||
c.HostPluginRepoFn = func() (*plugin.Repository, error) {
|
||||
c.PluginRepoFn = func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(ctx, dbase, dbase, c.kms)
|
||||
}
|
||||
c.PluginStorageBucketRepoFn = func() (*pluginstorage.Repository, error) {
|
||||
return pluginstorage.NewRepository(ctx, dbase, dbase, c.kms)
|
||||
}
|
||||
c.AuthTokenRepoFn = func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(dbase, dbase, c.kms,
|
||||
authtoken.WithTokenTimeToLiveDuration(c.conf.RawConfig.Controller.AuthTokenTimeToLiveDuration),
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/roles"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/scopes"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/sessions"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/storage_buckets"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/users"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
@@ -133,7 +134,7 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error {
|
||||
currentServices := s.GetServiceInfo()
|
||||
|
||||
if _, ok := currentServices[services.HostCatalogService_ServiceDesc.ServiceName]; !ok {
|
||||
hcs, err := host_catalogs.NewService(c.StaticHostRepoFn, c.PluginHostRepoFn, c.HostPluginRepoFn, c.IamRepoFn)
|
||||
hcs, err := host_catalogs.NewService(c.StaticHostRepoFn, c.PluginHostRepoFn, c.PluginRepoFn, c.IamRepoFn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create host catalog handler service: %w", err)
|
||||
}
|
||||
@@ -188,6 +189,18 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error {
|
||||
}
|
||||
services.RegisterUserServiceServer(s, us)
|
||||
}
|
||||
if _, ok := currentServices[services.StorageBucketService_ServiceDesc.ServiceName]; !ok {
|
||||
sbs, err := storage_buckets.NewServiceFn(
|
||||
c.baseContext,
|
||||
c.PluginStorageBucketRepoFn,
|
||||
c.IamRepoFn,
|
||||
c.PluginRepoFn,
|
||||
c.ControllerExtension)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create storage bucket handler service: %w", err)
|
||||
}
|
||||
services.RegisterStorageBucketServiceServer(s, sbs)
|
||||
}
|
||||
if _, ok := currentServices[services.TargetService_ServiceDesc.ServiceName]; !ok {
|
||||
ts, err := targets.NewService(
|
||||
c.baseContext,
|
||||
@@ -332,6 +345,9 @@ func registerGrpcGatewayEndpoints(ctx context.Context, gwMux *runtime.ServeMux,
|
||||
if err := services.RegisterSessionRecordingServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil {
|
||||
return fmt.Errorf("failed to register session recording service handler: %w", err)
|
||||
}
|
||||
if err := services.RegisterStorageBucketServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil {
|
||||
return fmt.Errorf("failed to register storage bucket handler: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -132,6 +132,8 @@ func TestHandleImplementedPaths(t *testing.T) {
|
||||
"v1/scopes/someid",
|
||||
"v1/sessions",
|
||||
"v1/sessions/someid",
|
||||
"v1/storage-buckets",
|
||||
"v1/storage-buckets/someid",
|
||||
"v1/targets",
|
||||
"v1/targets/someid",
|
||||
"v1/users",
|
||||
@@ -148,6 +150,7 @@ func TestHandleImplementedPaths(t *testing.T) {
|
||||
"v1/hosts",
|
||||
"v1/roles",
|
||||
"v1/scopes",
|
||||
"v1/storage-buckets",
|
||||
"v1/targets",
|
||||
"v1/users",
|
||||
|
||||
@@ -190,6 +193,7 @@ func TestHandleImplementedPaths(t *testing.T) {
|
||||
"v1/hosts/someid",
|
||||
"v1/roles/someid",
|
||||
"v1/scopes/someid",
|
||||
"v1/storage-buckets/someid",
|
||||
"v1/targets/someid",
|
||||
"v1/users/someid",
|
||||
},
|
||||
@@ -203,6 +207,7 @@ func TestHandleImplementedPaths(t *testing.T) {
|
||||
"v1/hosts/someid",
|
||||
"v1/roles/someid",
|
||||
"v1/scopes/someid",
|
||||
"v1/storage-buckets/someid",
|
||||
"v1/targets/someid",
|
||||
"v1/users/someid",
|
||||
},
|
||||
|
||||
@@ -88,7 +88,7 @@ type Service struct {
|
||||
|
||||
staticRepoFn common.StaticRepoFactory
|
||||
pluginHostRepoFn common.PluginHostRepoFactory
|
||||
pluginRepoFn common.HostPluginRepoFactory
|
||||
pluginRepoFn common.PluginRepoFactory
|
||||
iamRepoFn common.IamRepoFactory
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ var _ pbs.HostCatalogServiceServer = (*Service)(nil)
|
||||
|
||||
// NewService returns a host catalog Service which handles host catalog related requests to boundary and uses the provided
|
||||
// repositories for storage and retrieval.
|
||||
func NewService(repoFn common.StaticRepoFactory, pluginHostRepoFn common.PluginHostRepoFactory, hostPluginRepoFn common.HostPluginRepoFactory, iamRepoFn common.IamRepoFactory) (Service, error) {
|
||||
func NewService(repoFn common.StaticRepoFactory, pluginHostRepoFn common.PluginHostRepoFactory, hostPluginRepoFn common.PluginRepoFactory, iamRepoFn common.IamRepoFactory) (Service, error) {
|
||||
const op = "host_catalogs.NewService"
|
||||
if repoFn == nil {
|
||||
return Service{}, errors.NewDeprecated(errors.InvalidParameter, op, "missing static repository")
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_catalogs"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/roles"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/sessions"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/storage_buckets"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/users"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
|
||||
@@ -67,22 +68,24 @@ var (
|
||||
|
||||
scopeCollectionTypeMapMap = map[string]map[resource.Type]action.ActionSet{
|
||||
scope.Global.String(): {
|
||||
resource.AuthMethod: authmethods.CollectionActions,
|
||||
resource.AuthToken: authtokens.CollectionActions,
|
||||
resource.Group: groups.CollectionActions,
|
||||
resource.Role: roles.CollectionActions,
|
||||
resource.Scope: CollectionActions,
|
||||
resource.User: users.CollectionActions,
|
||||
resource.Worker: workers.CollectionActions,
|
||||
resource.AuthMethod: authmethods.CollectionActions,
|
||||
resource.StorageBucket: storage_buckets.CollectionActions,
|
||||
resource.AuthToken: authtokens.CollectionActions,
|
||||
resource.Group: groups.CollectionActions,
|
||||
resource.Role: roles.CollectionActions,
|
||||
resource.Scope: CollectionActions,
|
||||
resource.User: users.CollectionActions,
|
||||
resource.Worker: workers.CollectionActions,
|
||||
},
|
||||
|
||||
scope.Org.String(): {
|
||||
resource.AuthMethod: authmethods.CollectionActions,
|
||||
resource.AuthToken: authtokens.CollectionActions,
|
||||
resource.Group: groups.CollectionActions,
|
||||
resource.Role: roles.CollectionActions,
|
||||
resource.Scope: CollectionActions,
|
||||
resource.User: users.CollectionActions,
|
||||
resource.AuthMethod: authmethods.CollectionActions,
|
||||
resource.StorageBucket: storage_buckets.CollectionActions,
|
||||
resource.AuthToken: authtokens.CollectionActions,
|
||||
resource.Group: groups.CollectionActions,
|
||||
resource.Role: roles.CollectionActions,
|
||||
resource.Scope: CollectionActions,
|
||||
resource.User: users.CollectionActions,
|
||||
},
|
||||
|
||||
scope.Project.String(): {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package storage_buckets
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/globals"
|
||||
"github.com/hashicorp/boundary/internal/types/action"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var (
|
||||
// IdActions contains the set of actions that can be performed on
|
||||
// individual resources
|
||||
IdActions = action.ActionSet{
|
||||
action.NoOp,
|
||||
action.Read,
|
||||
action.Update,
|
||||
action.Delete,
|
||||
}
|
||||
|
||||
// CollectionActions contains the set of actions that can be performed on
|
||||
// this collection
|
||||
CollectionActions = action.ActionSet{
|
||||
action.Create,
|
||||
action.List,
|
||||
}
|
||||
)
|
||||
|
||||
// NewServiceFn returns a storage bucket service which is not implemented in OSS
|
||||
var NewServiceFn = func(ctx context.Context,
|
||||
pluginStorageRepoFn common.PluginStorageBucketRepoFactory,
|
||||
iamRepoFn common.IamRepoFactory,
|
||||
pluginRepoFn common.PluginRepoFactory,
|
||||
controllerExt globals.ControllerExtension,
|
||||
) (pbs.StorageBucketServiceServer, error) {
|
||||
return Service{}, nil
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
pbs.UnsafeStorageBucketServiceServer
|
||||
}
|
||||
|
||||
var _ pbs.StorageBucketServiceServer = (*Service)(nil)
|
||||
|
||||
// ListStorageBuckets implements the interface pbs.StorageBucketServiceServer.
|
||||
func (s Service) ListStorageBuckets(ctx context.Context, req *pbs.ListStorageBucketsRequest) (*pbs.ListStorageBucketsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "storage buckets are an Enterprise-only feature")
|
||||
}
|
||||
|
||||
// GetStorageBucket implements the interface pbs.StorageBucketServiceServer.
|
||||
func (s Service) GetStorageBucket(ctx context.Context, req *pbs.GetStorageBucketRequest) (*pbs.GetStorageBucketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "storage buckets are an Enterprise-only feature")
|
||||
}
|
||||
|
||||
// CreateStorageBucket implements the interface pbs.StorageBucketServiceServer.
|
||||
func (s Service) CreateStorageBucket(ctx context.Context, req *pbs.CreateStorageBucketRequest) (*pbs.CreateStorageBucketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "storage buckets are an Enterprise-only feature")
|
||||
}
|
||||
|
||||
// UpdateStorageBucket implements the interface pbs.StorageBucketServiceServer.
|
||||
func (s Service) UpdateStorageBucket(ctx context.Context, req *pbs.UpdateStorageBucketRequest) (*pbs.UpdateStorageBucketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "storage buckets are an Enterprise-only feature")
|
||||
}
|
||||
|
||||
// DeleteStorageBucket implements the interface pbs.StorageBucketServiceServer.
|
||||
func (s Service) DeleteStorageBucket(ctx context.Context, req *pbs.DeleteStorageBucketRequest) (*pbs.DeleteStorageBucketResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "storage buckets are an Enterprise-only feature")
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package storage_buckets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestService(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
s := Service{}
|
||||
|
||||
gotCreate, err := s.CreateStorageBucket(ctx, &pbs.CreateStorageBucketRequest{})
|
||||
require.Nil(gotCreate)
|
||||
require.Error(err)
|
||||
gotStatus, ok := status.FromError(err)
|
||||
require.True(ok)
|
||||
assert.Equal(gotStatus.Code(), codes.Unimplemented)
|
||||
assert.Equal(gotStatus.Message(), "storage buckets are an Enterprise-only feature")
|
||||
|
||||
gotUpdate, err := s.UpdateStorageBucket(ctx, &pbs.UpdateStorageBucketRequest{})
|
||||
require.Nil(gotUpdate)
|
||||
require.Error(err)
|
||||
gotStatus, ok = status.FromError(err)
|
||||
require.True(ok)
|
||||
assert.Equal(gotStatus.Code(), codes.Unimplemented)
|
||||
assert.Equal(gotStatus.Message(), "storage buckets are an Enterprise-only feature")
|
||||
|
||||
gotGet, err := s.GetStorageBucket(ctx, &pbs.GetStorageBucketRequest{})
|
||||
require.Nil(gotGet)
|
||||
require.Error(err)
|
||||
gotStatus, ok = status.FromError(err)
|
||||
require.True(ok)
|
||||
assert.Equal(gotStatus.Code(), codes.Unimplemented)
|
||||
assert.Equal(gotStatus.Message(), "storage buckets are an Enterprise-only feature")
|
||||
|
||||
gotDelete, err := s.DeleteStorageBucket(ctx, &pbs.DeleteStorageBucketRequest{})
|
||||
require.Nil(gotDelete)
|
||||
require.Error(err)
|
||||
gotStatus, ok = status.FromError(err)
|
||||
require.True(ok)
|
||||
assert.Equal(gotStatus.Code(), codes.Unimplemented)
|
||||
assert.Equal(gotStatus.Message(), "storage buckets are an Enterprise-only feature")
|
||||
|
||||
got, err := s.ListStorageBuckets(ctx, &pbs.ListStorageBucketsRequest{})
|
||||
require.Nil(got)
|
||||
require.Error(err)
|
||||
gotStatus, ok = status.FromError(err)
|
||||
require.True(ok)
|
||||
assert.Equal(gotStatus.Code(), codes.Unimplemented)
|
||||
assert.Equal(gotStatus.Message(), "storage buckets are an Enterprise-only feature")
|
||||
}
|
||||
Reference in new issue
Block a user