Chromium Code Reviews| Index: appengine/gaeconfig/default.go |
| diff --git a/appengine/gaeconfig/default.go b/appengine/gaeconfig/default.go |
| index 18cd7db2fd97559735b62e9b06c743cae9f10e8a..869b558c5c23b682103e7bf8797f1b67dbfe69f3 100644 |
| --- a/appengine/gaeconfig/default.go |
| +++ b/appengine/gaeconfig/default.go |
| @@ -7,23 +7,23 @@ package gaeconfig |
| import ( |
| "errors" |
| "fmt" |
| - "net/http" |
| "os" |
| "path/filepath" |
| - "sync" |
| "time" |
| - "golang.org/x/net/context" |
| + "github.com/luci/luci-go/common/config/impl/filesystem" |
| + "github.com/luci/luci-go/server/config" |
| + "github.com/luci/luci-go/server/config/caching" |
| + "github.com/luci/luci-go/server/config/erroring" |
| + "github.com/luci/luci-go/server/config/testconfig" |
| + "github.com/luci/luci-go/server/config/textproto" |
| "github.com/luci/gae/service/info" |
| - "github.com/luci/luci-go/common/config" |
| - "github.com/luci/luci-go/common/config/impl/erroring" |
| - "github.com/luci/luci-go/common/config/impl/filesystem" |
| - "github.com/luci/luci-go/common/config/impl/remote" |
| - "github.com/luci/luci-go/server/auth" |
| + |
| + "golang.org/x/net/context" |
| ) |
| -// ErrNotConfigured is returned by methods of config.Interface object returned |
| +// ErrNotConfigured is returned by methods of config.Backend object returned |
| // by New if config service URL is not set. Usually happens for new apps. |
| var ErrNotConfigured = errors.New("config service URL is not set in settings") |
| @@ -31,21 +31,7 @@ var ErrNotConfigured = errors.New("config service URL is not set in settings") |
| // local dev appserver model. See New for details. |
| const devCfgDir = "devcfg" |
| -// implCache is used to avoid reallocating config.Interface implementation |
| -// during each request. |
| -// |
| -// config.Interface instances don't actually depend on the context and thus we |
| -// can share them between requests. |
| -// |
| -// Cache key is the current value of Settings struct. We don't bother to clean |
| -// up old entries, since in most cases there'll be none (the settings are mostly |
| -// static). |
| -var implCache struct { |
| - lock sync.RWMutex |
| - cache map[Settings]config.Interface |
| -} |
| - |
| -// New constructs default luci-config client. |
| +// Use installs the default luci-config client. |
| // |
| // The client is configured to use luci-config URL specified in the settings, |
| // using GAE app service account for authentication. |
| @@ -64,58 +50,61 @@ var implCache struct { |
| // |
| // Panics if it can't load the settings (should not happen since they are in |
| // the local memory cache usually). |
| -func New(c context.Context) config.Interface { |
| - settings, err := FetchCachedSettings(c) |
| - if err != nil { |
| - panic(err) |
| - } |
| +func Use(c context.Context) context.Context { return useImpl(c, nil) } |
|
iannucci
2017/01/07 21:05:26
if you do the package renaming, this should move o
dnj
2017/01/10 03:30:07
I'll move to luci_config/appengine/gaeconfig.
|
| - if settings.ConfigServiceURL == "" { |
| - if info.IsDevAppServer(c) { |
| - return devServerConfig() |
| - } |
| - return erroring.New(ErrNotConfigured) |
| - } |
| - |
| - return configImplForSettings(settings) |
| +func useImpl(c context.Context, backend config.Backend) context.Context { |
| + return installConfigBackend(c, mustFetchCachedSettings(c), backend) |
| } |
| -// configImplForSettings returns config.Interface based on given settings. |
| -// |
| -// Split out from New to enforce that returned config.Interface doesn't depend |
| -// on the context (since this function doesn't accept a context). |
| -func configImplForSettings(settings Settings) config.Interface { |
| - implCache.lock.RLock() |
| - impl, ok := implCache.cache[settings] |
| - implCache.lock.RUnlock() |
| - if ok { |
| - return impl |
| +func installConfigBackend(c context.Context, s *Settings, backend config.Backend) context.Context { |
| + if backend == nil { |
| + // Non-testing, build a Backend. |
| + backend = getPrimaryBackend(c, s) |
| } |
| - implCache.lock.Lock() |
| - defer implCache.lock.Unlock() |
| + // Install a FormatRegistry. Register common config service protobufs with it. |
| + c = withFormatRegistry(c, defaultFormatterRegistry()) |
| - if impl, ok := implCache.cache[settings]; ok { |
| - return impl |
| + backend = &config.FormatBackend{ |
| + Backend: backend, |
| + GetRegistry: GetFormatterRegistry, |
| } |
| - impl = remote.New(settings.ConfigServiceURL+"/_ah/api/config/v1/", authenticatedClient) |
| - if settings.CacheExpirationSec != 0 { |
| - impl = WrapWithCache(impl, time.Duration(settings.CacheExpirationSec)*time.Second) |
| + // Apply caching configuration. |
| + exp := time.Duration(s.CacheExpirationSec) * time.Second |
| + if exp > 0 { |
| + // Add a ProcCache, backed by memcache. |
| + backend = caching.ProcCache(backend, exp) |
| + backend = memcacheBackend(backend, exp) |
| } |
| - if implCache.cache == nil { |
| - implCache.cache = make(map[Settings]config.Interface, 1) |
| + c = config.WithBackend(c, backend) |
| + return c |
| +} |
| + |
| +func getPrimaryBackend(c context.Context, settings *Settings) (backend config.Backend) { |
| + // Identify our config service Backend (in testing, it will be supplied). |
| + if settings.ConfigServiceURL == "" { |
| + if info.IsDevAppServer(c) { |
| + return devServerBackend() |
| + } |
| + return erroring.New(ErrNotConfigured) |
| } |
| - implCache.cache[settings] = impl |
| + return &config.ClientBackend{&config.RemoteClientProvider{ |
| + BaseURL: settings.ConfigServiceURL, |
| + }} |
| +} |
| - return impl |
| +func defaultFormatterRegistry() *config.FormatterRegistry { |
| + var fr config.FormatterRegistry |
| + textproto.RegisterFormatter(&fr) |
| + return &fr |
| } |
| // devServerConfig returns config.Interface to use on a devserver. |
| // |
| // See New for details. |
| -func devServerConfig() config.Interface { |
| +func devServerBackend() config.Backend { |
| pwd := os.Getenv("PWD") // os.Getwd works funny with symlinks, use PWD |
| candidates := []string{ |
| filepath.Join(pwd, devCfgDir), |
| @@ -127,20 +116,22 @@ func devServerConfig() config.Interface { |
| if err != nil { |
| return erroring.New(err) |
| } |
| - return fs |
| + return &config.ClientBackend{&testconfig.LocalClientProvider{ |
| + Base: fs, |
| + }} |
| } |
| } |
| return erroring.New(fmt.Errorf("luci-config: could not find local configs in any of %s", candidates)) |
| } |
| -// authenticatedClient returns http.Client to use for making authenticated |
| -// request to the config service. |
| -// |
| -// The returned client uses GAE app's service account for authentication. |
| -func authenticatedClient(ctx context.Context) (*http.Client, error) { |
| - t, err := auth.GetRPCTransport(ctx, auth.AsSelf) |
| - if err != nil { |
| - return nil, err |
| - } |
| - return &http.Client{Transport: t}, nil |
| +var formatRegistryKey = "github.com/luci/luci-go/appengine/gaeconfig:formatRegistry" |
| + |
| +func withFormatRegistry(c context.Context, fr *config.FormatterRegistry) context.Context { |
| + return context.WithValue(c, &formatRegistryKey, fr) |
| +} |
| + |
| +// GetFormatterRegistry is used to retrieve the config service format registry |
| +// from the supplied Context. |
| +func GetFormatterRegistry(c context.Context) *config.FormatterRegistry { |
| + return c.Value(&formatRegistryKey).(*config.FormatterRegistry) |
| } |