pull_v2.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. package distribution
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "runtime"
  10. "github.com/Sirupsen/logrus"
  11. "github.com/docker/distribution"
  12. "github.com/docker/distribution/digest"
  13. "github.com/docker/distribution/manifest/manifestlist"
  14. "github.com/docker/distribution/manifest/schema1"
  15. "github.com/docker/distribution/manifest/schema2"
  16. "github.com/docker/distribution/registry/api/errcode"
  17. "github.com/docker/distribution/registry/client"
  18. "github.com/docker/docker/distribution/metadata"
  19. "github.com/docker/docker/distribution/xfer"
  20. "github.com/docker/docker/image"
  21. "github.com/docker/docker/image/v1"
  22. "github.com/docker/docker/layer"
  23. "github.com/docker/docker/pkg/ioutils"
  24. "github.com/docker/docker/pkg/progress"
  25. "github.com/docker/docker/pkg/stringid"
  26. "github.com/docker/docker/reference"
  27. "github.com/docker/docker/registry"
  28. "golang.org/x/net/context"
  29. )
  30. var errRootFSMismatch = errors.New("layers from manifest don't match image configuration")
  31. type v2Puller struct {
  32. V2MetadataService *metadata.V2MetadataService
  33. endpoint registry.APIEndpoint
  34. config *ImagePullConfig
  35. repoInfo *registry.RepositoryInfo
  36. repo distribution.Repository
  37. // confirmedV2 is set to true if we confirm we're talking to a v2
  38. // registry. This is used to limit fallbacks to the v1 protocol.
  39. confirmedV2 bool
  40. }
  41. func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (err error) {
  42. // TODO(tiborvass): was ReceiveTimeout
  43. p.repo, p.confirmedV2, err = NewV2Repository(ctx, p.repoInfo, p.endpoint, p.config.MetaHeaders, p.config.AuthConfig, "pull")
  44. if err != nil {
  45. logrus.Warnf("Error getting v2 registry: %v", err)
  46. return fallbackError{err: err, confirmedV2: p.confirmedV2}
  47. }
  48. if err = p.pullV2Repository(ctx, ref); err != nil {
  49. if _, ok := err.(fallbackError); ok {
  50. return err
  51. }
  52. if registry.ContinueOnError(err) {
  53. logrus.Debugf("Error trying v2 registry: %v", err)
  54. return fallbackError{err: err, confirmedV2: p.confirmedV2}
  55. }
  56. }
  57. return err
  58. }
  59. func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) {
  60. var layersDownloaded bool
  61. if !reference.IsNameOnly(ref) {
  62. layersDownloaded, err = p.pullV2Tag(ctx, ref)
  63. if err != nil {
  64. return err
  65. }
  66. } else {
  67. tags, err := p.repo.Tags(ctx).All(ctx)
  68. if err != nil {
  69. // If this repository doesn't exist on V2, we should
  70. // permit a fallback to V1.
  71. return allowV1Fallback(err)
  72. }
  73. // The v2 registry knows about this repository, so we will not
  74. // allow fallback to the v1 protocol even if we encounter an
  75. // error later on.
  76. p.confirmedV2 = true
  77. for _, tag := range tags {
  78. tagRef, err := reference.WithTag(ref, tag)
  79. if err != nil {
  80. return err
  81. }
  82. pulledNew, err := p.pullV2Tag(ctx, tagRef)
  83. if err != nil {
  84. // Since this is the pull-all-tags case, don't
  85. // allow an error pulling a particular tag to
  86. // make the whole pull fall back to v1.
  87. if fallbackErr, ok := err.(fallbackError); ok {
  88. return fallbackErr.err
  89. }
  90. return err
  91. }
  92. // pulledNew is true if either new layers were downloaded OR if existing images were newly tagged
  93. // TODO(tiborvass): should we change the name of `layersDownload`? What about message in WriteStatus?
  94. layersDownloaded = layersDownloaded || pulledNew
  95. }
  96. }
  97. writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
  98. return nil
  99. }
  100. type v2LayerDescriptor struct {
  101. digest digest.Digest
  102. repoInfo *registry.RepositoryInfo
  103. repo distribution.Repository
  104. V2MetadataService *metadata.V2MetadataService
  105. tmpFile *os.File
  106. }
  107. func (ld *v2LayerDescriptor) Key() string {
  108. return "v2:" + ld.digest.String()
  109. }
  110. func (ld *v2LayerDescriptor) ID() string {
  111. return stringid.TruncateID(ld.digest.String())
  112. }
  113. func (ld *v2LayerDescriptor) DiffID() (layer.DiffID, error) {
  114. return ld.V2MetadataService.GetDiffID(ld.digest)
  115. }
  116. func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progress.Output) (io.ReadCloser, int64, error) {
  117. logrus.Debugf("pulling blob %q", ld.digest)
  118. var err error
  119. if ld.tmpFile == nil {
  120. ld.tmpFile, err = createDownloadFile()
  121. } else {
  122. _, err = ld.tmpFile.Seek(0, os.SEEK_SET)
  123. }
  124. if err != nil {
  125. return nil, 0, xfer.DoNotRetry{Err: err}
  126. }
  127. tmpFile := ld.tmpFile
  128. blobs := ld.repo.Blobs(ctx)
  129. layerDownload, err := blobs.Open(ctx, ld.digest)
  130. if err != nil {
  131. logrus.Debugf("Error statting layer: %v", err)
  132. if err == distribution.ErrBlobUnknown {
  133. return nil, 0, xfer.DoNotRetry{Err: err}
  134. }
  135. return nil, 0, retryOnError(err)
  136. }
  137. size, err := layerDownload.Seek(0, os.SEEK_END)
  138. if err != nil {
  139. // Seek failed, perhaps because there was no Content-Length
  140. // header. This shouldn't fail the download, because we can
  141. // still continue without a progress bar.
  142. size = 0
  143. } else {
  144. // Restore the seek offset at the beginning of the stream.
  145. _, err = layerDownload.Seek(0, os.SEEK_SET)
  146. if err != nil {
  147. return nil, 0, err
  148. }
  149. }
  150. reader := progress.NewProgressReader(ioutils.NewCancelReadCloser(ctx, layerDownload), progressOutput, size, ld.ID(), "Downloading")
  151. defer reader.Close()
  152. verifier, err := digest.NewDigestVerifier(ld.digest)
  153. if err != nil {
  154. return nil, 0, xfer.DoNotRetry{Err: err}
  155. }
  156. _, err = io.Copy(tmpFile, io.TeeReader(reader, verifier))
  157. if err != nil {
  158. tmpFile.Close()
  159. if err := os.Remove(tmpFile.Name()); err != nil {
  160. logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
  161. }
  162. ld.tmpFile = nil
  163. return nil, 0, retryOnError(err)
  164. }
  165. progress.Update(progressOutput, ld.ID(), "Verifying Checksum")
  166. if !verifier.Verified() {
  167. err = fmt.Errorf("filesystem layer verification failed for digest %s", ld.digest)
  168. logrus.Error(err)
  169. tmpFile.Close()
  170. if err := os.Remove(tmpFile.Name()); err != nil {
  171. logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
  172. }
  173. ld.tmpFile = nil
  174. return nil, 0, xfer.DoNotRetry{Err: err}
  175. }
  176. progress.Update(progressOutput, ld.ID(), "Download complete")
  177. logrus.Debugf("Downloaded %s to tempfile %s", ld.ID(), tmpFile.Name())
  178. _, err = tmpFile.Seek(0, os.SEEK_SET)
  179. if err != nil {
  180. tmpFile.Close()
  181. if err := os.Remove(tmpFile.Name()); err != nil {
  182. logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
  183. }
  184. ld.tmpFile = nil
  185. return nil, 0, xfer.DoNotRetry{Err: err}
  186. }
  187. return tmpFile, size, nil
  188. }
  189. func (ld *v2LayerDescriptor) Close() {
  190. if ld.tmpFile != nil {
  191. ld.tmpFile.Close()
  192. if err := os.RemoveAll(ld.tmpFile.Name()); err != nil {
  193. logrus.Errorf("Failed to remove temp file: %s", ld.tmpFile.Name())
  194. }
  195. }
  196. }
  197. func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
  198. // Cache mapping from this layer's DiffID to the blobsum
  199. ld.V2MetadataService.Add(diffID, metadata.V2Metadata{Digest: ld.digest, SourceRepository: ld.repoInfo.FullName()})
  200. }
  201. func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
  202. manSvc, err := p.repo.Manifests(ctx)
  203. if err != nil {
  204. return false, err
  205. }
  206. var (
  207. manifest distribution.Manifest
  208. tagOrDigest string // Used for logging/progress only
  209. )
  210. if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
  211. // NOTE: not using TagService.Get, since it uses HEAD requests
  212. // against the manifests endpoint, which are not supported by
  213. // all registry versions.
  214. manifest, err = manSvc.Get(ctx, "", client.WithTag(tagged.Tag()))
  215. if err != nil {
  216. return false, allowV1Fallback(err)
  217. }
  218. tagOrDigest = tagged.Tag()
  219. } else if digested, isDigested := ref.(reference.Canonical); isDigested {
  220. manifest, err = manSvc.Get(ctx, digested.Digest())
  221. if err != nil {
  222. return false, err
  223. }
  224. tagOrDigest = digested.Digest().String()
  225. } else {
  226. return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
  227. }
  228. if manifest == nil {
  229. return false, fmt.Errorf("image manifest does not exist for tag or digest %q", tagOrDigest)
  230. }
  231. // If manSvc.Get succeeded, we can be confident that the registry on
  232. // the other side speaks the v2 protocol.
  233. p.confirmedV2 = true
  234. logrus.Debugf("Pulling ref from V2 registry: %s", ref.String())
  235. progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+p.repo.Named().Name())
  236. var (
  237. imageID image.ID
  238. manifestDigest digest.Digest
  239. )
  240. switch v := manifest.(type) {
  241. case *schema1.SignedManifest:
  242. imageID, manifestDigest, err = p.pullSchema1(ctx, ref, v)
  243. if err != nil {
  244. return false, err
  245. }
  246. case *schema2.DeserializedManifest:
  247. imageID, manifestDigest, err = p.pullSchema2(ctx, ref, v)
  248. if err != nil {
  249. return false, err
  250. }
  251. case *manifestlist.DeserializedManifestList:
  252. imageID, manifestDigest, err = p.pullManifestList(ctx, ref, v)
  253. if err != nil {
  254. return false, err
  255. }
  256. default:
  257. return false, errors.New("unsupported manifest format")
  258. }
  259. progress.Message(p.config.ProgressOutput, "", "Digest: "+manifestDigest.String())
  260. oldTagImageID, err := p.config.ReferenceStore.Get(ref)
  261. if err == nil {
  262. if oldTagImageID == imageID {
  263. return false, nil
  264. }
  265. } else if err != reference.ErrDoesNotExist {
  266. return false, err
  267. }
  268. if canonical, ok := ref.(reference.Canonical); ok {
  269. if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
  270. return false, err
  271. }
  272. } else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil {
  273. return false, err
  274. }
  275. return true, nil
  276. }
  277. func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Named, unverifiedManifest *schema1.SignedManifest) (imageID image.ID, manifestDigest digest.Digest, err error) {
  278. var verifiedManifest *schema1.Manifest
  279. verifiedManifest, err = verifySchema1Manifest(unverifiedManifest, ref)
  280. if err != nil {
  281. return "", "", err
  282. }
  283. rootFS := image.NewRootFS()
  284. if err := detectBaseLayer(p.config.ImageStore, verifiedManifest, rootFS); err != nil {
  285. return "", "", err
  286. }
  287. // remove duplicate layers and check parent chain validity
  288. err = fixManifestLayers(verifiedManifest)
  289. if err != nil {
  290. return "", "", err
  291. }
  292. var descriptors []xfer.DownloadDescriptor
  293. // Image history converted to the new format
  294. var history []image.History
  295. // Note that the order of this loop is in the direction of bottom-most
  296. // to top-most, so that the downloads slice gets ordered correctly.
  297. for i := len(verifiedManifest.FSLayers) - 1; i >= 0; i-- {
  298. blobSum := verifiedManifest.FSLayers[i].BlobSum
  299. var throwAway struct {
  300. ThrowAway bool `json:"throwaway,omitempty"`
  301. }
  302. if err := json.Unmarshal([]byte(verifiedManifest.History[i].V1Compatibility), &throwAway); err != nil {
  303. return "", "", err
  304. }
  305. h, err := v1.HistoryFromConfig([]byte(verifiedManifest.History[i].V1Compatibility), throwAway.ThrowAway)
  306. if err != nil {
  307. return "", "", err
  308. }
  309. history = append(history, h)
  310. if throwAway.ThrowAway {
  311. continue
  312. }
  313. layerDescriptor := &v2LayerDescriptor{
  314. digest: blobSum,
  315. repoInfo: p.repoInfo,
  316. repo: p.repo,
  317. V2MetadataService: p.V2MetadataService,
  318. }
  319. descriptors = append(descriptors, layerDescriptor)
  320. }
  321. resultRootFS, release, err := p.config.DownloadManager.Download(ctx, *rootFS, descriptors, p.config.ProgressOutput)
  322. if err != nil {
  323. return "", "", err
  324. }
  325. defer release()
  326. config, err := v1.MakeConfigFromV1Config([]byte(verifiedManifest.History[0].V1Compatibility), &resultRootFS, history)
  327. if err != nil {
  328. return "", "", err
  329. }
  330. imageID, err = p.config.ImageStore.Create(config)
  331. if err != nil {
  332. return "", "", err
  333. }
  334. manifestDigest = digest.FromBytes(unverifiedManifest.Canonical)
  335. return imageID, manifestDigest, nil
  336. }
  337. func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *schema2.DeserializedManifest) (imageID image.ID, manifestDigest digest.Digest, err error) {
  338. manifestDigest, err = schema2ManifestDigest(ref, mfst)
  339. if err != nil {
  340. return "", "", err
  341. }
  342. target := mfst.Target()
  343. imageID = image.ID(target.Digest)
  344. if _, err := p.config.ImageStore.Get(imageID); err == nil {
  345. // If the image already exists locally, no need to pull
  346. // anything.
  347. return imageID, manifestDigest, nil
  348. }
  349. configChan := make(chan []byte, 1)
  350. errChan := make(chan error, 1)
  351. var cancel func()
  352. ctx, cancel = context.WithCancel(ctx)
  353. // Pull the image config
  354. go func() {
  355. configJSON, err := p.pullSchema2ImageConfig(ctx, target.Digest)
  356. if err != nil {
  357. errChan <- err
  358. cancel()
  359. return
  360. }
  361. configChan <- configJSON
  362. }()
  363. var descriptors []xfer.DownloadDescriptor
  364. // Note that the order of this loop is in the direction of bottom-most
  365. // to top-most, so that the downloads slice gets ordered correctly.
  366. for _, d := range mfst.References() {
  367. layerDescriptor := &v2LayerDescriptor{
  368. digest: d.Digest,
  369. repo: p.repo,
  370. repoInfo: p.repoInfo,
  371. V2MetadataService: p.V2MetadataService,
  372. }
  373. descriptors = append(descriptors, layerDescriptor)
  374. }
  375. var (
  376. configJSON []byte // raw serialized image config
  377. unmarshalledConfig image.Image // deserialized image config
  378. downloadRootFS image.RootFS // rootFS to use for registering layers.
  379. )
  380. if runtime.GOOS == "windows" {
  381. configJSON, unmarshalledConfig, err = receiveConfig(configChan, errChan)
  382. if err != nil {
  383. return "", "", err
  384. }
  385. if unmarshalledConfig.RootFS == nil {
  386. return "", "", errors.New("image config has no rootfs section")
  387. }
  388. downloadRootFS = *unmarshalledConfig.RootFS
  389. downloadRootFS.DiffIDs = []layer.DiffID{}
  390. } else {
  391. downloadRootFS = *image.NewRootFS()
  392. }
  393. rootFS, release, err := p.config.DownloadManager.Download(ctx, downloadRootFS, descriptors, p.config.ProgressOutput)
  394. if err != nil {
  395. if configJSON != nil {
  396. // Already received the config
  397. return "", "", err
  398. }
  399. select {
  400. case err = <-errChan:
  401. return "", "", err
  402. default:
  403. cancel()
  404. select {
  405. case <-configChan:
  406. case <-errChan:
  407. }
  408. return "", "", err
  409. }
  410. }
  411. defer release()
  412. if configJSON == nil {
  413. configJSON, unmarshalledConfig, err = receiveConfig(configChan, errChan)
  414. if err != nil {
  415. return "", "", err
  416. }
  417. }
  418. // The DiffIDs returned in rootFS MUST match those in the config.
  419. // Otherwise the image config could be referencing layers that aren't
  420. // included in the manifest.
  421. if len(rootFS.DiffIDs) != len(unmarshalledConfig.RootFS.DiffIDs) {
  422. return "", "", errRootFSMismatch
  423. }
  424. for i := range rootFS.DiffIDs {
  425. if rootFS.DiffIDs[i] != unmarshalledConfig.RootFS.DiffIDs[i] {
  426. return "", "", errRootFSMismatch
  427. }
  428. }
  429. imageID, err = p.config.ImageStore.Create(configJSON)
  430. if err != nil {
  431. return "", "", err
  432. }
  433. return imageID, manifestDigest, nil
  434. }
  435. func receiveConfig(configChan <-chan []byte, errChan <-chan error) ([]byte, image.Image, error) {
  436. select {
  437. case configJSON := <-configChan:
  438. var unmarshalledConfig image.Image
  439. if err := json.Unmarshal(configJSON, &unmarshalledConfig); err != nil {
  440. return nil, image.Image{}, err
  441. }
  442. return configJSON, unmarshalledConfig, nil
  443. case err := <-errChan:
  444. return nil, image.Image{}, err
  445. // Don't need a case for ctx.Done in the select because cancellation
  446. // will trigger an error in p.pullSchema2ImageConfig.
  447. }
  448. }
  449. // pullManifestList handles "manifest lists" which point to various
  450. // platform-specifc manifests.
  451. func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mfstList *manifestlist.DeserializedManifestList) (imageID image.ID, manifestListDigest digest.Digest, err error) {
  452. manifestListDigest, err = schema2ManifestDigest(ref, mfstList)
  453. if err != nil {
  454. return "", "", err
  455. }
  456. var manifestDigest digest.Digest
  457. for _, manifestDescriptor := range mfstList.Manifests {
  458. // TODO(aaronl): The manifest list spec supports optional
  459. // "features" and "variant" fields. These are not yet used.
  460. // Once they are, their values should be interpreted here.
  461. if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == runtime.GOOS {
  462. manifestDigest = manifestDescriptor.Digest
  463. break
  464. }
  465. }
  466. if manifestDigest == "" {
  467. return "", "", errors.New("no supported platform found in manifest list")
  468. }
  469. manSvc, err := p.repo.Manifests(ctx)
  470. if err != nil {
  471. return "", "", err
  472. }
  473. manifest, err := manSvc.Get(ctx, manifestDigest)
  474. if err != nil {
  475. return "", "", err
  476. }
  477. manifestRef, err := reference.WithDigest(ref, manifestDigest)
  478. if err != nil {
  479. return "", "", err
  480. }
  481. switch v := manifest.(type) {
  482. case *schema1.SignedManifest:
  483. imageID, _, err = p.pullSchema1(ctx, manifestRef, v)
  484. if err != nil {
  485. return "", "", err
  486. }
  487. case *schema2.DeserializedManifest:
  488. imageID, _, err = p.pullSchema2(ctx, manifestRef, v)
  489. if err != nil {
  490. return "", "", err
  491. }
  492. default:
  493. return "", "", errors.New("unsupported manifest format")
  494. }
  495. return imageID, manifestListDigest, err
  496. }
  497. func (p *v2Puller) pullSchema2ImageConfig(ctx context.Context, dgst digest.Digest) (configJSON []byte, err error) {
  498. blobs := p.repo.Blobs(ctx)
  499. configJSON, err = blobs.Get(ctx, dgst)
  500. if err != nil {
  501. return nil, err
  502. }
  503. // Verify image config digest
  504. verifier, err := digest.NewDigestVerifier(dgst)
  505. if err != nil {
  506. return nil, err
  507. }
  508. if _, err := verifier.Write(configJSON); err != nil {
  509. return nil, err
  510. }
  511. if !verifier.Verified() {
  512. err := fmt.Errorf("image config verification failed for digest %s", dgst)
  513. logrus.Error(err)
  514. return nil, err
  515. }
  516. return configJSON, nil
  517. }
  518. // schema2ManifestDigest computes the manifest digest, and, if pulling by
  519. // digest, ensures that it matches the requested digest.
  520. func schema2ManifestDigest(ref reference.Named, mfst distribution.Manifest) (digest.Digest, error) {
  521. _, canonical, err := mfst.Payload()
  522. if err != nil {
  523. return "", err
  524. }
  525. // If pull by digest, then verify the manifest digest.
  526. if digested, isDigested := ref.(reference.Canonical); isDigested {
  527. verifier, err := digest.NewDigestVerifier(digested.Digest())
  528. if err != nil {
  529. return "", err
  530. }
  531. if _, err := verifier.Write(canonical); err != nil {
  532. return "", err
  533. }
  534. if !verifier.Verified() {
  535. err := fmt.Errorf("manifest verification failed for digest %s", digested.Digest())
  536. logrus.Error(err)
  537. return "", err
  538. }
  539. return digested.Digest(), nil
  540. }
  541. return digest.FromBytes(canonical), nil
  542. }
  543. // allowV1Fallback checks if the error is a possible reason to fallback to v1
  544. // (even if confirmedV2 has been set already), and if so, wraps the error in
  545. // a fallbackError with confirmedV2 set to false. Otherwise, it returns the
  546. // error unmodified.
  547. func allowV1Fallback(err error) error {
  548. switch v := err.(type) {
  549. case errcode.Errors:
  550. if len(v) != 0 {
  551. if v0, ok := v[0].(errcode.Error); ok && registry.ShouldV2Fallback(v0) {
  552. return fallbackError{err: err, confirmedV2: false}
  553. }
  554. }
  555. case errcode.Error:
  556. if registry.ShouldV2Fallback(v) {
  557. return fallbackError{err: err, confirmedV2: false}
  558. }
  559. }
  560. return err
  561. }
  562. func verifySchema1Manifest(signedManifest *schema1.SignedManifest, ref reference.Named) (m *schema1.Manifest, err error) {
  563. // If pull by digest, then verify the manifest digest. NOTE: It is
  564. // important to do this first, before any other content validation. If the
  565. // digest cannot be verified, don't even bother with those other things.
  566. if digested, isCanonical := ref.(reference.Canonical); isCanonical {
  567. verifier, err := digest.NewDigestVerifier(digested.Digest())
  568. if err != nil {
  569. return nil, err
  570. }
  571. if _, err := verifier.Write(signedManifest.Canonical); err != nil {
  572. return nil, err
  573. }
  574. if !verifier.Verified() {
  575. err := fmt.Errorf("image verification failed for digest %s", digested.Digest())
  576. logrus.Error(err)
  577. return nil, err
  578. }
  579. }
  580. m = &signedManifest.Manifest
  581. if m.SchemaVersion != 1 {
  582. return nil, fmt.Errorf("unsupported schema version %d for %q", m.SchemaVersion, ref.String())
  583. }
  584. if len(m.FSLayers) != len(m.History) {
  585. return nil, fmt.Errorf("length of history not equal to number of layers for %q", ref.String())
  586. }
  587. if len(m.FSLayers) == 0 {
  588. return nil, fmt.Errorf("no FSLayers in manifest for %q", ref.String())
  589. }
  590. return m, nil
  591. }
  592. // fixManifestLayers removes repeated layers from the manifest and checks the
  593. // correctness of the parent chain.
  594. func fixManifestLayers(m *schema1.Manifest) error {
  595. imgs := make([]*image.V1Image, len(m.FSLayers))
  596. for i := range m.FSLayers {
  597. img := &image.V1Image{}
  598. if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), img); err != nil {
  599. return err
  600. }
  601. imgs[i] = img
  602. if err := v1.ValidateID(img.ID); err != nil {
  603. return err
  604. }
  605. }
  606. if imgs[len(imgs)-1].Parent != "" && runtime.GOOS != "windows" {
  607. // Windows base layer can point to a base layer parent that is not in manifest.
  608. return errors.New("Invalid parent ID in the base layer of the image.")
  609. }
  610. // check general duplicates to error instead of a deadlock
  611. idmap := make(map[string]struct{})
  612. var lastID string
  613. for _, img := range imgs {
  614. // skip IDs that appear after each other, we handle those later
  615. if _, exists := idmap[img.ID]; img.ID != lastID && exists {
  616. return fmt.Errorf("ID %+v appears multiple times in manifest", img.ID)
  617. }
  618. lastID = img.ID
  619. idmap[lastID] = struct{}{}
  620. }
  621. // backwards loop so that we keep the remaining indexes after removing items
  622. for i := len(imgs) - 2; i >= 0; i-- {
  623. if imgs[i].ID == imgs[i+1].ID { // repeated ID. remove and continue
  624. m.FSLayers = append(m.FSLayers[:i], m.FSLayers[i+1:]...)
  625. m.History = append(m.History[:i], m.History[i+1:]...)
  626. } else if imgs[i].Parent != imgs[i+1].ID {
  627. return fmt.Errorf("Invalid parent ID. Expected %v, got %v.", imgs[i+1].ID, imgs[i].Parent)
  628. }
  629. }
  630. return nil
  631. }
  632. func createDownloadFile() (*os.File, error) {
  633. return ioutil.TempFile("", "GetImageBlob")
  634. }