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 /* | 5 /* |
6 Package cipd implements client side of Chrome Infra Package Deployer. | 6 Package cipd implements client side of Chrome Infra Package Deployer. |
7 | 7 |
8 TODO: write more. | 8 TODO: write more. |
9 | 9 |
10 Binary package file format (in free form representation): | 10 Binary package file format (in free form representation): |
(...skipping 23 matching lines...) Expand all Loading... | |
34 */ | 34 */ |
35 package cipd | 35 package cipd |
36 | 36 |
37 import ( | 37 import ( |
38 "bufio" | 38 "bufio" |
39 "errors" | 39 "errors" |
40 "fmt" | 40 "fmt" |
41 "io" | 41 "io" |
42 "net/http" | 42 "net/http" |
43 "os" | 43 "os" |
44 "path/filepath" | |
44 "sort" | 45 "sort" |
45 "strings" | 46 "strings" |
47 "sync" | |
46 "time" | 48 "time" |
47 | 49 |
48 "github.com/luci/luci-go/common/logging" | 50 "github.com/luci/luci-go/common/logging" |
49 | 51 |
50 "infra/tools/cipd/common" | 52 "infra/tools/cipd/common" |
53 "infra/tools/cipd/internal" | |
51 "infra/tools/cipd/local" | 54 "infra/tools/cipd/local" |
52 ) | 55 ) |
53 | 56 |
54 // PackageACLChangeAction defines a flavor of PackageACLChange. | 57 // PackageACLChangeAction defines a flavor of PackageACLChange. |
55 type PackageACLChangeAction string | 58 type PackageACLChangeAction string |
56 | 59 |
57 const ( | 60 const ( |
58 // GrantRole is used in PackageACLChange to request a role to be granted . | 61 // GrantRole is used in PackageACLChange to request a role to be granted . |
59 GrantRole PackageACLChangeAction = "GRANT" | 62 GrantRole PackageACLChangeAction = "GRANT" |
60 // RevokeRole is used in PackageACLChange to request a role to be revoke d. | 63 // RevokeRole is used in PackageACLChange to request a role to be revoke d. |
61 RevokeRole PackageACLChangeAction = "REVOKE" | 64 RevokeRole PackageACLChangeAction = "REVOKE" |
62 | 65 |
63 // CASFinalizationTimeout is how long to wait for CAS service to finaliz e the upload. | 66 // CASFinalizationTimeout is how long to wait for CAS service to finaliz e the upload. |
64 CASFinalizationTimeout = 1 * time.Minute | 67 CASFinalizationTimeout = 1 * time.Minute |
65 // SetRefTimeout is how long to wait for an instance to be processed whe n setting a ref. | 68 // SetRefTimeout is how long to wait for an instance to be processed whe n setting a ref. |
66 SetRefTimeout = 1 * time.Minute | 69 SetRefTimeout = 1 * time.Minute |
67 // TagAttachTimeout is how long to wait for an instance to be processed when attaching tags. | 70 // TagAttachTimeout is how long to wait for an instance to be processed when attaching tags. |
68 TagAttachTimeout = 1 * time.Minute | 71 TagAttachTimeout = 1 * time.Minute |
69 | 72 |
70 // UserAgent is HTTP user agent string for CIPD client. | 73 // UserAgent is HTTP user agent string for CIPD client. |
71 UserAgent = "cipd 1.0" | 74 UserAgent = "cipd 1.0" |
72 | 75 |
73 // ServiceURL is URL of a backend to connect to by default. | 76 // ServiceURL is URL of a backend to connect to by default. |
74 ServiceURL = "https://chrome-infra-packages.appspot.com" | 77 ServiceURL = "https://chrome-infra-packages.appspot.com" |
75 ) | 78 ) |
76 | 79 |
77 var ( | 80 var ( |
78 // ErrFinalizationTimeout is returned if CAS service can not finalize up load fast enough. | 81 // ErrFinalizationTimeout is returned if CAS service can not finalize up load fast enough. |
79 » ErrFinalizationTimeout = errors.New("Timeout while waiting for CAS servi ce to finalize the upload") | 82 » ErrFinalizationTimeout = errors.New("timeout while waiting for CAS servi ce to finalize the upload") |
80 // ErrBadUpload is returned when a package file is uploaded, but servers asks us to upload it again. | 83 // ErrBadUpload is returned when a package file is uploaded, but servers asks us to upload it again. |
81 » ErrBadUpload = errors.New("Package file is uploaded, but servers asks us to upload it again") | 84 » ErrBadUpload = errors.New("package file is uploaded, but servers asks us to upload it again") |
82 // ErrBadUploadSession is returned by UploadToCAS if provided UploadSess ion is not valid. | 85 // ErrBadUploadSession is returned by UploadToCAS if provided UploadSess ion is not valid. |
83 » ErrBadUploadSession = errors.New("UploadURL must be set if UploadSession ID is used") | 86 » ErrBadUploadSession = errors.New("uploadURL must be set if UploadSession ID is used") |
84 // ErrUploadSessionDied is returned by UploadToCAS if upload session sud denly disappeared. | 87 // ErrUploadSessionDied is returned by UploadToCAS if upload session sud denly disappeared. |
85 » ErrUploadSessionDied = errors.New("Upload session is unexpectedly missin g") | 88 » ErrUploadSessionDied = errors.New("upload session is unexpectedly missin g") |
86 // ErrNoUploadSessionID is returned by UploadToCAS if server didn't prov ide upload session ID. | 89 // ErrNoUploadSessionID is returned by UploadToCAS if server didn't prov ide upload session ID. |
87 » ErrNoUploadSessionID = errors.New("Server didn't provide upload session ID") | 90 » ErrNoUploadSessionID = errors.New("server didn't provide upload session ID") |
88 // ErrSetRefTimeout is returned when service refuses to move a ref for a long time. | 91 // ErrSetRefTimeout is returned when service refuses to move a ref for a long time. |
89 » ErrSetRefTimeout = errors.New("Timeout while moving a ref") | 92 » ErrSetRefTimeout = errors.New("timeout while moving a ref") |
90 // ErrAttachTagsTimeout is returned when service refuses to accept tags for a long time. | 93 // ErrAttachTagsTimeout is returned when service refuses to accept tags for a long time. |
91 » ErrAttachTagsTimeout = errors.New("Timeout while attaching tags") | 94 » ErrAttachTagsTimeout = errors.New("timeout while attaching tags") |
92 // ErrDownloadError is returned by FetchInstance on download errors. | 95 // ErrDownloadError is returned by FetchInstance on download errors. |
93 » ErrDownloadError = errors.New("Failed to download the package file after multiple attempts") | 96 » ErrDownloadError = errors.New("failed to download the package file after multiple attempts") |
94 // ErrUploadError is returned by RegisterInstance and UploadToCAS on upl oad errors. | 97 // ErrUploadError is returned by RegisterInstance and UploadToCAS on upl oad errors. |
95 » ErrUploadError = errors.New("Failed to upload the package file after mul tiple attempts") | 98 » ErrUploadError = errors.New("failed to upload the package file after mul tiple attempts") |
96 // ErrAccessDenined is returned by calls talking to backend on 401 or 40 3 HTTP errors. | 99 // ErrAccessDenined is returned by calls talking to backend on 401 or 40 3 HTTP errors. |
97 » ErrAccessDenined = errors.New("Access denied (not authenticated or not e nough permissions)") | 100 » ErrAccessDenined = errors.New("access denied (not authenticated or not e nough permissions)") |
98 // ErrBackendInaccessible is returned by calls talking to backed if it d oesn't response. | 101 // ErrBackendInaccessible is returned by calls talking to backed if it d oesn't response. |
99 » ErrBackendInaccessible = errors.New("Request to the backend failed after multiple attempts") | 102 » ErrBackendInaccessible = errors.New("request to the backend failed after multiple attempts") |
100 // ErrEnsurePackagesFailed is returned by EnsurePackages if something is not right. | 103 // ErrEnsurePackagesFailed is returned by EnsurePackages if something is not right. |
101 » ErrEnsurePackagesFailed = errors.New("Failed to update packages, see the log") | 104 » ErrEnsurePackagesFailed = errors.New("failed to update packages, see the log") |
102 ) | 105 ) |
103 | 106 |
104 // PackageACL is per package path per role access control list that is a part of | 107 // PackageACL is per package path per role access control list that is a part of |
105 // larger overall ACL: ACL for package "a/b/c" is a union of PackageACLs for "a" | 108 // larger overall ACL: ACL for package "a/b/c" is a union of PackageACLs for "a" |
106 // "a/b" and "a/b/c". | 109 // "a/b" and "a/b/c". |
107 type PackageACL struct { | 110 type PackageACL struct { |
108 // PackagePath is a package subpath this ACL is defined for. | 111 // PackagePath is a package subpath this ACL is defined for. |
109 PackagePath string | 112 PackagePath string |
110 // Role is a role that listed users have, e.g. 'READER', 'WRITER', ... | 113 // Role is a role that listed users have, e.g. 'READER', 'WRITER', ... |
111 Role string | 114 Role string |
(...skipping 16 matching lines...) Expand all Loading... | |
128 } | 131 } |
129 | 132 |
130 // UploadSession describes open CAS upload session. | 133 // UploadSession describes open CAS upload session. |
131 type UploadSession struct { | 134 type UploadSession struct { |
132 // ID identifies upload session in the backend. | 135 // ID identifies upload session in the backend. |
133 ID string | 136 ID string |
134 // URL is where to upload the data to. | 137 // URL is where to upload the data to. |
135 URL string | 138 URL string |
136 } | 139 } |
137 | 140 |
138 // Client provides high-level CIPD client interface. | 141 // Client provides high-level CIPD client interface. Thread safe. |
139 type Client interface { | 142 type Client interface { |
140 // FetchACL returns a list of PackageACL objects (parent paths first) th at | 143 // FetchACL returns a list of PackageACL objects (parent paths first) th at |
141 // together define the access control list for the given package subpath . | 144 // together define the access control list for the given package subpath . |
142 FetchACL(packagePath string) ([]PackageACL, error) | 145 FetchACL(packagePath string) ([]PackageACL, error) |
143 | 146 |
144 // ModifyACL applies a set of PackageACLChanges to a package path. | 147 // ModifyACL applies a set of PackageACLChanges to a package path. |
145 ModifyACL(packagePath string, changes []PackageACLChange) error | 148 ModifyACL(packagePath string, changes []PackageACLChange) error |
146 | 149 |
147 // UploadToCAS uploads package data blob to Content Addressed Store if i t is | 150 // UploadToCAS uploads package data blob to Content Addressed Store if i t is |
148 // not there already. The data is addressed by SHA1 hash (also known as | 151 // not there already. The data is addressed by SHA1 hash (also known as |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 // <package name> <desired version>. Whitespaces are ignored. Lines that start | 187 // <package name> <desired version>. Whitespaces are ignored. Lines that start |
185 // with '#' are ignored. Version can be specified as instance ID, tag or ref. | 188 // with '#' are ignored. Version can be specified as instance ID, tag or ref. |
186 // Will resolve tags and refs to concrete instance IDs by calling the ba ckend. | 189 // Will resolve tags and refs to concrete instance IDs by calling the ba ckend. |
187 ProcessEnsureFile(r io.Reader) ([]common.Pin, error) | 190 ProcessEnsureFile(r io.Reader) ([]common.Pin, error) |
188 | 191 |
189 // EnsurePackages is high-level interface for installation, removal and update | 192 // EnsurePackages is high-level interface for installation, removal and update |
190 // of packages inside the installation site root. Given a description of | 193 // of packages inside the installation site root. Given a description of |
191 // what packages (and versions) should be installed it will do all neces sary | 194 // what packages (and versions) should be installed it will do all neces sary |
192 // actions to bring the state of the site root to the desired one. | 195 // actions to bring the state of the site root to the desired one. |
193 EnsurePackages(pins []common.Pin) error | 196 EnsurePackages(pins []common.Pin) error |
197 | |
198 // Close should be called to dump any cached state to disk. | |
199 Close() | |
194 } | 200 } |
195 | 201 |
196 // HTTPClientFactory lazily creates http.Client to use for making requests. | 202 // HTTPClientFactory lazily creates http.Client to use for making requests. |
197 type HTTPClientFactory func() (*http.Client, error) | 203 type HTTPClientFactory func() (*http.Client, error) |
198 | 204 |
199 // ClientOptions is passed to NewClient factory function. | 205 // ClientOptions is passed to NewClient factory function. |
200 type ClientOptions struct { | 206 type ClientOptions struct { |
201 // ServiceURL is root URL of the backend service. | 207 // ServiceURL is root URL of the backend service. |
202 ServiceURL string | 208 ServiceURL string |
203 » // Root is a site root directory (where packages will be installed). It can | 209 |
204 » // be empty string if client is not going to be used to deploy or remove local packages. | 210 » // Root is a site root directory (a directory where packages will be |
211 » // installed to). It also hosts .cipd/* directory that tracks internal s tate | |
212 » // of installed packages and keeps various cache files. 'Root' can be an empty | |
213 » // string if the client is not going to be used to deploy or remove loca l | |
214 » // packages. In that case caches are also disabled. | |
205 Root string | 215 Root string |
216 | |
206 // Logger is a logger to use for logs (null-logger by default). | 217 // Logger is a logger to use for logs (null-logger by default). |
207 Logger logging.Logger | 218 Logger logging.Logger |
208 » // AuthenticatedClientFactory lazily creates http.Client to use for maki ng RPC requests. | 219 |
220 » // AuthenticatedClientFactory lazily creates http.Client to use for maki ng | |
221 » // RPC requests. | |
209 AuthenticatedClientFactory HTTPClientFactory | 222 AuthenticatedClientFactory HTTPClientFactory |
210 » // AnonymousClientFactory lazily creates http.Client to use for making r equests to storage. | 223 |
224 » // AnonymousClientFactory lazily creates http.Client to use for making | |
225 » // requests to storage. | |
211 AnonymousClientFactory HTTPClientFactory | 226 AnonymousClientFactory HTTPClientFactory |
227 | |
212 // UserAgent is put into User-Agent HTTP header with each request. | 228 // UserAgent is put into User-Agent HTTP header with each request. |
213 UserAgent string | 229 UserAgent string |
214 } | 230 } |
215 | 231 |
216 // NewClient initializes CIPD client object. | 232 // NewClient initializes CIPD client object. |
217 func NewClient(opts ClientOptions) Client { | 233 func NewClient(opts ClientOptions) Client { |
218 if opts.ServiceURL == "" { | 234 if opts.ServiceURL == "" { |
219 opts.ServiceURL = ServiceURL | 235 opts.ServiceURL = ServiceURL |
220 } | 236 } |
221 if opts.Logger == nil { | 237 if opts.Logger == nil { |
(...skipping 14 matching lines...) Expand all Loading... | |
236 } | 252 } |
237 c.remote = &remoteImpl{c} | 253 c.remote = &remoteImpl{c} |
238 c.storage = &storageImpl{c, uploadChunkSize} | 254 c.storage = &storageImpl{c, uploadChunkSize} |
239 c.deployer = local.NewDeployer(opts.Root, opts.Logger) | 255 c.deployer = local.NewDeployer(opts.Root, opts.Logger) |
240 return c | 256 return c |
241 } | 257 } |
242 | 258 |
243 type clientImpl struct { | 259 type clientImpl struct { |
244 ClientOptions | 260 ClientOptions |
245 | 261 |
246 » // clock provides current time and ability to sleep. | 262 » // lock protects lazily initialized portions of the client. |
263 » lock sync.Mutex | |
264 | |
265 » // clock provides current time and ability to sleep. Thread safe. | |
247 clock clock | 266 clock clock |
248 » // remote knows how to call backend REST API. | 267 |
268 » // remote knows how to call backend REST API. Thread safe. | |
249 remote remote | 269 remote remote |
270 | |
250 // storage knows how to upload and download raw binaries using signed UR Ls. | 271 // storage knows how to upload and download raw binaries using signed UR Ls. |
272 // Thread safe. | |
251 storage storage | 273 storage storage |
252 » // deployer knows how to install packages to local file system. | 274 |
275 » // deployer knows how to install packages to local file system. Thread s afe. | |
253 deployer local.Deployer | 276 deployer local.Deployer |
254 | 277 |
255 » // authClient is a lazily created http.Client to use for authenticated r equests. | 278 » // tagCache is used to cache (pkgname, tag) -> instanceID mapping. |
279 » // Thread safe, but lazily initialized under lock. | |
280 » tagCache internal.TagCache | |
281 | |
282 » // authClient is a lazily created http.Client to use for authenticated | |
283 » // requests. Thread safe, but lazily initialized under lock. | |
256 authClient *http.Client | 284 authClient *http.Client |
285 | |
257 // anonClient is a lazily created http.Client to use for anonymous reque sts. | 286 // anonClient is a lazily created http.Client to use for anonymous reque sts. |
287 // Thread safe, but lazily initialized under lock. | |
258 anonClient *http.Client | 288 anonClient *http.Client |
259 } | 289 } |
260 | 290 |
261 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s. | 291 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s. |
262 func (client *clientImpl) doAuthenticatedHTTPRequest(req *http.Request) (*http.R esponse, error) { | 292 func (client *clientImpl) doAuthenticatedHTTPRequest(req *http.Request) (*http.R esponse, error) { |
263 » if client.authClient == nil { | 293 » return client.doRequest(req, &client.authClient, client.AuthenticatedCli entFactory) |
264 » » var err error | |
265 » » client.authClient, err = client.AuthenticatedClientFactory() | |
266 » » if err != nil { | |
267 » » » return nil, err | |
268 » » } | |
269 » } | |
270 » return client.authClient.Do(req) | |
271 } | 294 } |
272 | 295 |
273 // doAnonymousHTTPRequest is used by storage implementation to make HTTP calls. | 296 // doAnonymousHTTPRequest is used by storage implementation to make HTTP calls. |
274 func (client *clientImpl) doAnonymousHTTPRequest(req *http.Request) (*http.Respo nse, error) { | 297 func (client *clientImpl) doAnonymousHTTPRequest(req *http.Request) (*http.Respo nse, error) { |
275 » if client.anonClient == nil { | 298 » return client.doRequest(req, &client.anonClient, client.AnonymousClientF actory) |
299 } | |
300 | |
301 // doRequest lazy-initializes http.Client by calling giving callback and then | |
tandrii(chromium)
2015/09/30 18:11:15
s/by calling giving callback/using provided factor
Vadim Sh.
2015/09/30 22:50:59
Done.
| |
302 // executes the request. | |
303 func (client *clientImpl) doRequest(req *http.Request, c **http.Client, fac HTTP ClientFactory) (*http.Response, error) { | |
304 » httpClient, err := func() (*http.Client, error) { | |
305 » » client.lock.Lock() | |
306 » » defer client.lock.Unlock() | |
276 var err error | 307 var err error |
277 » » client.anonClient, err = client.AnonymousClientFactory() | 308 » » if *c == nil { |
278 » » if err != nil { | 309 » » » *c, err = fac() |
279 » » » return nil, err | 310 » » } |
311 » » return *c, err | |
312 » }() | |
313 » if err != nil { | |
314 » » return nil, err | |
315 » } | |
316 » return httpClient.Do(req) | |
317 } | |
318 | |
319 // tagCachePath returns path to a tag cache file or "" if no root dir. | |
320 func (client *clientImpl) tagCachePath() string { | |
321 » if client.Root == "" { | |
322 » » return "" | |
323 » } | |
324 » return filepath.Join(client.Root, local.SiteServiceDir, "tagcache.db") | |
325 } | |
326 | |
327 // getTagCache lazy-initializes tagCache instance and returns it. | |
328 func (client *clientImpl) getTagCache() internal.TagCache { | |
329 » client.lock.Lock() | |
330 » defer client.lock.Unlock() | |
331 » if client.tagCache == nil { | |
332 » » if path := client.tagCachePath(); path != "" { | |
333 » » » var err error | |
334 » » » client.tagCache, err = internal.LoadTagCacheFromFile(pat h) | |
335 » » » if err != nil { | |
336 » » » » client.Logger.Warningf("cipd: failed to load tag cache - %s", err) | |
337 » » » » client.tagCache = internal.NewTagCache() | |
nodir
2015/09/30 19:08:23
remove this
Vadim Sh.
2015/09/30 22:50:59
Done.
| |
338 » » » } | |
339 » » } else { | |
340 » » » client.tagCache = internal.NewTagCache() | |
nodir
2015/09/30 19:08:23
remove this
Vadim Sh.
2015/09/30 22:50:58
Done.
| |
280 } | 341 } |
281 } | 342 } |
nodir
2015/09/30 19:08:23
add
if client.tagCache == nil {
client.TagCach
Vadim Sh.
2015/09/30 22:50:58
Done.
| |
282 » return client.anonClient.Do(req) | 343 » return client.tagCache |
344 } | |
345 | |
346 // closeTagCache dumps any changes made to tag cache to disk, if necessary. | |
347 // Called under lock. | |
tandrii(chromium)
2015/09/30 18:11:15
nit suggestion: s/.../Must be called under lock.
Vadim Sh.
2015/09/30 22:50:59
Done. Whatever.
| |
348 func (client *clientImpl) closeTagCache() { | |
349 » path := client.tagCachePath() | |
350 » if client.tagCache == nil || path == "" || !client.tagCache.Dirty() { | |
351 » » client.tagCache = nil | |
352 » » return | |
353 » } | |
354 » //It's tiny in size (and protobuf can't serialize to io.Reader anyway). Then | |
tandrii(chromium)
2015/09/30 18:11:15
nit: space between // and It
nit: s/Then/So,
Vadim Sh.
2015/09/30 22:50:59
Done.
| |
355 » // dump it to disk via FileSystem object to deal with possible concurren t | |
356 » // updates, missing directories, etc. | |
357 » fs := local.NewFileSystem(filepath.Dir(path), client.Logger) | |
358 » out, err := client.tagCache.Save() | |
359 » if err == nil { | |
360 » » err = fs.EnsureFile(path, out, 0666) | |
361 » } | |
362 » if err != nil { | |
363 » » client.Logger.Warningf("cipd: failed to update tag cache - %s", err) | |
364 » } | |
365 » client.tagCache = nil | |
283 } | 366 } |
284 | 367 |
285 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { | 368 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { |
286 return client.remote.fetchACL(packagePath) | 369 return client.remote.fetchACL(packagePath) |
287 } | 370 } |
288 | 371 |
289 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error { | 372 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error { |
290 return client.remote.modifyACL(packagePath, changes) | 373 return client.remote.modifyACL(packagePath, changes) |
291 } | 374 } |
292 | 375 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
361 if err := common.ValidatePackageName(packageName); err != nil { | 444 if err := common.ValidatePackageName(packageName); err != nil { |
362 return common.Pin{}, err | 445 return common.Pin{}, err |
363 } | 446 } |
364 // Is it instance ID already? Don't bother calling the backend. | 447 // Is it instance ID already? Don't bother calling the backend. |
365 if common.ValidateInstanceID(version) == nil { | 448 if common.ValidateInstanceID(version) == nil { |
366 return common.Pin{PackageName: packageName, InstanceID: version} , nil | 449 return common.Pin{PackageName: packageName, InstanceID: version} , nil |
367 } | 450 } |
368 if err := common.ValidateInstanceVersion(version); err != nil { | 451 if err := common.ValidateInstanceVersion(version); err != nil { |
369 return common.Pin{}, err | 452 return common.Pin{}, err |
370 } | 453 } |
371 » return client.remote.resolveVersion(packageName, version) | 454 » // Use local cache when resolving tags to avoid round trips to backed wh en |
tandrii(chromium)
2015/09/30 18:11:15
s/backed/backend
Vadim Sh.
2015/09/30 22:50:59
Done.
| |
455 » // calling same 'cipd ensure' command again and again. | |
456 » isTag := common.ValidateInstanceTag(version) == nil | |
457 » if isTag { | |
458 » » cached := client.getTagCache().ResolveTag(packageName, version) | |
459 » » if cached.InstanceID != "" { | |
460 » » » return cached, nil | |
461 » » } | |
462 » } | |
463 » pin, err := client.remote.resolveVersion(packageName, version) | |
464 » if err != nil { | |
465 » » return pin, err | |
466 » } | |
467 » if isTag { | |
468 » » client.getTagCache().AddTag(pin, version) | |
469 » } | |
470 » return pin, nil | |
372 } | 471 } |
373 | 472 |
374 func (client *clientImpl) RegisterInstance(instance local.PackageInstance) error { | 473 func (client *clientImpl) RegisterInstance(instance local.PackageInstance) error { |
375 // Attempt to register. | 474 // Attempt to register. |
376 client.Logger.Infof("cipd: registering %s", instance.Pin()) | 475 client.Logger.Infof("cipd: registering %s", instance.Pin()) |
377 result, err := client.remote.registerInstance(instance.Pin()) | 476 result, err := client.remote.registerInstance(instance.Pin()) |
378 if err != nil { | 477 if err != nil { |
379 return err | 478 return err |
380 } | 479 } |
381 | 480 |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
622 } | 721 } |
623 } | 722 } |
624 | 723 |
625 if !fail { | 724 if !fail { |
626 client.Logger.Infof("All changes applied.") | 725 client.Logger.Infof("All changes applied.") |
627 return nil | 726 return nil |
628 } | 727 } |
629 return ErrEnsurePackagesFailed | 728 return ErrEnsurePackagesFailed |
630 } | 729 } |
631 | 730 |
731 func (client *clientImpl) Close() { | |
732 client.lock.Lock() | |
733 defer client.lock.Unlock() | |
734 client.closeTagCache() | |
735 client.authClient = nil | |
736 client.anonClient = nil | |
737 } | |
738 | |
632 //////////////////////////////////////////////////////////////////////////////// | 739 //////////////////////////////////////////////////////////////////////////////// |
633 // Private structs and interfaces. | 740 // Private structs and interfaces. |
634 | 741 |
635 type clock interface { | 742 type clock interface { |
636 now() time.Time | 743 now() time.Time |
637 sleep(time.Duration) | 744 sleep(time.Duration) |
638 } | 745 } |
639 | 746 |
640 type remote interface { | 747 type remote interface { |
641 fetchACL(packagePath string) ([]PackageACL, error) | 748 fetchACL(packagePath string) ([]PackageACL, error) |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 } | 808 } |
702 | 809 |
703 // buildInstanceIDMap builds mapping {package name -> instance ID}. | 810 // buildInstanceIDMap builds mapping {package name -> instance ID}. |
704 func buildInstanceIDMap(pins []common.Pin) map[string]string { | 811 func buildInstanceIDMap(pins []common.Pin) map[string]string { |
705 out := map[string]string{} | 812 out := map[string]string{} |
706 for _, p := range pins { | 813 for _, p := range pins { |
707 out[p.PackageName] = p.InstanceID | 814 out[p.PackageName] = p.InstanceID |
708 } | 815 } |
709 return out | 816 return out |
710 } | 817 } |
OLD | NEW |