Chromium Code Reviews| 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 cipd implements client side of Chrome Infra Package Deployer. | 5 // Package cipd implements client side of Chrome Infra Package Deployer. |
| 6 // | 6 // |
| 7 // Binary package file format (in free form representation): | 7 // Binary package file format (in free form representation): |
| 8 // <binary package> := <zipped data> | 8 // <binary package> := <zipped data> |
| 9 // <zipped data> := DeterministicZip(<all input files> + <manifest json>) | 9 // <zipped data> := DeterministicZip(<all input files> + <manifest json>) |
| 10 // <manifest json> := File{ | 10 // <manifest json> := File{ |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 // instance sorted by tag key and creation timestamp (newest first). If 'tags' | 265 // instance sorted by tag key and creation timestamp (newest first). If 'tags' |
| 266 // is empty, fetches all attached tags, otherwise only ones specified. | 266 // is empty, fetches all attached tags, otherwise only ones specified. |
| 267 FetchInstanceTags(pin common.Pin, tags []string) ([]TagInfo, error) | 267 FetchInstanceTags(pin common.Pin, tags []string) ([]TagInfo, error) |
| 268 | 268 |
| 269 // FetchInstanceRefs returns information about refs pointing to the pack age | 269 // FetchInstanceRefs returns information about refs pointing to the pack age |
| 270 // instance sorted by modification timestamp (newest first). If 'ref' is | 270 // instance sorted by modification timestamp (newest first). If 'ref' is |
| 271 // empty, fetches all refs, otherwise only ones specified. | 271 // empty, fetches all refs, otherwise only ones specified. |
| 272 FetchInstanceRefs(pin common.Pin, refs []string) ([]RefInfo, error) | 272 FetchInstanceRefs(pin common.Pin, refs []string) ([]RefInfo, error) |
| 273 | 273 |
| 274 // FetchInstance downloads package instance file from the repository. | 274 // FetchInstance downloads package instance file from the repository. |
| 275 » FetchInstance(pin common.Pin, output io.WriteSeeker) error | 275 » FetchInstance(pin common.Pin, output io.ReadWriteSeeker) error |
| 276 | 276 |
| 277 // FetchAndDeployInstance fetches the package instance and deploys it in to | 277 // FetchAndDeployInstance fetches the package instance and deploys it in to |
| 278 // the site root. It doesn't check whether the instance is already deplo yed. | 278 // the site root. It doesn't check whether the instance is already deplo yed. |
| 279 FetchAndDeployInstance(pin common.Pin) error | 279 FetchAndDeployInstance(pin common.Pin) error |
| 280 | 280 |
| 281 // ListPackages returns a list of strings of package names. | 281 // ListPackages returns a list of strings of package names. |
| 282 ListPackages(path string, recursive bool) ([]string, error) | 282 ListPackages(path string, recursive bool) ([]string, error) |
| 283 | 283 |
| 284 // SearchInstances finds all instances with given tag and optionally nam e and | 284 // SearchInstances finds all instances with given tag and optionally nam e and |
| 285 // returns their concrete Pins. | 285 // returns their concrete Pins. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 // RPC requests. | 329 // RPC requests. |
| 330 AuthenticatedClientFactory HTTPClientFactory | 330 AuthenticatedClientFactory HTTPClientFactory |
| 331 | 331 |
| 332 // AnonymousClientFactory lazily creates http.Client to use for making | 332 // AnonymousClientFactory lazily creates http.Client to use for making |
| 333 // requests to storage. | 333 // requests to storage. |
| 334 AnonymousClientFactory HTTPClientFactory | 334 AnonymousClientFactory HTTPClientFactory |
| 335 | 335 |
| 336 // UserAgent is put into User-Agent HTTP header with each request. | 336 // UserAgent is put into User-Agent HTTP header with each request. |
| 337 UserAgent string | 337 UserAgent string |
| 338 | 338 |
| 339 » // CacheDir is a directory for shared cache. If empty, tags are cached | 339 » // CacheDir is a directory for shared cache. If empty, instances are not |
| 340 » // inside the site root. If both Root and CacheDir are empty, tag cache | 340 » // cached and tags are cached inside the site root. If both Root and |
| 341 » // is disabled. | 341 » // CacheDir are empty, tag cache is disabled. |
| 342 CacheDir string | 342 CacheDir string |
| 343 } | 343 } |
| 344 | 344 |
| 345 // NewClient initializes CIPD client object. | 345 // NewClient initializes CIPD client object. |
| 346 func NewClient(opts ClientOptions) Client { | 346 func NewClient(opts ClientOptions) Client { |
| 347 if opts.ServiceURL == "" { | 347 if opts.ServiceURL == "" { |
| 348 opts.ServiceURL = ServiceURL | 348 opts.ServiceURL = ServiceURL |
| 349 } | 349 } |
| 350 if opts.Logger == nil { | 350 if opts.Logger == nil { |
| 351 opts.Logger = logging.Null() | 351 opts.Logger = logging.Null() |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 386 storage storage | 386 storage storage |
| 387 | 387 |
| 388 // deployer knows how to install packages to local file system. Thread s afe. | 388 // deployer knows how to install packages to local file system. Thread s afe. |
| 389 deployer local.Deployer | 389 deployer local.Deployer |
| 390 | 390 |
| 391 // tagCache is used to cache (pkgname, tag) -> instanceID mapping. | 391 // tagCache is used to cache (pkgname, tag) -> instanceID mapping. |
| 392 // Thread safe, but lazily initialized under lock. | 392 // Thread safe, but lazily initialized under lock. |
| 393 tagCache *internal.TagCache | 393 tagCache *internal.TagCache |
| 394 tagCacheInit sync.Once | 394 tagCacheInit sync.Once |
| 395 | 395 |
| 396 // instanceCache is a file-system based cache of instances. | |
| 397 instanceCache *internal.InstanceCache | |
| 398 instanceCacheInit sync.Once | |
| 399 | |
| 396 // authClient is a lazily created http.Client to use for authenticated | 400 // authClient is a lazily created http.Client to use for authenticated |
| 397 // requests. Thread safe, but lazily initialized under lock. | 401 // requests. Thread safe, but lazily initialized under lock. |
| 398 authClient *http.Client | 402 authClient *http.Client |
| 399 | 403 |
| 400 // anonClient is a lazily created http.Client to use for anonymous reque sts. | 404 // anonClient is a lazily created http.Client to use for anonymous reque sts. |
| 401 // Thread safe, but lazily initialized under lock. | 405 // Thread safe, but lazily initialized under lock. |
| 402 anonClient *http.Client | 406 anonClient *http.Client |
| 403 } | 407 } |
| 404 | 408 |
| 405 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s. | 409 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 out, err := client.tagCache.Save() | 483 out, err := client.tagCache.Save() |
| 480 if err == nil { | 484 if err == nil { |
| 481 err = fs.EnsureFile(path, out, 0666) | 485 err = fs.EnsureFile(path, out, 0666) |
| 482 } | 486 } |
| 483 if err != nil { | 487 if err != nil { |
| 484 client.Logger.Warningf("cipd: failed to update tag cache - %s", err) | 488 client.Logger.Warningf("cipd: failed to update tag cache - %s", err) |
| 485 } | 489 } |
| 486 client.tagCache = nil | 490 client.tagCache = nil |
| 487 } | 491 } |
| 488 | 492 |
| 493 // instanceCachePath returns path to the instance cache directory or "" if | |
| 494 // instance cache is disabled. | |
| 495 func (client *clientImpl) instanceCachePath() string { | |
| 496 if client.CacheDir == "" { | |
| 497 return "" | |
| 498 } | |
| 499 return filepath.Join(client.CacheDir, "instances") | |
| 500 } | |
| 501 | |
| 502 // getInstanceCache lazy-initializes instanceCache and returns it. | |
| 503 func (client *clientImpl) getInstanceCache() *internal.InstanceCache { | |
| 504 client.instanceCacheInit.Do(func() { | |
| 505 if path := client.instanceCachePath(); path != "" { | |
| 506 cachePath := local.NewFileSystem(path, client.Logger) | |
| 507 client.instanceCache = internal.LoadInstanceCache(cacheP ath, client.Logger, client.clock.now()) | |
| 508 } | |
| 509 }) | |
| 510 return client.instanceCache | |
| 511 } | |
| 512 | |
| 513 // closeInstanceCache dumps any changes made to instance cache to disk, if neces sary. | |
| 514 func (client *clientImpl) closeInstanceCache() { | |
| 515 if client.instanceCache == nil || !client.instanceCache.Dirty() { | |
| 516 return | |
| 517 } | |
| 518 | |
| 519 if err := client.instanceCache.Save(); err != nil { | |
| 520 client.Logger.Warningf("cipd: failed to save instance cache - %s ", err) | |
| 521 } | |
| 522 client.instanceCache = nil | |
| 523 } | |
| 524 | |
| 489 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { | 525 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { |
| 490 return client.remote.fetchACL(packagePath) | 526 return client.remote.fetchACL(packagePath) |
| 491 } | 527 } |
| 492 | 528 |
| 493 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error { | 529 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error { |
| 494 return client.remote.modifyACL(packagePath, changes) | 530 return client.remote.modifyACL(packagePath, changes) |
| 495 } | 531 } |
| 496 | 532 |
| 497 func (client *clientImpl) ListPackages(path string, recursive bool) ([]string, e rror) { | 533 func (client *clientImpl) ListPackages(path string, recursive bool) ([]string, e rror) { |
| 498 pkgs, dirs, err := client.remote.listPackages(path, recursive) | 534 pkgs, dirs, err := client.remote.listPackages(path, recursive) |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 741 } | 777 } |
| 742 | 778 |
| 743 func (client *clientImpl) FetchInstanceRefs(pin common.Pin, refs []string) ([]Re fInfo, error) { | 779 func (client *clientImpl) FetchInstanceRefs(pin common.Pin, refs []string) ([]Re fInfo, error) { |
| 744 err := common.ValidatePin(pin) | 780 err := common.ValidatePin(pin) |
| 745 if err != nil { | 781 if err != nil { |
| 746 return nil, err | 782 return nil, err |
| 747 } | 783 } |
| 748 return client.remote.fetchRefs(pin, refs) | 784 return client.remote.fetchRefs(pin, refs) |
| 749 } | 785 } |
| 750 | 786 |
| 751 func (client *clientImpl) FetchInstance(pin common.Pin, output io.WriteSeeker) e rror { | 787 func (client *clientImpl) FetchInstance(pin common.Pin, output io.ReadWriteSeeke r) error { |
| 752 err := common.ValidatePin(pin) | 788 err := common.ValidatePin(pin) |
| 753 if err != nil { | 789 if err != nil { |
| 754 return err | 790 return err |
| 755 } | 791 } |
| 792 | |
| 793 now := client.clock.now() | |
| 794 | |
| 795 cache := client.getInstanceCache() | |
| 796 if cache != nil { | |
| 797 switch err := cache.Get(pin, output, now); { | |
| 798 case os.IsNotExist(err): | |
| 799 // output is not corrupted. | |
| 800 | |
| 801 case err != nil: | |
| 802 client.Logger.Warningf("cipd: could not get %s from cach e - %s", pin, err) | |
| 803 // Output may be corrupted. Rewinding back. | |
| 804 if _, err := output.Seek(0, 0); err != nil { | |
|
Vadim Sh.
2016/04/11 16:52:02
well, it may not be enough. We also need to trunca
nodir
2016/04/11 22:16:16
Done.
| |
| 805 return err | |
| 806 } | |
| 807 | |
| 808 default: | |
| 809 client.Logger.Infof("cipd: cache hit for %s", pin) | |
| 810 return nil | |
| 811 } | |
| 812 } | |
| 813 | |
| 756 client.Logger.Infof("cipd: resolving fetch URL for %s", pin) | 814 client.Logger.Infof("cipd: resolving fetch URL for %s", pin) |
| 757 fetchInfo, err := client.remote.fetchInstance(pin) | 815 fetchInfo, err := client.remote.fetchInstance(pin) |
| 758 » if err == nil { | 816 » if err != nil { |
| 759 » » err = client.storage.download(fetchInfo.fetchURL, output) | 817 » » goto fetchFail |
| 760 } | 818 } |
| 761 » if err != nil { | 819 |
| 762 » » client.Logger.Errorf("cipd: failed to fetch %s - %s", pin, err) | 820 » if err = client.storage.download(fetchInfo.fetchURL, output); err != nil { |
| 763 » » return err | 821 » » goto fetchFail |
| 764 } | 822 } |
| 823 | |
| 765 client.Logger.Infof("cipd: successfully fetched %s", pin) | 824 client.Logger.Infof("cipd: successfully fetched %s", pin) |
| 825 | |
| 826 if cache != nil { | |
| 827 if _, err := output.Seek(0, 0); err != nil { | |
|
Vadim Sh.
2016/04/11 16:52:02
It may be simpler to always download into cache, a
nodir
2016/04/11 22:16:16
Done.
| |
| 828 client.Logger.Warningf("cipd: could not seek output to t he beginning for caching - %s", err) | |
| 829 } else if err := cache.Put(pin, output, now); err != nil { | |
| 830 client.Logger.Warningf("cipd: could not cache %s - %s", pin, err) | |
| 831 } | |
| 832 } | |
| 833 | |
| 766 return nil | 834 return nil |
| 835 | |
| 836 fetchFail: | |
| 837 client.Logger.Errorf("cipd: failed to fetch %s - %s", pin, err) | |
| 838 return err | |
| 767 } | 839 } |
| 768 | 840 |
| 769 func (client *clientImpl) FetchAndDeployInstance(pin common.Pin) error { | 841 func (client *clientImpl) FetchAndDeployInstance(pin common.Pin) error { |
| 770 err := common.ValidatePin(pin) | 842 err := common.ValidatePin(pin) |
| 771 if err != nil { | 843 if err != nil { |
| 772 return err | 844 return err |
| 773 } | 845 } |
| 774 | 846 |
| 775 // Use temp file for storing package file. Delete it when done. | 847 // Use temp file for storing package file. Delete it when done. |
| 776 var instance local.PackageInstance | 848 var instance local.PackageInstance |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 941 client.Logger.Infof("All changes applied.") | 1013 client.Logger.Infof("All changes applied.") |
| 942 return actions, nil | 1014 return actions, nil |
| 943 } | 1015 } |
| 944 return actions, ErrEnsurePackagesFailed | 1016 return actions, ErrEnsurePackagesFailed |
| 945 } | 1017 } |
| 946 | 1018 |
| 947 func (client *clientImpl) Close() { | 1019 func (client *clientImpl) Close() { |
| 948 client.lock.Lock() | 1020 client.lock.Lock() |
| 949 defer client.lock.Unlock() | 1021 defer client.lock.Unlock() |
| 950 client.closeTagCache() | 1022 client.closeTagCache() |
| 1023 client.closeInstanceCache() | |
| 951 client.authClient = nil | 1024 client.authClient = nil |
| 952 client.anonClient = nil | 1025 client.anonClient = nil |
| 953 } | 1026 } |
| 954 | 1027 |
| 955 //////////////////////////////////////////////////////////////////////////////// | 1028 //////////////////////////////////////////////////////////////////////////////// |
| 956 // Private structs and interfaces. | 1029 // Private structs and interfaces. |
| 957 | 1030 |
| 958 type clock interface { | 1031 type clock interface { |
| 959 now() time.Time | 1032 now() time.Time |
| 960 sleep(time.Duration) | 1033 sleep(time.Duration) |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1032 } | 1105 } |
| 1033 | 1106 |
| 1034 // buildInstanceIDMap builds mapping {package name -> instance ID}. | 1107 // buildInstanceIDMap builds mapping {package name -> instance ID}. |
| 1035 func buildInstanceIDMap(pins []common.Pin) map[string]string { | 1108 func buildInstanceIDMap(pins []common.Pin) map[string]string { |
| 1036 out := map[string]string{} | 1109 out := map[string]string{} |
| 1037 for _, p := range pins { | 1110 for _, p := range pins { |
| 1038 out[p.PackageName] = p.InstanceID | 1111 out[p.PackageName] = p.InstanceID |
| 1039 } | 1112 } |
| 1040 return out | 1113 return out |
| 1041 } | 1114 } |
| OLD | NEW |