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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 // <package name> <desired version>. Whitespaces are ignored. Lines that
start | 191 // <package name> <desired version>. Whitespaces are ignored. Lines that
start |
189 // with '#' are ignored. Version can be specified as instance ID, tag or
ref. | 192 // with '#' are ignored. Version can be specified as instance ID, tag or
ref. |
190 // Will resolve tags and refs to concrete instance IDs by calling the ba
ckend. | 193 // Will resolve tags and refs to concrete instance IDs by calling the ba
ckend. |
191 ProcessEnsureFile(r io.Reader) ([]common.Pin, error) | 194 ProcessEnsureFile(r io.Reader) ([]common.Pin, error) |
192 | 195 |
193 // EnsurePackages is high-level interface for installation, removal and
update | 196 // EnsurePackages is high-level interface for installation, removal and
update |
194 // of packages inside the installation site root. Given a description of | 197 // of packages inside the installation site root. Given a description of |
195 // what packages (and versions) should be installed it will do all neces
sary | 198 // what packages (and versions) should be installed it will do all neces
sary |
196 // actions to bring the state of the site root to the desired one. | 199 // actions to bring the state of the site root to the desired one. |
197 EnsurePackages(pins []common.Pin) error | 200 EnsurePackages(pins []common.Pin) error |
| 201 |
| 202 // Close should be called to dump any cached state to disk. |
| 203 Close() |
198 } | 204 } |
199 | 205 |
200 // HTTPClientFactory lazily creates http.Client to use for making requests. | 206 // HTTPClientFactory lazily creates http.Client to use for making requests. |
201 type HTTPClientFactory func() (*http.Client, error) | 207 type HTTPClientFactory func() (*http.Client, error) |
202 | 208 |
203 // ClientOptions is passed to NewClient factory function. | 209 // ClientOptions is passed to NewClient factory function. |
204 type ClientOptions struct { | 210 type ClientOptions struct { |
205 // ServiceURL is root URL of the backend service. | 211 // ServiceURL is root URL of the backend service. |
206 ServiceURL string | 212 ServiceURL string |
207 » // Root is a site root directory (where packages will be installed). It
can | 213 |
208 » // be empty string if client is not going to be used to deploy or remove
local packages. | 214 » // Root is a site root directory (a directory where packages will be |
| 215 » // installed to). It also hosts .cipd/* directory that tracks internal s
tate |
| 216 » // of installed packages and keeps various cache files. 'Root' can be an
empty |
| 217 » // string if the client is not going to be used to deploy or remove loca
l |
| 218 » // packages. In that case caches are also disabled. |
209 Root string | 219 Root string |
| 220 |
210 // Logger is a logger to use for logs (null-logger by default). | 221 // Logger is a logger to use for logs (null-logger by default). |
211 Logger logging.Logger | 222 Logger logging.Logger |
212 » // AuthenticatedClientFactory lazily creates http.Client to use for maki
ng RPC requests. | 223 |
| 224 » // AuthenticatedClientFactory lazily creates http.Client to use for maki
ng |
| 225 » // RPC requests. |
213 AuthenticatedClientFactory HTTPClientFactory | 226 AuthenticatedClientFactory HTTPClientFactory |
214 » // AnonymousClientFactory lazily creates http.Client to use for making r
equests to storage. | 227 |
| 228 » // AnonymousClientFactory lazily creates http.Client to use for making |
| 229 » // requests to storage. |
215 AnonymousClientFactory HTTPClientFactory | 230 AnonymousClientFactory HTTPClientFactory |
| 231 |
216 // UserAgent is put into User-Agent HTTP header with each request. | 232 // UserAgent is put into User-Agent HTTP header with each request. |
217 UserAgent string | 233 UserAgent string |
218 } | 234 } |
219 | 235 |
220 // NewClient initializes CIPD client object. | 236 // NewClient initializes CIPD client object. |
221 func NewClient(opts ClientOptions) Client { | 237 func NewClient(opts ClientOptions) Client { |
222 if opts.ServiceURL == "" { | 238 if opts.ServiceURL == "" { |
223 opts.ServiceURL = ServiceURL | 239 opts.ServiceURL = ServiceURL |
224 } | 240 } |
225 if opts.Logger == nil { | 241 if opts.Logger == nil { |
(...skipping 14 matching lines...) Expand all Loading... |
240 } | 256 } |
241 c.remote = &remoteImpl{c} | 257 c.remote = &remoteImpl{c} |
242 c.storage = &storageImpl{c, uploadChunkSize} | 258 c.storage = &storageImpl{c, uploadChunkSize} |
243 c.deployer = local.NewDeployer(opts.Root, opts.Logger) | 259 c.deployer = local.NewDeployer(opts.Root, opts.Logger) |
244 return c | 260 return c |
245 } | 261 } |
246 | 262 |
247 type clientImpl struct { | 263 type clientImpl struct { |
248 ClientOptions | 264 ClientOptions |
249 | 265 |
250 » // clock provides current time and ability to sleep. | 266 » // lock protects lazily initialized portions of the client. |
| 267 » lock sync.Mutex |
| 268 |
| 269 » // clock provides current time and ability to sleep. Thread safe. |
251 clock clock | 270 clock clock |
252 » // remote knows how to call backend REST API. | 271 |
| 272 » // remote knows how to call backend REST API. Thread safe. |
253 remote remote | 273 remote remote |
| 274 |
254 // storage knows how to upload and download raw binaries using signed UR
Ls. | 275 // storage knows how to upload and download raw binaries using signed UR
Ls. |
| 276 // Thread safe. |
255 storage storage | 277 storage storage |
256 » // deployer knows how to install packages to local file system. | 278 |
| 279 » // deployer knows how to install packages to local file system. Thread s
afe. |
257 deployer local.Deployer | 280 deployer local.Deployer |
258 | 281 |
259 » // authClient is a lazily created http.Client to use for authenticated r
equests. | 282 » // tagCache is used to cache (pkgname, tag) -> instanceID mapping. |
| 283 » // Thread safe, but lazily initialized under lock. |
| 284 » tagCache *internal.TagCache |
| 285 |
| 286 » // authClient is a lazily created http.Client to use for authenticated |
| 287 » // requests. Thread safe, but lazily initialized under lock. |
260 authClient *http.Client | 288 authClient *http.Client |
| 289 |
261 // anonClient is a lazily created http.Client to use for anonymous reque
sts. | 290 // anonClient is a lazily created http.Client to use for anonymous reque
sts. |
| 291 // Thread safe, but lazily initialized under lock. |
262 anonClient *http.Client | 292 anonClient *http.Client |
263 } | 293 } |
264 | 294 |
265 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call
s. | 295 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call
s. |
266 func (client *clientImpl) doAuthenticatedHTTPRequest(req *http.Request) (*http.R
esponse, error) { | 296 func (client *clientImpl) doAuthenticatedHTTPRequest(req *http.Request) (*http.R
esponse, error) { |
267 » if client.authClient == nil { | 297 » return client.doRequest(req, &client.authClient, client.AuthenticatedCli
entFactory) |
268 » » var err error | |
269 » » client.authClient, err = client.AuthenticatedClientFactory() | |
270 » » if err != nil { | |
271 » » » return nil, err | |
272 » » } | |
273 » } | |
274 » return client.authClient.Do(req) | |
275 } | 298 } |
276 | 299 |
277 // doAnonymousHTTPRequest is used by storage implementation to make HTTP calls. | 300 // doAnonymousHTTPRequest is used by storage implementation to make HTTP calls. |
278 func (client *clientImpl) doAnonymousHTTPRequest(req *http.Request) (*http.Respo
nse, error) { | 301 func (client *clientImpl) doAnonymousHTTPRequest(req *http.Request) (*http.Respo
nse, error) { |
279 » if client.anonClient == nil { | 302 » return client.doRequest(req, &client.anonClient, client.AnonymousClientF
actory) |
| 303 } |
| 304 |
| 305 // doRequest lazy-initializes http.Client using provided factory and then |
| 306 // executes the request. |
| 307 func (client *clientImpl) doRequest(req *http.Request, c **http.Client, fac HTTP
ClientFactory) (*http.Response, error) { |
| 308 » httpClient, err := func() (*http.Client, error) { |
| 309 » » client.lock.Lock() |
| 310 » » defer client.lock.Unlock() |
280 var err error | 311 var err error |
281 » » client.anonClient, err = client.AnonymousClientFactory() | 312 » » if *c == nil { |
282 » » if err != nil { | 313 » » » *c, err = fac() |
283 » » » return nil, err | 314 » » } |
| 315 » » return *c, err |
| 316 » }() |
| 317 » if err != nil { |
| 318 » » return nil, err |
| 319 » } |
| 320 » return httpClient.Do(req) |
| 321 } |
| 322 |
| 323 // tagCachePath returns path to a tag cache file or "" if no root dir. |
| 324 func (client *clientImpl) tagCachePath() string { |
| 325 » if client.Root == "" { |
| 326 » » return "" |
| 327 » } |
| 328 » return filepath.Join(client.Root, local.SiteServiceDir, "tagcache.db") |
| 329 } |
| 330 |
| 331 // getTagCache lazy-initializes tagCache instance and returns it. |
| 332 func (client *clientImpl) getTagCache() *internal.TagCache { |
| 333 » client.lock.Lock() |
| 334 » defer client.lock.Unlock() |
| 335 » if client.tagCache == nil { |
| 336 » » if path := client.tagCachePath(); path != "" { |
| 337 » » » var err error |
| 338 » » » client.tagCache, err = internal.LoadTagCacheFromFile(pat
h) |
| 339 » » » if err != nil { |
| 340 » » » » client.Logger.Warningf("cipd: failed to load tag
cache - %s", err) |
| 341 » » » } |
| 342 » » } |
| 343 » » if client.tagCache == nil { |
| 344 » » » client.tagCache = &internal.TagCache{} |
284 } | 345 } |
285 } | 346 } |
286 » return client.anonClient.Do(req) | 347 » return client.tagCache |
| 348 } |
| 349 |
| 350 // closeTagCache dumps any changes made to tag cache to disk, if necessary. |
| 351 // Must be called under lock. |
| 352 func (client *clientImpl) closeTagCache() { |
| 353 » path := client.tagCachePath() |
| 354 » if client.tagCache == nil || path == "" || !client.tagCache.Dirty() { |
| 355 » » client.tagCache = nil |
| 356 » » return |
| 357 » } |
| 358 » // It's tiny in size (and protobuf can't serialize to io.Reader anyway).
Dump |
| 359 » // it to disk via FileSystem object to deal with possible concurrent upd
ates, |
| 360 » // missing directories, etc. |
| 361 » fs := local.NewFileSystem(filepath.Dir(path), client.Logger) |
| 362 » out, err := client.tagCache.Save() |
| 363 » if err == nil { |
| 364 » » err = fs.EnsureFile(path, out, 0666) |
| 365 » } |
| 366 » if err != nil { |
| 367 » » client.Logger.Warningf("cipd: failed to update tag cache - %s",
err) |
| 368 » } |
| 369 » client.tagCache = nil |
287 } | 370 } |
288 | 371 |
289 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { | 372 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { |
290 return client.remote.fetchACL(packagePath) | 373 return client.remote.fetchACL(packagePath) |
291 } | 374 } |
292 | 375 |
293 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan
ge) error { | 376 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan
ge) error { |
294 return client.remote.modifyACL(packagePath, changes) | 377 return client.remote.modifyACL(packagePath, changes) |
295 } | 378 } |
296 | 379 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 if err := common.ValidatePackageName(packageName); err != nil { | 448 if err := common.ValidatePackageName(packageName); err != nil { |
366 return common.Pin{}, err | 449 return common.Pin{}, err |
367 } | 450 } |
368 // Is it instance ID already? Don't bother calling the backend. | 451 // Is it instance ID already? Don't bother calling the backend. |
369 if common.ValidateInstanceID(version) == nil { | 452 if common.ValidateInstanceID(version) == nil { |
370 return common.Pin{PackageName: packageName, InstanceID: version}
, nil | 453 return common.Pin{PackageName: packageName, InstanceID: version}
, nil |
371 } | 454 } |
372 if err := common.ValidateInstanceVersion(version); err != nil { | 455 if err := common.ValidateInstanceVersion(version); err != nil { |
373 return common.Pin{}, err | 456 return common.Pin{}, err |
374 } | 457 } |
375 » return client.remote.resolveVersion(packageName, version) | 458 » // Use local cache when resolving tags to avoid round trips to backend w
hen |
| 459 » // calling same 'cipd ensure' command again and again. |
| 460 » isTag := common.ValidateInstanceTag(version) == nil |
| 461 » if isTag { |
| 462 » » cached := client.getTagCache().ResolveTag(packageName, version) |
| 463 » » if cached.InstanceID != "" { |
| 464 » » » return cached, nil |
| 465 » » } |
| 466 » } |
| 467 » pin, err := client.remote.resolveVersion(packageName, version) |
| 468 » if err != nil { |
| 469 » » return pin, err |
| 470 » } |
| 471 » if isTag { |
| 472 » » client.getTagCache().AddTag(pin, version) |
| 473 » } |
| 474 » return pin, nil |
376 } | 475 } |
377 | 476 |
378 func (client *clientImpl) RegisterInstance(instance local.PackageInstance) error
{ | 477 func (client *clientImpl) RegisterInstance(instance local.PackageInstance) error
{ |
379 // Attempt to register. | 478 // Attempt to register. |
380 client.Logger.Infof("cipd: registering %s", instance.Pin()) | 479 client.Logger.Infof("cipd: registering %s", instance.Pin()) |
381 result, err := client.remote.registerInstance(instance.Pin()) | 480 result, err := client.remote.registerInstance(instance.Pin()) |
382 if err != nil { | 481 if err != nil { |
383 return err | 482 return err |
384 } | 483 } |
385 | 484 |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 } | 735 } |
637 } | 736 } |
638 | 737 |
639 if !fail { | 738 if !fail { |
640 client.Logger.Infof("All changes applied.") | 739 client.Logger.Infof("All changes applied.") |
641 return nil | 740 return nil |
642 } | 741 } |
643 return ErrEnsurePackagesFailed | 742 return ErrEnsurePackagesFailed |
644 } | 743 } |
645 | 744 |
| 745 func (client *clientImpl) Close() { |
| 746 client.lock.Lock() |
| 747 defer client.lock.Unlock() |
| 748 client.closeTagCache() |
| 749 client.authClient = nil |
| 750 client.anonClient = nil |
| 751 } |
| 752 |
646 //////////////////////////////////////////////////////////////////////////////// | 753 //////////////////////////////////////////////////////////////////////////////// |
647 // Private structs and interfaces. | 754 // Private structs and interfaces. |
648 | 755 |
649 type clock interface { | 756 type clock interface { |
650 now() time.Time | 757 now() time.Time |
651 sleep(time.Duration) | 758 sleep(time.Duration) |
652 } | 759 } |
653 | 760 |
654 type remote interface { | 761 type remote interface { |
655 fetchACL(packagePath string) ([]PackageACL, error) | 762 fetchACL(packagePath string) ([]PackageACL, error) |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
716 } | 823 } |
717 | 824 |
718 // buildInstanceIDMap builds mapping {package name -> instance ID}. | 825 // buildInstanceIDMap builds mapping {package name -> instance ID}. |
719 func buildInstanceIDMap(pins []common.Pin) map[string]string { | 826 func buildInstanceIDMap(pins []common.Pin) map[string]string { |
720 out := map[string]string{} | 827 out := map[string]string{} |
721 for _, p := range pins { | 828 for _, p := range pins { |
722 out[p.PackageName] = p.InstanceID | 829 out[p.PackageName] = p.InstanceID |
723 } | 830 } |
724 return out | 831 return out |
725 } | 832 } |
OLD | NEW |