Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(514)

Side by Side Diff: server/config/service.go

Issue 2580713002: Implement a server-side config service interface. (Closed)
Patch Set: Update MultiResolver interface, add test for MultiError. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package config
6
7 import (
8 "net/http"
9 "net/url"
10 "sync"
11
12 "github.com/luci/luci-go/common/config"
13 "github.com/luci/luci-go/common/config/impl/remote"
14 "github.com/luci/luci-go/common/errors"
15 "github.com/luci/luci-go/server/auth"
16
17 "golang.org/x/net/context"
18 )
19
20 // ClientProvider returns a config.Interface for the supplied parameters.
21 type ClientProvider interface {
22 GetConfigClient(context.Context, Authority) config.Interface
23 }
24
25 // ClientBackend returns a Backend implementation that falls through to the
26 // supplied client config.Interface supplied by the Provider.
27 //
28 // url is the base URL to the configuration service, e.g.,
29 // https://example.appspot.com.
30 type ClientBackend struct {
31 Provider ClientProvider
32 }
33
34 var _ Backend = (*ClientBackend)(nil)
35
36 // ServiceURL implements Backend.
37 func (cb *ClientBackend) ServiceURL(c context.Context) url.URL {
38 return cb.getIface(c, AsAnonymous).ServiceURL(c)
39 }
40
41 // ConfigSetURL implements Backend.
42 func (cb *ClientBackend) ConfigSetURL(c context.Context, a Authority, configSet string) (url.URL, error) {
43 u, err := cb.getIface(c, a).GetConfigSetLocation(c, configSet)
44 if err != nil || u == nil {
45 return url.URL{}, err
46 }
47 return *u, nil
48 }
49
50 // Get implements Backend.
51 func (cb *ClientBackend) Get(c context.Context, configSet, path string, p Params ) (*Item, error) {
52 svc := cb.getIface(c, p.Authority)
53
54 cfg, err := svc.GetConfig(c, configSet, path, !p.Content)
55 if err != nil {
56 return nil, translateConfigErr(err)
57 }
58
59 return makeItem(cfg), nil
60 }
61
62 // GetAll implements Backend.
63 func (cb *ClientBackend) GetAll(c context.Context, t GetAllType, path string, p Params) ([]*Item, error) {
64 svc := cb.getIface(c, p.Authority)
65
66 var fn func(context.Context, string, bool) ([]config.Config, error)
67 switch t {
68 case Project:
69 fn = svc.GetProjectConfigs
70 case Ref:
71 fn = svc.GetRefConfigs
72 default:
73 return nil, errors.Reason("unknown GetAllType: %(type)q").D("typ e", t).Err()
74 }
75
76 cfgs, err := fn(c, path, !p.Content)
77 if err != nil || len(cfgs) == 0 {
78 return nil, translateConfigErr(err)
79 }
80
81 items := make([]*Item, len(cfgs))
82 for i := range cfgs {
83 items[i] = makeItem(&cfgs[i])
84 }
85 return items, nil
86 }
87
88 func (cb *ClientBackend) getIface(c context.Context, a Authority) config.Interfa ce {
89 return cb.Provider.GetConfigClient(c, a)
90 }
91
92 // RemoteClientProvider is a ClientProvider implementation that binds to
93 // a remote configuration service.
94 type RemoteClientProvider struct {
95 // BaseURL is the base URL to the configuration service, e.g.,
96 // https://example.appspot.com.
97 BaseURL string
98
99 cacheLock sync.RWMutex
100 cache map[Authority]config.Interface
101
102 // testUserDelegationToken, if not nil, is the delegation token to use f or
103 // AsUser calls. This is done to mock delegation token generation.
104 testUserDelegationToken string
105 }
106
107 var _ ClientProvider = (*RemoteClientProvider)(nil)
108
109 // GetConfigClient implements ClientProvider.
110 func (p *RemoteClientProvider) GetConfigClient(c context.Context, a Authority) c onfig.Interface {
111 p.cacheLock.RLock()
112 impl, ok := p.cache[a]
113 p.cacheLock.RUnlock()
114 if ok {
115 return impl
116 }
117
118 p.cacheLock.Lock()
119 defer p.cacheLock.Unlock()
120
121 if impl, ok := p.cache[a]; ok {
122 return impl
123 }
124
125 // Create our remote implementation.
126 impl = remote.New(p.BaseURL+"/_ah/api/config/v1/", func(c context.Contex t) (*http.Client, error) {
127 var opts []auth.RPCOption
128 if a == AsUser && p.testUserDelegationToken != "" {
129 opts = append(opts, auth.WithDelegationToken(p.testUserD elegationToken))
130 }
131 t, err := auth.GetRPCTransport(c, a.rpcAuthorityKind(), opts...)
132 if err != nil {
133 return nil, err
134 }
135 return &http.Client{Transport: t}, nil
136 })
137 if p.cache == nil {
138 p.cache = make(map[Authority]config.Interface, 3)
139 }
140 p.cache[a] = impl
141
142 return impl
143 }
144
145 func translateConfigErr(err error) error {
146 switch err {
147 case config.ErrNoConfig:
148 return ErrNoConfig
149 default:
150 return err
151 }
152 }
153
154 func makeItem(cfg *config.Config) *Item {
155 return &Item{
156 Meta: Meta{
157 ConfigSet: cfg.ConfigSet,
158 Path: cfg.Path,
159 ContentHash: cfg.ContentHash,
160 Revision: cfg.Revision,
161 },
162 Content: cfg.Content,
163 }
164 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698