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..47defc6c9bc77573382e4000a7bc159ccf967146 100644 |
| --- a/appengine/logdog/coordinator/project.go |
| +++ b/appengine/logdog/coordinator/project.go |
| @@ -7,20 +7,28 @@ 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/parallel" |
| "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 +37,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 +49,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 +65,67 @@ 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) |
| +// ActiveProjects returns a full list of all config service projects with LogDog |
| +// project configurations. |
| +// |
| +// If userOnly is true, any project not accessible by the current user will not |
| +// be returned. |
| +func ActiveProjects(c context.Context, userOnly bool) ([]luciConfig.ProjectName, error) { |
| + projects, err := config.Projects(c) |
|
nodir
2016/05/19 00:38:59
use https://godoc.org/github.com/luci/luci-go/comm
|
| + if err != nil { |
| + return nil, err |
| + } |
| + log.Infof(c, "All projects: %v", projects) |
| + |
| + svcs := GetServices(c) |
| + err = parallel.WorkPool(projectConfigWorkers, func(taskC chan<- func() error) { |
| + for i := range projects { |
| + i := i |
| + taskC <- func() error { |
| + var err error |
| + if userOnly { |
| + // Verify user access. This includes loading the project's config. |
| + err = IsProjectReader(c, projects[i]) |
| + } else { |
| + _, err = svcs.ProjectConfig(c, projects[i]) |
| + } |
| + |
| + switch { |
| + case err == nil: |
| + // Project config loaded and (if requested) user had access. |
| + return nil |
| + |
| + case err == luciConfig.ErrNoConfig, err == config.ErrInvalidConfig, IsMembershipError(err): |
| + // No configuration for this project, the configuration is invalid, or |
| + // the user didn't have access. Remove it from the list. |
| + projects[i] = "" |
| + return nil |
| + |
| + default: |
| + log.Fields{ |
| + log.ErrorKey: err, |
| + "project": projects[i], |
| + "userOnly": userOnly, |
| + }.Errorf(c, "Failed to check project.") |
| + return err |
| + } |
| + } |
| } |
| - return nil |
| }) |
| if err != nil { |
| + log.WithError(err).Errorf(c, "Failed to get project list.") |
| return nil, err |
| } |
| + |
| + // Remove any projects that have been blanked out. |
| + cidx := 0 |
| + for _, proj := range projects { |
| + if proj != "" { |
| + projects[cidx] = proj |
| + cidx++ |
| + } |
| + } |
| + projects = projects[:cidx] |
| + log.Infof(c, "Pruned projects: %v", projects) |
| return projects, nil |
| } |