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 |