Exemple #1
0
        public void TestListDigests()
        {
            CacheStorageFiles cacheStorageFiles =
                new CacheStorageFiles(temporaryFolder.NewFolder().ToPath());

            CacheStorageReader cacheStorageReader = new CacheStorageReader(cacheStorageFiles);

            // Creates test layer directories.
            Files.CreateDirectories(cacheStorageFiles.GetLayersDirectory().Resolve(layerDigest1.GetHash()));
            Files.CreateDirectories(cacheStorageFiles.GetLayersDirectory().Resolve(layerDigest2.GetHash()));

            // Checks that layer directories created are all listed.
            Assert.AreEqual(
                new HashSet <DescriptorDigest>(new[] { layerDigest1, layerDigest2 }),
                cacheStorageReader.FetchDigests());

            // Checks that non-digest directories means the cache is corrupted.
            Files.CreateDirectory(cacheStorageFiles.GetLayersDirectory().Resolve("not a hash"));
            try
            {
                cacheStorageReader.FetchDigests();
                Assert.Fail("Listing digests should have failed");
            }
            catch (CacheCorruptedException ex)
            {
                Assert.That(
                    ex.Message, Does.StartWith("Found non-digest file in layers directory"));
                Assert.IsInstanceOf <DigestException>(ex.InnerException);
            }
        }
Exemple #2
0
        /**
         * Retrieves the {@link CachedLayer} for the layer with digest {@code layerDigest}.
         *
         * @param layerDigest the layer digest
         * @return the {@link CachedLayer} referenced by the layer digest, if found
         * @throws CacheCorruptedException if the cache was found to be corrupted
         * @throws IOException if an I/O exception occurs
         */
        public Maybe <CachedLayer> Retrieve(DescriptorDigest layerDigest)
        {
            layerDigest = layerDigest ?? throw new ArgumentNullException(nameof(layerDigest));
            SystemPath layerDirectory = cacheStorageFiles.GetLayerDirectory(layerDigest);

            if (!Files.Exists(layerDirectory))
            {
                return(Maybe.Empty <CachedLayer>());
            }

            CachedLayer.Builder cachedLayerBuilder = CachedLayer.CreateBuilder().SetLayerDigest(layerDigest);

            foreach (SystemPath fileInLayerDirectory in Files.List(layerDirectory))
            {
                if (CacheStorageFiles.IsLayerFile(fileInLayerDirectory))
                {
                    if (cachedLayerBuilder.HasLayerBlob())
                    {
                        throw new CacheCorruptedException(
                                  cacheStorageFiles.GetCacheDirectory(),
                                  "Multiple layer files found for layer with digest "
                                  + layerDigest.GetHash()
                                  + " in directory: "
                                  + layerDirectory);
                    }
                    cachedLayerBuilder
                    .SetLayerBlob(Blobs.From(fileInLayerDirectory))
                    .SetLayerDiffId(cacheStorageFiles.GetDiffId(fileInLayerDirectory))
                    .SetLayerSize(Files.Size(fileInLayerDirectory));
                }
            }
            return(Maybe.Of(cachedLayerBuilder.Build()));
        }
Exemple #3
0
        /**
         * Retrieves the layer digest selected by the {@code selector}.
         *
         * @param selector the selector
         * @return the layer digest {@code selector} selects, if found
         * @throws CacheCorruptedException if the selector file contents was not a valid layer digest
         * @throws IOException if an I/O exception occurs
         */
        public Maybe <DescriptorDigest> Select(DescriptorDigest selector)
        {
            selector = selector ?? throw new ArgumentNullException(nameof(selector));
            SystemPath selectorFile = cacheStorageFiles.GetSelectorFile(selector);

            if (!Files.Exists(selectorFile))
            {
                return(Maybe.Empty <DescriptorDigest>());
            }
            string selectorFileContents =
                File.ReadAllText(selectorFile.ToFile().FullName, Encoding.UTF8);

            try
            {
                return(Maybe.Of(DescriptorDigest.FromHash(selectorFileContents)));
            }
            catch (DigestException)
            {
                throw new CacheCorruptedException(
                          cacheStorageFiles.GetCacheDirectory(),
                          "Expected valid layer digest as contents of selector file `"
                          + selectorFile
                          + "` for selector `"
                          + selector.GetHash()
                          + "`, but got: "
                          + selectorFileContents);
            }
        }
Exemple #4
0
        public void TestCreateFromHash_pass()
        {
            string goodHash = CreateGoodHash('a');

            DescriptorDigest descriptorDigest = DescriptorDigest.FromHash(goodHash);

            Assert.AreEqual(goodHash, descriptorDigest.GetHash());
            Assert.AreEqual("sha256:" + goodHash, descriptorDigest.ToString());
        }
