Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package coordinator | 5 package coordinator |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "strings" | 8 "strings" |
| 9 | 9 |
| 10 "github.com/luci/gae/service/datastore/meta" | |
| 11 "github.com/luci/gae/service/info" | 10 "github.com/luci/gae/service/info" |
| 12 » "github.com/luci/luci-go/common/config" | 11 » "github.com/luci/luci-go/appengine/logdog/coordinator/config" |
| 12 » luciConfig "github.com/luci/luci-go/common/config" | |
| 13 » log "github.com/luci/luci-go/common/logging" | |
| 14 » "github.com/luci/luci-go/common/parallel" | |
| 13 "github.com/luci/luci-go/common/proto/logdog/svcconfig" | 15 "github.com/luci/luci-go/common/proto/logdog/svcconfig" |
| 14 "golang.org/x/net/context" | 16 "golang.org/x/net/context" |
|
nodir
2016/05/19 00:38:58
should be in a separate import block
| |
| 15 ) | 17 ) |
| 16 | 18 |
| 17 // projectNamespacePrefix is the datastore namespace prefix for project | 19 const ( |
| 18 // namespaces. | 20 » // projectNamespacePrefix is the datastore namespace prefix for project |
| 19 const projectNamespacePrefix = "luci." | 21 » // namespaces. |
| 22 » projectNamespacePrefix = "luci." | |
|
nodir
2016/05/19 00:38:58
I'd definitely use "project." so namespaces are "p
| |
| 23 | |
| 24 » // projectConfigWorkers is the number of workers that will pull project | |
| 25 » // configs from the config service. | |
| 26 » projectConfigWorkers = 16 | |
| 27 ) | |
| 20 | 28 |
| 21 // ProjectNamespace returns the AppEngine namespace for a given luci-config | 29 // ProjectNamespace returns the AppEngine namespace for a given luci-config |
| 22 // project name. | 30 // project name. |
| 23 func ProjectNamespace(project config.ProjectName) string { | 31 func ProjectNamespace(project luciConfig.ProjectName) string { |
| 24 return projectNamespacePrefix + string(project) | 32 return projectNamespacePrefix + string(project) |
| 25 } | 33 } |
| 26 | 34 |
| 27 // ProjectFromNamespace returns the current project installed in the supplied | 35 // ProjectFromNamespace returns the current project installed in the supplied |
| 28 // Context's namespace. | 36 // Context's namespace. |
| 29 // | 37 // |
| 30 // If the namespace does not have a project namespace prefix, this function | 38 // If the namespace does not have a project namespace prefix, this function |
| 31 // will return an empty string. | 39 // will return an empty string. |
| 32 func ProjectFromNamespace(ns string) config.ProjectName { | 40 func ProjectFromNamespace(ns string) luciConfig.ProjectName { |
| 33 if !strings.HasPrefix(ns, projectNamespacePrefix) { | 41 if !strings.HasPrefix(ns, projectNamespacePrefix) { |
| 34 return "" | 42 return "" |
| 35 } | 43 } |
| 36 » return config.ProjectName(ns[len(projectNamespacePrefix):]) | 44 » return luciConfig.ProjectName(ns[len(projectNamespacePrefix):]) |
| 37 } | 45 } |
| 38 | 46 |
| 39 // CurrentProject returns the current project based on the currently-loaded | 47 // CurrentProject returns the current project based on the currently-loaded |
| 40 // namespace. | 48 // namespace. |
| 41 // | 49 // |
| 42 // If there is no current namespace, or if the current namespace is not a valid | 50 // If there is no current namespace, or if the current namespace is not a valid |
| 43 // project namespace, an empty string will be returned. | 51 // project namespace, an empty string will be returned. |
| 44 func CurrentProject(c context.Context) config.ProjectName { | 52 func CurrentProject(c context.Context) luciConfig.ProjectName { |
| 45 if ns, ok := info.Get(c).GetNamespace(); ok { | 53 if ns, ok := info.Get(c).GetNamespace(); ok { |
| 46 return ProjectFromNamespace(ns) | 54 return ProjectFromNamespace(ns) |
| 47 } | 55 } |
| 48 return "" | 56 return "" |
| 49 } | 57 } |
| 50 | 58 |
| 51 // CurrentProjectConfig returns the project-specific configuration for the | 59 // CurrentProjectConfig returns the project-specific configuration for the |
| 52 // current project. | 60 // current project. |
| 53 // | 61 // |
| 54 // If there is no current project namespace, or if the current project has no | 62 // If there is no current project namespace, or if the current project has no |
| 55 // configuration, config.ErrInvalidConfig will be returned. | 63 // configuration, config.ErrInvalidConfig will be returned. |
| 56 func CurrentProjectConfig(c context.Context) (*svcconfig.ProjectConfig, error) { | 64 func CurrentProjectConfig(c context.Context) (*svcconfig.ProjectConfig, error) { |
| 57 return GetServices(c).ProjectConfig(c, CurrentProject(c)) | 65 return GetServices(c).ProjectConfig(c, CurrentProject(c)) |
| 58 } | 66 } |
| 59 | 67 |
| 60 // AllProjectsWithNamespaces scans current namespaces and returns those that | 68 // ActiveProjects returns a full list of all config service projects with LogDog |
| 61 // belong to LUCI projects. | 69 // project configurations. |
| 62 func AllProjectsWithNamespaces(c context.Context) ([]config.ProjectName, error) { | 70 // |
| 63 » var projects []config.ProjectName | 71 // If userOnly is true, any project not accessible by the current user will not |
| 64 » err := meta.NamespacesWithPrefix(c, projectNamespacePrefix, func(ns stri ng) error { | 72 // be returned. |
| 65 » » if proj := ProjectFromNamespace(ns); proj != "" { | 73 func ActiveProjects(c context.Context, userOnly bool) ([]luciConfig.ProjectName, error) { |
| 66 » » » projects = append(projects, proj) | 74 » projects, err := config.Projects(c) |
| 67 » » } | |
| 68 » » return nil | |
| 69 » }) | |
| 70 if err != nil { | 75 if err != nil { |
| 71 return nil, err | 76 return nil, err |
| 72 } | 77 } |
| 78 log.Infof(c, "All projects: %v", projects) | |
| 79 | |
| 80 svcs := GetServices(c) | |
| 81 err = parallel.WorkPool(projectConfigWorkers, func(taskC chan<- func() e rror) { | |
| 82 for i := range projects { | |
| 83 i := i | |
| 84 taskC <- func() error { | |
| 85 var err error | |
| 86 if userOnly { | |
| 87 // Verify user access. This includes loa ding the project's config. | |
| 88 err = IsProjectReader(c, projects[i]) | |
| 89 } else { | |
| 90 _, err = svcs.ProjectConfig(c, projects[ i]) | |
| 91 } | |
| 92 | |
| 93 switch { | |
| 94 case err == nil: | |
| 95 // Project config loaded and (if request ed) user had access. | |
| 96 return nil | |
| 97 | |
| 98 case err == luciConfig.ErrNoConfig, err == confi g.ErrInvalidConfig, IsMembershipError(err): | |
| 99 // No configuration for this project, th e configuration is invalid, or | |
| 100 // the user didn't have access. Remove i t from the list. | |
| 101 projects[i] = "" | |
| 102 return nil | |
| 103 | |
| 104 default: | |
| 105 log.Fields{ | |
| 106 log.ErrorKey: err, | |
| 107 "project": projects[i], | |
| 108 "userOnly": userOnly, | |
| 109 }.Errorf(c, "Failed to check project.") | |
| 110 return err | |
| 111 } | |
| 112 } | |
| 113 } | |
| 114 }) | |
| 115 if err != nil { | |
| 116 log.WithError(err).Errorf(c, "Failed to get project list.") | |
| 117 return nil, err | |
| 118 } | |
| 119 | |
| 120 // Remove any projects that have been blanked out. | |
| 121 cidx := 0 | |
| 122 for _, proj := range projects { | |
| 123 if proj != "" { | |
| 124 projects[cidx] = proj | |
| 125 cidx++ | |
| 126 } | |
| 127 } | |
| 128 projects = projects[:cidx] | |
| 129 log.Infof(c, "Pruned projects: %v", projects) | |
| 73 return projects, nil | 130 return projects, nil |
| 74 } | 131 } |
| OLD | NEW |