Index: appengine/logdog/coordinator/project.go |
diff --git a/appengine/logdog/coordinator/project.go b/appengine/logdog/coordinator/project.go |
index 0553620a5bfe27caa9a059bcde0c247b9fd94e46..1fea5efe6ddc24114022851bae75340f08470d0e 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,35 @@ 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 |
+// LogDog project configurations that the current user has READ access to. |
+// |
+// TODO: Load project configs and all project configs lists from datastore. Add |
+// a background cron job to periodically update these lists from luci-config. |
+// This should be a generic config service capability. |
+func ActiveUserProjects(c context.Context) (map[luciConfig.ProjectName]*svcconfig.ProjectConfig, error) { |
+ allPcfgs, err := config.AllProjectConfigs(c) |
if err != nil { |
return nil, err |
} |
- return projects, nil |
+ |
+ for project, pcfg := range allPcfgs { |
+ // Verify user READ access. |
+ if err := IsProjectReader(c, pcfg); err != nil { |
+ delete(allPcfgs, project) |
+ |
+ // 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 |
} |