Exemple #5
0
        public async Task TestRetrieveAsync()
        {
            CacheStorageFiles cacheStorageFiles =
                new CacheStorageFiles(temporaryFolder.NewFolder().ToPath());

            CacheStorageReader cacheStorageReader = new CacheStorageReader(cacheStorageFiles);

            // Creates the test layer directory.
            DescriptorDigest layerDigest = layerDigest1;
            DescriptorDigest layerDiffId = layerDigest2;

            Files.CreateDirectories(cacheStorageFiles.GetLayerDirectory(layerDigest));
            using (Stream @out =
                       Files.NewOutputStream(cacheStorageFiles.GetLayerFile(layerDigest, layerDiffId)))
            {
                byte[] bytes = Encoding.UTF8.GetBytes("layerBlob");
                await @out.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
            }

            // Checks that the CachedLayer is retrieved correctly.
            Maybe <CachedLayer> optionalCachedLayer = cacheStorageReader.Retrieve(layerDigest);

            Assert.IsTrue(optionalCachedLayer.IsPresent());
            Assert.AreEqual(layerDigest, optionalCachedLayer.Get().GetDigest());
            Assert.AreEqual(layerDiffId, optionalCachedLayer.Get().GetDiffId());
            Assert.AreEqual("layerBlob".Length, optionalCachedLayer.Get().GetSize());
            Assert.AreEqual("layerBlob", await Blobs.WriteToStringAsync(optionalCachedLayer.Get().GetBlob()).ConfigureAwait(false));

            // Checks that multiple .layer files means the cache is corrupted.
            Files.CreateFile(cacheStorageFiles.GetLayerFile(layerDigest, layerDigest));
            try
            {
                cacheStorageReader.Retrieve(layerDigest);
                Assert.Fail("Should have thrown CacheCorruptedException");
            }
            catch (CacheCorruptedException ex)
            {
                Assert.That(
                    ex.Message, Does.StartWith(
                        "Multiple layer files found for layer with digest "
                        + layerDigest.GetHash()
                        + " in directory: "
                        + cacheStorageFiles.GetLayerDirectory(layerDigest)));
            }
        }
        public async Task TestWrite_uncompressedAsync()
        {
            IBlob          uncompressedLayerBlob = Blobs.From("uncompressedLayerBlob");
            BlobDescriptor layerDigestDescriptor = await GetDigestAsync(Compress(uncompressedLayerBlob)).ConfigureAwait(false);

            DescriptorDigest layerDigest        = layerDigestDescriptor.GetDigest();
            BlobDescriptor   selectorDescriptor = await GetDigestAsync(Blobs.From("selector")).ConfigureAwait(false);

            DescriptorDigest selector = selectorDescriptor.GetDigest();

            CachedLayer cachedLayer =
                await new CacheStorageWriter(cacheStorageFiles)
                .WriteUncompressedAsync(uncompressedLayerBlob, selector).ConfigureAwait(false);

            await VerifyCachedLayerAsync(cachedLayer, uncompressedLayerBlob).ConfigureAwait(false);

            // Verifies that the files are present.
            SystemPath selectorFile = cacheStorageFiles.GetSelectorFile(selector);

            Assert.IsTrue(Files.Exists(selectorFile));
            Assert.AreEqual(layerDigest.GetHash(), await Blobs.WriteToStringAsync(Blobs.From(selectorFile)).ConfigureAwait(false));
        }
Exemple #7
0
        /**
         * Writes the {@code selector} to a file in the selectors directory, with contents {@code
         * layerDigest}.
         *
         * @param selector the selector
         * @param layerDigest the layer digest it selects
         * @throws IOException if an I/O exception occurs
         */
        private void WriteSelector(DescriptorDigest selector, DescriptorDigest layerDigest)
        {
            SystemPath selectorFile = cacheStorageFiles.GetSelectorFile(selector);

            // Creates the selectors directory if it doesn't exist.
            Files.CreateDirectories(selectorFile.GetParent());

            // Writes the selector to a temporary file and then moves the file to the intended location.
            using (TemporaryFile temporarySelectorFile = Files.CreateTempFile())
            {
                using (Stream fileOut = FileOperations.NewLockingOutputStream(temporarySelectorFile.Path))
                {
                    byte[] bytes = Encoding.UTF8.GetBytes(layerDigest.GetHash());
                    fileOut.Write(bytes, 0, bytes.Length);
                }

                // Attempts an atomic move first, and falls back to non-atomic if the file system does not
                // support atomic moves.
                Files.Move(
                    temporarySelectorFile.Path,
                    selectorFile,
                    StandardCopyOption.REPLACE_EXISTING);
            }
        }
Exemple #8
0
 /**
  * Gets the directory for the layer with digest {@code layerDigest}.
  *
  * @param layerDigest the digest of the layer
  * @return the directory for that {@code layerDigest}
  */
 public SystemPath GetLayerDirectory(DescriptorDigest layerDigest)
 {
     layerDigest = layerDigest ?? throw new ArgumentNullException(nameof(layerDigest));
     return(GetLayersDirectory().Resolve(layerDigest.GetHash()));
 }
