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

Side by Side Diff: luci_config/server/cfgclient/backend/client/client.go

Issue 2580713002: Implement a server-side config service interface. (Closed)
Patch Set: Renamed, moved to luci_config package, fixes, split out backends. Created 3 years, 11 months 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 client implements a config client backend for a configuration client.
6 package client
7
8 import (
9 "fmt"
10 "net/http"
11 "net/url"
12 "sync"
13
14 "github.com/luci/luci-go/common/config"
15 "github.com/luci/luci-go/common/config/impl/remote"
16 "github.com/luci/luci-go/common/errors"
17 "github.com/luci/luci-go/luci_config/server/cfgclient"
18 "github.com/luci/luci-go/luci_config/server/cfgclient/backend"
19 "github.com/luci/luci-go/server/auth"
20
21 "golang.org/x/net/context"
22 )
23
24 // Provider returns a config.Interface for the supplied parameters.
25 type Provider interface {
26 GetConfigClient(context.Context, backend.Authority) config.Interface
27 }
28
29 // Backend returns a backend.B implementation that falls through to the supplied
30 // configuration service client's config.Interface, supplied by the Provider.
31 //
32 // url is the base URL to the configuration service, e.g.,
33 // https://example.appspot.com.
34 type Backend struct {
35 Provider Provider
36 }
37
38 var _ backend.B = (*Backend)(nil)
39
40 // ServiceURL implements backend.B.
41 func (be *Backend) ServiceURL(c context.Context) url.URL {
42 return be.getIface(c, backend.AsAnonymous).ServiceURL(c)
43 }
44
45 // ConfigSetURL implements backend.B.
46 func (be *Backend) ConfigSetURL(c context.Context, configSet string, p backend.P arams) (url.URL, error) {
47 u, err := be.getIface(c, p.Authority).GetConfigSetLocation(c, configSet)
48 if err != nil || u == nil {
49 return url.URL{}, err
50 }
51 return *u, nil
52 }
53
54 // Get implements backend.B.
55 func (be *Backend) Get(c context.Context, configSet, path string, p backend.Para ms) (*backend.Item, error) {
56 svc := be.getIface(c, p.Authority)
57
58 cfg, err := svc.GetConfig(c, configSet, path, !p.Content)
59 if err != nil {
60 return nil, translateConfigErr(err)
61 }
62
63 return makeItem(cfg), nil
64 }
65
66 // GetAll implements backend.B.
67 func (be *Backend) GetAll(c context.Context, t backend.GetAllTarget, path string , p backend.Params) (
68 []*backend.Item, error) {
69
70 svc := be.getIface(c, p.Authority)
71
72 var fn func(context.Context, string, bool) ([]config.Config, error)
73 switch t {
74 case backend.GetAllProject:
75 fn = svc.GetProjectConfigs
76 case backend.GetAllRef:
77 fn = svc.GetRefConfigs
78 default:
79 return nil, errors.Reason("unknown GetAllType: %(type)q").D("typ e", t).Err()
80 }
81
82 cfgs, err := fn(c, path, !p.Content)
83 if err != nil || len(cfgs) == 0 {
84 return nil, translateConfigErr(err)
85 }
86
87 items := make([]*backend.Item, len(cfgs))
88 for i := range cfgs {
89 items[i] = makeItem(&cfgs[i])
90 }
91 return items, nil
92 }
93
94 func (be *Backend) getIface(c context.Context, a backend.Authority) config.Inter face {
95 return be.Provider.GetConfigClient(c, a)
96 }
97
98 // RemoteProvider is a Provider implementation that binds to
99 // a remote configuration service.
100 type RemoteProvider struct {
101 // BaseURL is the base URL to the configuration service, e.g.,
102 // https://example.appspot.com.
103 BaseURL string
104
105 cacheLock sync.RWMutex
106 cache map[backend.Authority]config.Interface
107
108 // testUserDelegationToken, if not nil, is the delegation token to use f or
109 // AsUser calls. This is done to mock delegation token generation.
110 testUserDelegationToken string
111 }
112
113 var _ Provider = (*RemoteProvider)(nil)
114
115 // GetConfigClient implements Provider.
116 func (p *RemoteProvider) GetConfigClient(c context.Context, a backend.Authority) config.Interface {
117 p.cacheLock.RLock()
118 impl, ok := p.cache[a]
119 p.cacheLock.RUnlock()
120 if ok {
121 return impl
122 }
123
124 p.cacheLock.Lock()
125 defer p.cacheLock.Unlock()
126
127 if impl, ok := p.cache[a]; ok {
128 return impl
129 }
130
131 // Create our remote implementation.
132 impl = remote.New(p.BaseURL+"/_ah/api/config/v1/", func(c context.Contex t) (*http.Client, error) {
133 var opts []auth.RPCOption
134 if a == backend.AsUser && p.testUserDelegationToken != "" {
135 opts = append(opts, auth.WithDelegationToken(p.testUserD elegationToken))
136 }
137 t, err := auth.GetRPCTransport(c, rpcAuthorityKind(a), opts...)
138 if err != nil {
139 return nil, err
140 }
141 return &http.Client{Transport: t}, nil
142 })
143 if p.cache == nil {
144 p.cache = make(map[backend.Authority]config.Interface, 3)
145 }
146 p.cache[a] = impl
147
148 return impl
149 }
150
151 func translateConfigErr(err error) error {
152 switch err {
153 case config.ErrNoConfig:
154 return cfgclient.ErrNoConfig
155 default:
156 return err
157 }
158 }
159
160 func makeItem(cfg *config.Config) *backend.Item {
161 return &backend.Item{
162 Meta: backend.Meta{
163 ConfigSet: cfg.ConfigSet,
164 Path: cfg.Path,
165 ContentHash: cfg.ContentHash,
166 Revision: cfg.Revision,
167 },
168 Content: cfg.Content,
169 }
170 }
171
172 // rpcAuthorityKind returns the RPC authority associated with this authority
173 // level.
174 func rpcAuthorityKind(a backend.Authority) auth.RPCAuthorityKind {
175 switch a {
176 case backend.AsAnonymous:
177 return auth.NoAuth
178 case backend.AsService:
179 return auth.AsSelf
180 case backend.AsUser:
181 return auth.AsUser
182 default:
183 panic(fmt.Errorf("unknown config Authority (%d)", a))
184 }
185 }
OLDNEW
« no previous file with comments | « luci_config/server/cfgclient/backend/backend.go ('k') | luci_config/server/cfgclient/backend/client/client_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698