K8s/SecureValues: Wire InlineSecureValueSupport to apistore (#109449)
* inline wire * extra fields * add variable * wire
This commit is contained in:
@@ -42,7 +42,7 @@ func (s *DashboardStorage) NewStore(dash utils.ResourceInfo, scheme *runtime.Sch
|
||||
return nil, err
|
||||
}
|
||||
client := legacy.NewDirectResourceClient(server) // same context
|
||||
optsGetter := apistore.NewRESTOptionsGetterForClient(client,
|
||||
optsGetter := apistore.NewRESTOptionsGetterForClient(client, nil,
|
||||
defaultOpts.StorageConfig.Config, nil,
|
||||
)
|
||||
optsGetter.RegisterOptions(dash.GroupResource(), apistore.StorageOptions{
|
||||
|
||||
@@ -333,7 +333,7 @@ func NewLocalStore(resourceInfo utils.ResourceInfo, scheme *runtime.Scheme, defa
|
||||
}
|
||||
|
||||
client := resource.NewLocalResourceClient(server)
|
||||
optsGetter := apistore.NewRESTOptionsGetterForClient(client, defaultOpts.StorageConfig.Config, nil)
|
||||
optsGetter := apistore.NewRESTOptionsGetterForClient(client, nil, defaultOpts.StorageConfig.Config, nil)
|
||||
|
||||
store, err := grafanaregistry.NewRegistryStore(scheme, resourceInfo, optsGetter)
|
||||
return store, err
|
||||
|
||||
@@ -59,6 +59,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/safepath"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/secrets"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/usage"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@@ -107,7 +108,8 @@ type APIBuilder struct {
|
||||
legacyMigrator legacy.LegacyMigrator
|
||||
storageStatus dualwrite.Service
|
||||
unified resource.ResourceClient
|
||||
repositorySecrets secrets.RepositorySecrets
|
||||
decryptSvc secret.DecryptService
|
||||
repositorySecrets secrets.RepositorySecrets // << Will be removed when the decryptSvc usage is stable
|
||||
client client.ProvisioningV0alpha1Interface
|
||||
access authlib.AccessChecker
|
||||
mutators []controller.Mutator
|
||||
@@ -130,6 +132,7 @@ func NewAPIBuilder(
|
||||
legacyMigrator legacy.LegacyMigrator,
|
||||
storageStatus dualwrite.Service,
|
||||
usageStats usagestats.Service,
|
||||
decryptSvc secret.DecryptService,
|
||||
repositorySecrets secrets.RepositorySecrets,
|
||||
access authlib.AccessChecker,
|
||||
tracer tracing.Tracer,
|
||||
@@ -160,6 +163,7 @@ func NewAPIBuilder(
|
||||
legacyMigrator: legacyMigrator,
|
||||
storageStatus: storageStatus,
|
||||
unified: unified,
|
||||
decryptSvc: decryptSvc,
|
||||
repositorySecrets: repositorySecrets,
|
||||
access: access,
|
||||
jobHistoryConfig: jobHistoryConfig,
|
||||
@@ -232,6 +236,7 @@ func RegisterAPIService(
|
||||
legacyMigrator legacy.LegacyMigrator,
|
||||
storageStatus dualwrite.Service,
|
||||
usageStats usagestats.Service,
|
||||
decryptSvc secret.DecryptService,
|
||||
repositorySecrets secrets.RepositorySecrets,
|
||||
tracer tracing.Tracer,
|
||||
extraBuilders []ExtraBuilder,
|
||||
@@ -250,6 +255,7 @@ func RegisterAPIService(
|
||||
configProvider, ghFactory,
|
||||
legacyMigrator, storageStatus,
|
||||
usageStats,
|
||||
decryptSvc,
|
||||
repositorySecrets,
|
||||
access,
|
||||
tracer,
|
||||
|
||||
+160
-150
File diff suppressed because one or more lines are too long
@@ -75,7 +75,7 @@ func (o *GrafanaAggregatorOptions) ApplyTo(aggregatorConfig *aggregatorapiserver
|
||||
return err
|
||||
}
|
||||
// override the RESTOptionsGetter to use the in memory storage options
|
||||
restOptionsGetter, err := apistore.NewRESTOptionsGetterMemory(etcdOptions.StorageConfig)
|
||||
restOptionsGetter, err := apistore.NewRESTOptionsGetterMemory(etcdOptions.StorageConfig, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
secret "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/apistore"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
@@ -63,6 +64,9 @@ type StorageOptions struct {
|
||||
// value, it is considered large and gets partially stored in blob storage.
|
||||
BlobThresholdBytes int
|
||||
|
||||
// Support writing secrets inline
|
||||
InlineSecrets secret.InlineSecureValueSupport
|
||||
|
||||
// {resource}.{group} = 1|2|3|4
|
||||
UnifiedStorageConfig map[string]setting.UnifiedStorageConfig
|
||||
|
||||
@@ -164,7 +168,7 @@ func (o *StorageOptions) ApplyTo(serverConfig *genericapiserver.RecommendedConfi
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
getter := apistore.NewRESTOptionsGetterForClient(unified, etcdOptions.StorageConfig, o.ConfigProvider)
|
||||
getter := apistore.NewRESTOptionsGetterForClient(unified, o.InlineSecrets, etcdOptions.StorageConfig, o.ConfigProvider)
|
||||
serverConfig.RESTOptionsGetter = getter
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/datasource"
|
||||
secret "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/aggregatorrunner"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/appinstaller"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/auth/authenticator"
|
||||
@@ -105,6 +106,7 @@ type service struct {
|
||||
contextProvider datasource.PluginContextWrapper
|
||||
pluginStore pluginstore.Store
|
||||
unified resource.ResourceClient
|
||||
secrets secret.InlineSecureValueSupport
|
||||
restConfigProvider RestConfigProvider
|
||||
|
||||
buildHandlerChainFuncFromBuilders builder.BuildHandlerChainFuncFromBuilders
|
||||
@@ -128,6 +130,7 @@ func ProvideService(
|
||||
pluginStore pluginstore.Store,
|
||||
storageStatus dualwrite.Service,
|
||||
unified resource.ResourceClient,
|
||||
secrets secret.InlineSecureValueSupport,
|
||||
restConfigProvider RestConfigProvider,
|
||||
buildHandlerChainFuncFromBuilders builder.BuildHandlerChainFuncFromBuilders,
|
||||
eventualRestConfigProvider *eventualRestConfigProvider,
|
||||
@@ -159,6 +162,7 @@ func ProvideService(
|
||||
serverLockService: serverLockService,
|
||||
storageStatus: storageStatus,
|
||||
unified: unified,
|
||||
secrets: secrets,
|
||||
restConfigProvider: restConfigProvider,
|
||||
buildHandlerChainFuncFromBuilders: buildHandlerChainFuncFromBuilders,
|
||||
aggregatorRunner: aggregatorRunner,
|
||||
@@ -337,7 +341,7 @@ func (s *service) start(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
getter := apistore.NewRESTOptionsGetterForClient(s.unified, o.RecommendedOptions.Etcd.StorageConfig, s.restConfigProvider)
|
||||
getter := apistore.NewRESTOptionsGetterForClient(s.unified, s.secrets, o.RecommendedOptions.Etcd.StorageConfig, s.restConfigProvider)
|
||||
optsregister = getter.RegisterOptions
|
||||
serverConfig.RESTOptionsGetter = getter
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
flowcontrolrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
secret "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
)
|
||||
|
||||
@@ -28,6 +29,7 @@ type StorageOptionsRegister func(gr schema.GroupResource, opts StorageOptions)
|
||||
|
||||
type RESTOptionsGetter struct {
|
||||
client resource.ResourceClient
|
||||
secrets secret.InlineSecureValueSupport
|
||||
original storagebackend.Config
|
||||
configProvider RestConfigProvider
|
||||
|
||||
@@ -35,16 +37,22 @@ type RESTOptionsGetter struct {
|
||||
options map[string]StorageOptions
|
||||
}
|
||||
|
||||
func NewRESTOptionsGetterForClient(client resource.ResourceClient, original storagebackend.Config, configProvider RestConfigProvider) *RESTOptionsGetter {
|
||||
func NewRESTOptionsGetterForClient(
|
||||
client resource.ResourceClient,
|
||||
secrets secret.InlineSecureValueSupport,
|
||||
original storagebackend.Config,
|
||||
configProvider RestConfigProvider,
|
||||
) *RESTOptionsGetter {
|
||||
return &RESTOptionsGetter{
|
||||
client: client,
|
||||
secrets: secrets,
|
||||
original: original,
|
||||
options: make(map[string]StorageOptions),
|
||||
configProvider: configProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config) (*RESTOptionsGetter, error) {
|
||||
func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config, secrets secret.InlineSecureValueSupport) (*RESTOptionsGetter, error) {
|
||||
backend, err := resource.NewCDKBackend(context.Background(), resource.CDKBackendOptions{
|
||||
Bucket: memblob.OpenBucket(&memblob.Options{}),
|
||||
})
|
||||
@@ -59,6 +67,7 @@ func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config) (*R
|
||||
}
|
||||
return NewRESTOptionsGetterForClient(
|
||||
resource.NewLocalResourceClient(server),
|
||||
secrets,
|
||||
originalStorageConfig,
|
||||
nil,
|
||||
), nil
|
||||
@@ -67,7 +76,7 @@ func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config) (*R
|
||||
// Optionally, this constructor allows specifying directories
|
||||
// for resources that are required to be read/watched on startup and there
|
||||
// won't be any write operations that initially bootstrap their directories
|
||||
func NewRESTOptionsGetterForFile(path string,
|
||||
func NewRESTOptionsGetterForFileXX(path string,
|
||||
originalStorageConfig storagebackend.Config,
|
||||
features map[string]any) (*RESTOptionsGetter, error) {
|
||||
if path == "" {
|
||||
@@ -95,6 +104,7 @@ func NewRESTOptionsGetterForFile(path string,
|
||||
}
|
||||
return NewRESTOptionsGetterForClient(
|
||||
resource.NewLocalResourceClient(server),
|
||||
nil, // secrets
|
||||
originalStorageConfig,
|
||||
nil,
|
||||
), nil
|
||||
@@ -137,8 +147,10 @@ func (r *RESTOptionsGetter) GetRESTOptions(resource schema.GroupResource, _ runt
|
||||
trigger storage.IndexerFuncs,
|
||||
indexers *cache.Indexers,
|
||||
) (storage.Interface, factory.DestroyFunc, error) {
|
||||
opts := r.options[resource.String()]
|
||||
opts.SecureValues = r.secrets
|
||||
return NewStorage(config, r.client, keyFunc, nil, newFunc, newListFunc, getAttrsFunc,
|
||||
trigger, indexers, r.configProvider, r.options[resource.String()])
|
||||
trigger, indexers, r.configProvider, opts)
|
||||
},
|
||||
DeleteCollectionWorkers: 0,
|
||||
EnableGarbageCollection: false,
|
||||
|
||||
@@ -32,9 +32,9 @@ import (
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
authtypes "github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
|
||||
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
)
|
||||
@@ -61,6 +61,9 @@ type StorageOptions struct {
|
||||
// Add internalID label when missing
|
||||
RequireDeprecatedInternalID bool
|
||||
|
||||
// Process inline secure values
|
||||
SecureValues secrets.InlineSecureValueSupport
|
||||
|
||||
// Temporary fix to support adding default permissions AfterCreate
|
||||
Permissions DefaultPermissionSetter
|
||||
}
|
||||
|
||||
@@ -6,24 +6,23 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"gocloud.dev/blob/fileblob"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
otgrpc "github.com/opentracing-contrib/go-grpc"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"gocloud.dev/blob/fileblob"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/dskit/flagext"
|
||||
"github.com/grafana/dskit/grpcclient"
|
||||
"github.com/grafana/dskit/middleware"
|
||||
"github.com/grafana/dskit/services"
|
||||
|
||||
infraDB "github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/options"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -36,13 +35,14 @@ import (
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Cfg *setting.Cfg
|
||||
Features featuremgmt.FeatureToggles
|
||||
DB infraDB.DB
|
||||
Tracer tracing.Tracer
|
||||
Reg prometheus.Registerer
|
||||
Authzc types.AccessClient
|
||||
Docs resource.DocumentBuilderSupplier
|
||||
Cfg *setting.Cfg
|
||||
Features featuremgmt.FeatureToggles
|
||||
DB infraDB.DB
|
||||
Tracer tracing.Tracer
|
||||
Reg prometheus.Registerer
|
||||
Authzc types.AccessClient
|
||||
Docs resource.DocumentBuilderSupplier
|
||||
SecureValues secrets.InlineSecureValueSupport
|
||||
}
|
||||
|
||||
type clientMetrics struct {
|
||||
@@ -64,7 +64,7 @@ func ProvideUnifiedStorageClient(opts *Options,
|
||||
SearchServerAddress: apiserverCfg.Key("search_server_address").MustString(""),
|
||||
BlobStoreURL: apiserverCfg.Key("blob_url").MustString(""),
|
||||
BlobThresholdBytes: apiserverCfg.Key("blob_threshold_bytes").MustInt(options.BlobThresholdDefault),
|
||||
}, opts.Cfg, opts.Features, opts.DB, opts.Tracer, opts.Reg, opts.Authzc, opts.Docs, storageMetrics, indexMetrics)
|
||||
}, opts.Cfg, opts.Features, opts.DB, opts.Tracer, opts.Reg, opts.Authzc, opts.Docs, storageMetrics, indexMetrics, opts.SecureValues)
|
||||
if err == nil {
|
||||
// Used to get the folder stats
|
||||
client = federated.NewFederatedClient(
|
||||
@@ -86,6 +86,7 @@ func newClient(opts options.StorageOptions,
|
||||
docs resource.DocumentBuilderSupplier,
|
||||
storageMetrics *resource.StorageMetrics,
|
||||
indexMetrics *resource.BleveIndexMetrics,
|
||||
secure secrets.InlineSecureValueSupport,
|
||||
) (resource.ResourceClient, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -168,6 +169,7 @@ func newClient(opts options.StorageOptions,
|
||||
StorageMetrics: storageMetrics,
|
||||
IndexMetrics: indexMetrics,
|
||||
Features: features,
|
||||
SecureValues: secure,
|
||||
}
|
||||
|
||||
if cfg.QOSEnabled {
|
||||
|
||||
@@ -6,6 +6,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/options"
|
||||
@@ -13,9 +16,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func TestUnifiedStorageClient(t *testing.T) {
|
||||
@@ -45,6 +45,7 @@ func TestUnifiedStorageClient(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -78,6 +79,7 @@ func TestUnifiedStorageClient(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/dskit/backoff"
|
||||
"github.com/grafana/dskit/ring"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
"github.com/grafana/grafana/pkg/util/scheduler"
|
||||
)
|
||||
@@ -208,6 +208,9 @@ type ResourceServerOptions struct {
|
||||
// Link RBAC
|
||||
AccessClient claims.AccessClient
|
||||
|
||||
// Manage secure values
|
||||
SecureValues secrets.InlineSecureValueSupport
|
||||
|
||||
// Callbacks for startup and shutdown
|
||||
Lifecycle LifecycleHooks
|
||||
|
||||
@@ -297,6 +300,7 @@ func NewResourceServer(opts ResourceServerOptions) (ResourceServer, error) {
|
||||
blob: blobstore,
|
||||
diagnostics: opts.Diagnostics,
|
||||
access: opts.AccessClient,
|
||||
secure: opts.SecureValues,
|
||||
writeHooks: opts.WriteHooks,
|
||||
lifecycle: opts.Lifecycle,
|
||||
now: opts.Now,
|
||||
@@ -333,6 +337,7 @@ type server struct {
|
||||
log *slog.Logger
|
||||
backend StorageBackend
|
||||
blob BlobSupport
|
||||
secure secrets.InlineSecureValueSupport
|
||||
search *searchSupport
|
||||
diagnostics resourcepb.DiagnosticsServer
|
||||
access claims.AccessClient
|
||||
@@ -444,16 +449,6 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *resour
|
||||
return nil, NewBadRequestError("can not save annotation: " + utils.AnnoKeyGrantPermissions)
|
||||
}
|
||||
|
||||
// Verify that this resource can reference secure values
|
||||
secure, err := obj.GetSecureValues()
|
||||
if err != nil {
|
||||
return nil, AsErrorResult(err)
|
||||
}
|
||||
if len(secure) > 0 {
|
||||
// See: https://github.com/grafana/grafana/pull/107803
|
||||
return nil, NewBadRequestError("Saving secure values is not yet supported")
|
||||
}
|
||||
|
||||
event := &WriteEvent{
|
||||
Value: value,
|
||||
Key: key,
|
||||
@@ -477,6 +472,20 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *resour
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that this resource can reference secure values
|
||||
secure, err := obj.GetSecureValues()
|
||||
if err != nil {
|
||||
return nil, AsErrorResult(err)
|
||||
}
|
||||
if len(secure) > 0 {
|
||||
if s.secure == nil {
|
||||
return nil, NewBadRequestError("secure storage not configured")
|
||||
}
|
||||
|
||||
// See: https://github.com/grafana/grafana/pull/107803
|
||||
return nil, NewBadRequestError("Saving secure values is not yet supported")
|
||||
}
|
||||
|
||||
if key.Namespace != obj.GetNamespace() {
|
||||
return nil, NewBadRequestError("key/namespace do not match")
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/dskit/ring"
|
||||
"github.com/grafana/dskit/services"
|
||||
|
||||
infraDB "github.com/grafana/grafana/pkg/infra/db"
|
||||
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -38,6 +38,7 @@ type ServerOptions struct {
|
||||
IndexMetrics *resource.BleveIndexMetrics
|
||||
Features featuremgmt.FeatureToggles
|
||||
QOSQueue QOSEnqueueDequeuer
|
||||
SecureValues secrets.InlineSecureValueSupport
|
||||
Ring *ring.Ring
|
||||
RingLifecycler *ring.BasicLifecycler
|
||||
}
|
||||
@@ -52,7 +53,8 @@ func NewResourceServer(
|
||||
Blob: resource.BlobConfig{
|
||||
URL: apiserverCfg.Key("blob_url").MustString(""),
|
||||
},
|
||||
Reg: opts.Reg,
|
||||
Reg: opts.Reg,
|
||||
SecureValues: opts.SecureValues,
|
||||
}
|
||||
if opts.AccessClient != nil {
|
||||
serverOptions.AccessClient = resource.NewAuthzLimitedClient(opts.AccessClient, resource.AuthzOptions{Tracer: opts.Tracer, Registry: opts.Reg})
|
||||
|
||||
Reference in New Issue
Block a user