Exemple #9
0
 /**
  * Resolves a selector file.
  *
  * @param selector the selector digest
  * @return the selector file
  */
 public SystemPath GetSelectorFile(DescriptorDigest selector)
 {
     selector = selector ?? throw new ArgumentNullException(nameof(selector));
     return(cacheDirectory.Resolve(SELECTORS_DIRECTORY).Resolve(selector.GetHash()));
 }
Exemple #10
0
 /**
  * Gets the filename for the layer file. The filename is in the form {@code <layer diff
  * ID>.layer}.
  *
  * @param layerDiffId the layer's diff ID
  * @return the layer filename
  */
 public virtual string GetLayerFilename(DescriptorDigest layerDiffId)
 {
     layerDiffId = layerDiffId ?? throw new ArgumentNullException(nameof(layerDiffId));
     return(layerDiffId.GetHash());
 }
        public async Task TestWriteToAsync()
        {
            SystemPath fileA     = Paths.Get(TestResources.GetResource("core/fileA").ToURI());
            SystemPath fileB     = Paths.Get(TestResources.GetResource("core/fileB").ToURI());
            long       fileASize = Files.Size(fileA);
            long       fileBSize = Files.Size(fileB);

            DescriptorDigest fakeDigestA =
                DescriptorDigest.FromHash(
                    "5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5");
            DescriptorDigest fakeDigestB =
                DescriptorDigest.FromHash(
                    "5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc6");

            Mock.Get(mockLayer1).Setup(m => m.GetBlob()).Returns(Blobs.From(fileA));

            Mock.Get(mockLayer1).Setup(m => m.GetBlobDescriptor()).Returns(new BlobDescriptor(fileASize, fakeDigestA));

            Mock.Get(mockLayer1).Setup(m => m.GetDiffId()).Returns(fakeDigestA);

            Mock.Get(mockLayer2).Setup(m => m.GetBlob()).Returns(Blobs.From(fileB));

            Mock.Get(mockLayer2).Setup(m => m.GetBlobDescriptor()).Returns(new BlobDescriptor(fileBSize, fakeDigestB));

            Mock.Get(mockLayer2).Setup(m => m.GetDiffId()).Returns(fakeDigestB);

            Image testImage =
                Image.CreateBuilder(ManifestFormat.V22).AddLayer(mockLayer1).AddLayer(mockLayer2).Build();

            ImageTarball imageToTarball = new ImageTarball(testImage, ImageReference.Parse("my/image:tag"));

            MemoryStream @out = new MemoryStream();
            await imageToTarball.WriteToAsync(@out).ConfigureAwait(false);

            MemoryStream @in = new MemoryStream(@out.ToArray());

            using (TarInputStream tarArchiveInputStream = new TarInputStream(@in))
            {
                // Verifies layer with fileA was added.
                TarEntry headerFileALayer = tarArchiveInputStream.GetNextEntry();
                Assert.AreEqual(fakeDigestA.GetHash() + ".tar.gz", headerFileALayer.Name);
                string fileAString =
                    await new StreamReader(tarArchiveInputStream).ReadToEndAsync().ConfigureAwait(false);
                Assert.AreEqual(await Blobs.WriteToStringAsync(Blobs.From(fileA)).ConfigureAwait(false), fileAString);

                // Verifies layer with fileB was added.
                TarEntry headerFileBLayer = tarArchiveInputStream.GetNextEntry();
                Assert.AreEqual(fakeDigestB.GetHash() + ".tar.gz", headerFileBLayer.Name);
                string fileBString = await new StreamReader(tarArchiveInputStream).ReadToEndAsync().ConfigureAwait(false);
                Assert.AreEqual(await Blobs.WriteToStringAsync(Blobs.From(fileB)).ConfigureAwait(false), fileBString);

                // Verifies container configuration was added.
                TarEntry headerContainerConfiguration = tarArchiveInputStream.GetNextEntry();
                Assert.AreEqual("config.json", headerContainerConfiguration.Name);
                string containerConfigJson = await new StreamReader(tarArchiveInputStream).ReadToEndAsync().ConfigureAwait(false);
                JsonTemplateMapper.ReadJson <ContainerConfigurationTemplate>(containerConfigJson);

                // Verifies manifest was added.
                TarEntry headerManifest = tarArchiveInputStream.GetNextEntry();
                Assert.AreEqual("manifest.json", headerManifest.Name);
                string manifestJson = await new StreamReader(tarArchiveInputStream).ReadToEndAsync().ConfigureAwait(false);
                JsonTemplateMapper.ReadListOfJson <DockerLoadManifestEntryTemplate>(manifestJson);
            }
        }