| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package gaeconfig | 5 package gaeconfig |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "errors" | 8 "errors" |
| 9 "fmt" | 9 "fmt" |
| 10 "os" | 10 "os" |
| 11 "path/filepath" | 11 "path/filepath" |
| 12 "time" | 12 "time" |
| 13 | 13 |
| 14 "github.com/luci/luci-go/common/config/impl/filesystem" | 14 "github.com/luci/luci-go/common/config/impl/filesystem" |
| 15 "github.com/luci/luci-go/server/config" | 15 "github.com/luci/luci-go/server/config" |
| 16 "github.com/luci/luci-go/server/config/caching" | 16 "github.com/luci/luci-go/server/config/caching" |
| 17 "github.com/luci/luci-go/server/config/erroring" | 17 "github.com/luci/luci-go/server/config/erroring" |
| 18 "github.com/luci/luci-go/server/config/testconfig" | 18 "github.com/luci/luci-go/server/config/testconfig" |
| 19 "github.com/luci/luci-go/server/config/textproto" | 19 "github.com/luci/luci-go/server/config/textproto" |
| 20 "github.com/luci/luci-go/server/router" |
| 20 | 21 |
| 21 "github.com/luci/gae/service/info" | 22 "github.com/luci/gae/service/info" |
| 22 | 23 |
| 23 "golang.org/x/net/context" | 24 "golang.org/x/net/context" |
| 24 ) | 25 ) |
| 25 | 26 |
| 26 // ErrNotConfigured is returned by methods of config.Backend object returned | 27 // ErrNotConfigured is returned by methods of config.Backend object returned |
| 27 // by New if config service URL is not set. Usually happens for new apps. | 28 // by New if config service URL is not set. Usually happens for new apps. |
| 28 var ErrNotConfigured = errors.New("config service URL is not set in settings") | 29 var ErrNotConfigured = errors.New("config service URL is not set in settings") |
| 29 | 30 |
| 30 // devCfgDir is a name of the directory with config files when running in | 31 // devCfgDir is a name of the directory with config files when running in |
| 31 // local dev appserver model. See New for details. | 32 // local dev appserver model. See New for details. |
| 32 const devCfgDir = "devcfg" | 33 const devCfgDir = "devcfg" |
| 33 | 34 |
| 35 // InstallCacheCronHandler installs the configuration service datastore caching |
| 36 // cron handler. This must be installed, and an associated cron must be set up, |
| 37 // if datastore caching is enabled. |
| 38 // |
| 39 // The cron should be configured to hit the handler at: |
| 40 // /admin/config/cache/manager |
| 41 func InstallCacheCronHandler(r *router.Router, base router.MiddlewareChain) { |
| 42 installCacheCronHandlerImpl(r, base, nil) |
| 43 } |
| 44 |
| 45 // Install our cache cron handler into the supplied Router. |
| 46 // |
| 47 // bf is a generator function used to get the primary (service) Backend to build |
| 48 // on top of. If nil, the "production" (one used by Use) Backend will be used. |
| 49 func installCacheCronHandlerImpl(r *router.Router, base router.MiddlewareChain,
backend config.Backend) { |
| 50 base = base.Extend(func(c *router.Context, next router.Handler) { |
| 51 // Install our Backend into our Context. |
| 52 c.Context = installConfigBackend(c.Context, mustFetchCachedSetti
ngs(c.Context), backend, true) |
| 53 next(c) |
| 54 }) |
| 55 |
| 56 dsCache.InstallCronRoute("/admin/config/cache/manager", r, base) |
| 57 } |
| 58 |
| 34 // Use installs the default luci-config client. | 59 // Use installs the default luci-config client. |
| 35 // | 60 // |
| 36 // The client is configured to use luci-config URL specified in the settings, | 61 // The client is configured to use luci-config URL specified in the settings, |
| 37 // using GAE app service account for authentication. | 62 // using GAE app service account for authentication. |
| 38 // | 63 // |
| 39 // If running in prod, and the settings don't specify luci-config URL, produces | 64 // If running in prod, and the settings don't specify luci-config URL, produces |
| 40 // an implementation of config.Interface that returns ErrNotConfigured from all | 65 // an implementation of config.Interface that returns ErrNotConfigured from all |
| 41 // methods. | 66 // methods. |
| 42 // | 67 // |
| 43 // If running on devserver, and the settings don't specify luci-config URL, | 68 // If running on devserver, and the settings don't specify luci-config URL, |
| 44 // returns a filesystem-based implementation that reads configs from a directory | 69 // returns a filesystem-based implementation that reads configs from a directory |
| 45 // (or a symlink) named 'devcfg' located in the GAE module directory (where | 70 // (or a symlink) named 'devcfg' located in the GAE module directory (where |
| 46 // app.yaml is) or its immediate parent directory. | 71 // app.yaml is) or its immediate parent directory. |
| 47 // | 72 // |
| 48 // If such directory can not be located, produces an implementation of | 73 // If such directory can not be located, produces an implementation of |
| 49 // config.Interface that returns errors from all methods. | 74 // config.Interface that returns errors from all methods. |
| 50 // | 75 // |
| 51 // Panics if it can't load the settings (should not happen since they are in | 76 // Panics if it can't load the settings (should not happen since they are in |
| 52 // the local memory cache usually). | 77 // the local memory cache usually). |
| 53 func Use(c context.Context) context.Context { return useImpl(c, nil) } | 78 func Use(c context.Context) context.Context { return useImpl(c, nil) } |
| 54 | 79 |
| 55 func useImpl(c context.Context, backend config.Backend) context.Context { | 80 func useImpl(c context.Context, backend config.Backend) context.Context { |
| 56 » return installConfigBackend(c, mustFetchCachedSettings(c), backend) | 81 » return installConfigBackend(c, mustFetchCachedSettings(c), backend, fals
e) |
| 57 } | 82 } |
| 58 | 83 |
| 59 func installConfigBackend(c context.Context, s *Settings, backend config.Backend
) context.Context { | 84 func installConfigBackend(c context.Context, s *Settings, backend config.Backend
, dsCron bool) context.Context { |
| 60 if backend == nil { | 85 if backend == nil { |
| 61 // Non-testing, build a Backend. | 86 // Non-testing, build a Backend. |
| 62 backend = getPrimaryBackend(c, s) | 87 backend = getPrimaryBackend(c, s) |
| 63 } | 88 } |
| 64 | 89 |
| 65 // Install a FormatRegistry. Register common config service protobufs wi
th it. | 90 // Install a FormatRegistry. Register common config service protobufs wi
th it. |
| 66 c = withFormatRegistry(c, defaultFormatterRegistry()) | 91 c = withFormatRegistry(c, defaultFormatterRegistry()) |
| 67 | 92 |
| 68 backend = &config.FormatBackend{ | 93 backend = &config.FormatBackend{ |
| 69 Backend: backend, | 94 Backend: backend, |
| 70 GetRegistry: GetFormatterRegistry, | 95 GetRegistry: GetFormatterRegistry, |
| 71 } | 96 } |
| 72 | 97 |
| 73 // Apply caching configuration. | 98 // Apply caching configuration. |
| 74 exp := time.Duration(s.CacheExpirationSec) * time.Second | 99 exp := time.Duration(s.CacheExpirationSec) * time.Second |
| 75 if exp > 0 { | 100 if exp > 0 { |
| 76 // Add a ProcCache, backed by memcache. | 101 // Add a ProcCache, backed by memcache. |
| 77 backend = caching.ProcCache(backend, exp) | 102 backend = caching.ProcCache(backend, exp) |
| 78 backend = memcacheBackend(backend, exp) | 103 backend = memcacheBackend(backend, exp) |
| 104 |
| 105 // If our datastore cache is enabled, install a handler for refr
esh. This |
| 106 // will be loaded by dsCache's "HandlerFunc". |
| 107 if s.DatastoreCacheMode != dsCacheDisabled { |
| 108 dsc := datastoreCache{ |
| 109 refreshInterval: exp, |
| 110 failOpen: s.DatastoreCacheMode == dsCache
Enabled, |
| 111 } |
| 112 |
| 113 if !dsCron { |
| 114 // For non-cron, install the datastore cache Bac
kend. |
| 115 backend = dsc.getBackend(backend) |
| 116 } else { |
| 117 // For cron, do not install the datastore cache
Backend. Instead, |
| 118 // install a lasting Handler into the Context to
be used for cache |
| 119 // resolution. This is necessary since resolutio
n calls will not be |
| 120 // the result of an actual resolution command (e
.g., cache.Get). |
| 121 c = dsc.withHandler(c, datastoreCronLoader(backe
nd), dsRPCDeadline) |
| 122 } |
| 123 } |
| 79 } | 124 } |
| 80 | 125 |
| 81 c = config.WithBackend(c, backend) | 126 c = config.WithBackend(c, backend) |
| 82 return c | 127 return c |
| 83 } | 128 } |
| 84 | 129 |
| 85 func getPrimaryBackend(c context.Context, settings *Settings) (backend config.Ba
ckend) { | 130 func getPrimaryBackend(c context.Context, settings *Settings) (backend config.Ba
ckend) { |
| 86 // Identify our config service Backend (in testing, it will be supplied)
. | 131 // Identify our config service Backend (in testing, it will be supplied)
. |
| 87 if settings.ConfigServiceURL == "" { | 132 if settings.ConfigServiceURL == "" { |
| 88 if info.IsDevAppServer(c) { | 133 if info.IsDevAppServer(c) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 | 173 |
| 129 func withFormatRegistry(c context.Context, fr *config.FormatterRegistry) context
.Context { | 174 func withFormatRegistry(c context.Context, fr *config.FormatterRegistry) context
.Context { |
| 130 return context.WithValue(c, &formatRegistryKey, fr) | 175 return context.WithValue(c, &formatRegistryKey, fr) |
| 131 } | 176 } |
| 132 | 177 |
| 133 // GetFormatterRegistry is used to retrieve the config service format registry | 178 // GetFormatterRegistry is used to retrieve the config service format registry |
| 134 // from the supplied Context. | 179 // from the supplied Context. |
| 135 func GetFormatterRegistry(c context.Context) *config.FormatterRegistry { | 180 func GetFormatterRegistry(c context.Context) *config.FormatterRegistry { |
| 136 return c.Value(&formatRegistryKey).(*config.FormatterRegistry) | 181 return c.Value(&formatRegistryKey).(*config.FormatterRegistry) |
| 137 } | 182 } |
| OLD | NEW |