Chromium Code Reviews| Index: appengine/logdog/coordinator/project.go |
| diff --git a/appengine/logdog/coordinator/project.go b/appengine/logdog/coordinator/project.go |
| index 0553620a5bfe27caa9a059bcde0c247b9fd94e46..78b358eddc00ba6149cd35015a048337b501adb7 100644 |
| --- a/appengine/logdog/coordinator/project.go |
| +++ b/appengine/logdog/coordinator/project.go |
| @@ -7,20 +7,27 @@ package coordinator |
| import ( |
| "strings" |
| - "github.com/luci/gae/service/datastore/meta" |
| "github.com/luci/gae/service/info" |
| - "github.com/luci/luci-go/common/config" |
| + "github.com/luci/luci-go/appengine/logdog/coordinator/config" |
| + luciConfig "github.com/luci/luci-go/common/config" |
| + log "github.com/luci/luci-go/common/logging" |
| "github.com/luci/luci-go/common/proto/logdog/svcconfig" |
| "golang.org/x/net/context" |
| ) |
| -// projectNamespacePrefix is the datastore namespace prefix for project |
| -// namespaces. |
| -const projectNamespacePrefix = "luci." |
| +const ( |
| + // projectNamespacePrefix is the datastore namespace prefix for project |
| + // namespaces. |
| + projectNamespacePrefix = "luci." |
| + |
| + // projectConfigWorkers is the number of workers that will pull project |
| + // configs from the config service. |
| + projectConfigWorkers = 16 |
| +) |
| // ProjectNamespace returns the AppEngine namespace for a given luci-config |
| // project name. |
| -func ProjectNamespace(project config.ProjectName) string { |
| +func ProjectNamespace(project luciConfig.ProjectName) string { |
| return projectNamespacePrefix + string(project) |
| } |
| @@ -29,11 +36,11 @@ func ProjectNamespace(project config.ProjectName) string { |
| // |
| // If the namespace does not have a project namespace prefix, this function |
| // will return an empty string. |
| -func ProjectFromNamespace(ns string) config.ProjectName { |
| +func ProjectFromNamespace(ns string) luciConfig.ProjectName { |
| if !strings.HasPrefix(ns, projectNamespacePrefix) { |
| return "" |
| } |
| - return config.ProjectName(ns[len(projectNamespacePrefix):]) |
| + return luciConfig.ProjectName(ns[len(projectNamespacePrefix):]) |
| } |
| // CurrentProject returns the current project based on the currently-loaded |
| @@ -41,7 +48,7 @@ func ProjectFromNamespace(ns string) config.ProjectName { |
| // |
| // If there is no current namespace, or if the current namespace is not a valid |
| // project namespace, an empty string will be returned. |
| -func CurrentProject(c context.Context) config.ProjectName { |
| +func CurrentProject(c context.Context) luciConfig.ProjectName { |
| if ns, ok := info.Get(c).GetNamespace(); ok { |
| return ProjectFromNamespace(ns) |
| } |
| @@ -57,18 +64,31 @@ func CurrentProjectConfig(c context.Context) (*svcconfig.ProjectConfig, error) { |
| return GetServices(c).ProjectConfig(c, CurrentProject(c)) |
| } |
| -// AllProjectsWithNamespaces scans current namespaces and returns those that |
| -// belong to LUCI projects. |
| -func AllProjectsWithNamespaces(c context.Context) ([]config.ProjectName, error) { |
| - var projects []config.ProjectName |
| - err := meta.NamespacesWithPrefix(c, projectNamespacePrefix, func(ns string) error { |
| - if proj := ProjectFromNamespace(ns); proj != "" { |
| - projects = append(projects, proj) |
| - } |
| - return nil |
| - }) |
| +// ActiveUserProjects returns a full list of all config service projects with |
| +// a LogDog project configurations that the current user has READ access to. |
|
nodir
2016/05/19 17:17:21
s/a //
dnj (Google)
2016/05/19 20:10:46
Done.
|
| +func ActiveUserProjects(c context.Context) (map[luciConfig.ProjectName]*svcconfig.ProjectConfig, error) { |
| + allPcfgs, err := config.AllProjectConfigs(c) |
|
nodir
2016/05/19 17:17:21
I'd strongly recommend calling this function in a
dnj (Google)
2016/05/19 20:10:46
Agreed, and I'll put a TODO in, but this is not a
|
| if err != nil { |
| return nil, err |
| } |
| - return projects, nil |
| + |
| + for project, pcfg := range allPcfgs { |
|
nodir
2016/05/19 17:17:21
add a TODO to make acl check concurrent. Auth grou
dnj (Google)
2016/05/19 20:10:46
If this is actually a problem, I think we need to
|
| + // Verify user access. This includes loading the project's config. |
|
nodir
2016/05/19 17:17:21
it does not include that
dnj (Google)
2016/05/19 20:10:46
Done.
|
| + if err := IsProjectReader(c, pcfg); err != nil { |
| + delete(allPcfgs, project) |
|
nodir
2016/05/19 17:17:21
this makes me nervous. I'd rather create a separat
dnj (Google)
2016/05/19 20:10:46
Agree about parallel construction.
I thought abou
|
| + |
| + // If it is a membership error, prune this project and continue. |
| + // Otherwise, forward the error. |
| + if !IsMembershipError(err) { |
| + // No configuration for this project, the configuration is invalid, or |
| + // the user didn't have access. Remove it from the list. |
| + log.Fields{ |
| + log.ErrorKey: err, |
| + "project": project, |
| + }.Errorf(c, "Failed to check project.") |
| + return nil, err |
| + } |
| + } |
| + } |
| + return allPcfgs, nil |
| } |