//private static DescriptorDigest fakeDigest = DescriptorDigest.fromHash(new string('a', 64));

        private void SetUp(ManifestFormat imageFormat)
        {
            Image.Builder testImageBuilder =
                Image.CreateBuilder(imageFormat)
                .SetCreated(Instant.FromUnixTimeSeconds(20))
                .SetArchitecture("wasm")
                .SetOs("js")
                .AddEnvironmentVariable("VAR1", "VAL1")
                .AddEnvironmentVariable("VAR2", "VAL2")
                .SetEntrypoint(new[] { "some", "entrypoint", "command" })
                .SetProgramArguments(new[] { "arg1", "arg2" })
                .SetHealthCheck(
                    DockerHealthCheck.FromCommand(ImmutableArray.Create("CMD-SHELL", "/checkhealth"))
                    .SetInterval(Duration.FromSeconds(3))
                    .SetTimeout(Duration.FromSeconds(1))
                    .SetStartPeriod(Duration.FromSeconds(2))
                    .SetRetries(3)
                    .Build())
                .AddExposedPorts(ImmutableHashSet.Create(Port.Tcp(1000), Port.Tcp(2000), Port.Udp(3000)))
                .AddVolumes(
                    ImmutableHashSet.Create(
                        AbsoluteUnixPath.Get("/var/job-result-data"),
                        AbsoluteUnixPath.Get("/var/log/my-app-logs")))
                .AddLabels(ImmutableDic.Of("key1", "value1", "key2", "value2"))
                .SetWorkingDirectory("/some/workspace")
                .SetUser("tomcat");

            DescriptorDigest fakeDigest =
                DescriptorDigest.FromDigest(
                    "sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad");

            testImageBuilder.AddLayer(
                new FakeLayer(fakeDigest));
            testImageBuilder.AddHistory(
                HistoryEntry.CreateBuilder()
                .SetCreationTimestamp(Instant.FromUnixTimeSeconds(0))
                .SetAuthor("Bazel")
                .SetCreatedBy("bazel build ...")
                .SetEmptyLayer(true)
                .Build());
            testImageBuilder.AddHistory(
                HistoryEntry.CreateBuilder()
                .SetCreationTimestamp(Instant.FromUnixTimeSeconds(20))
                .SetAuthor("Fib")
                .SetCreatedBy("fib")
                .Build());
            imageToJsonTranslator = new ImageToJsonTranslator(testImageBuilder.Build());
        }
예제 #2
0
        public async Task TestHandleResponse_invalidDigestAsync()
        {
            DescriptorDigest expectedDigest = await Digests.ComputeJsonDigestAsync(fakeManifestTemplate).ConfigureAwait(false);

            using (HttpResponseMessage mockResponse = new HttpResponseMessage
            {
                Headers = { { "Docker-Content-Digest", new List <string> {
                                  "not valid"
                              } } }
            })
            {
                Assert.AreEqual(expectedDigest, await testManifestPusher.HandleResponseAsync(mockResponse).ConfigureAwait(false));
                Mock.Get(mockEventHandlers).Verify(m => m.Dispatch(
                                                       LogEvent.Warn("Expected image digest " + expectedDigest + ", but received: not valid")));
            }
        }
예제 #3
0
        public async Task TestPushAsync()
        {
            localRegistry.PullAndPushToLocal("busybox", "busybox");
            IBlob testBlob = Blobs.From("crepecake");
            // Known digest for 'crepecake'
            DescriptorDigest testBlobDigest =
                DescriptorDigest.FromHash(
                    "52a9e4d4ba4333ce593707f98564fee1e6d898db0d3602408c0b2a6a424d357c");

            RegistryClient registryClient =
                RegistryClient.CreateFactory(EventHandlers.NONE, "localhost:5000", "testimage")
                .SetAllowInsecureRegistries(true)
                .NewRegistryClient();

            Assert.IsFalse(await registryClient.PushBlobAsync(testBlobDigest, testBlob, null, _ => { }).ConfigureAwait(false));
        }
예제 #4
0
 public void TestGetDiffId()
 {
     Assert.AreEqual(
         DescriptorDigest.FromHash(
             "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
         TEST_CACHE_STORAGE_FILES.GetDiffId(
             Paths.Get(
                 "layer",
                 "file",
                 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")));
     Assert.AreEqual(
         DescriptorDigest.FromHash(
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
         TEST_CACHE_STORAGE_FILES.GetDiffId(
             Paths.Get("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")));
 }
예제 #5
0
        /**
         * Gets the manifest as a JSON template. The {@code containerConfigurationBlobDescriptor} must be
         * the {@link BlobDescriptor} obtained by writing out the container configuration JSON returned
         * from {@link #getContainerConfiguration()}.
         *
         * @param <T> child type of {@link BuildableManifestTemplate}.
         * @param manifestTemplateClass the JSON template to translate the image to.
         * @param containerConfigurationBlobDescriptor the container configuration descriptor.
         * @return the image contents serialized as JSON.
         */
        public IBuildableManifestTemplate GetManifestTemplate(
            ManifestFormat manifestFormat, BlobDescriptor containerConfigurationBlobDescriptor)
        {
            containerConfigurationBlobDescriptor =
                containerConfigurationBlobDescriptor
                ?? throw new ArgumentNullException(nameof(containerConfigurationBlobDescriptor));
            try
            {
                IBuildableManifestTemplate template;
                // ISet up the JSON template.
                switch (manifestFormat)
                {
                case ManifestFormat.V22:
                    template = new V22ManifestTemplate();
                    break;

                case ManifestFormat.OCI:
                    template = new OCIManifestTemplate();
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(manifestFormat));
                }
                IBuildableManifestTemplate buildableTemplate = template;

                // Adds the container configuration reference.
                DescriptorDigest containerConfigurationDigest =
                    containerConfigurationBlobDescriptor.GetDigest();
                long containerConfigurationSize = containerConfigurationBlobDescriptor.GetSize();
                buildableTemplate.SetContainerConfiguration(containerConfigurationSize, containerConfigurationDigest);

                // Adds the layers.
                foreach (ILayer layer in image.GetLayers())
                {
                    buildableTemplate.AddLayer(
                        layer.GetBlobDescriptor().GetSize(), layer.GetBlobDescriptor().GetDigest());
                }

                // Serializes into JSON.
                return(template);
            }
            catch (JsonException ex)
            {
                throw new ArgumentException(manifestFormat + " cannot be instantiated", ex);
            }
        }
예제 #6
0
        public void SetUpFakes()
        {
            layerContentOutputStream = new MemoryStream();
            layerOutputStream        = new CountingDigestOutputStream(layerContentOutputStream);

            fakeDigest =
                DescriptorDigest.FromHash(
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

            testBlobPuller =
                new BlobPuller(
                    fakeRegistryEndpointRequestProperties,
                    fakeDigest,
                    layerOutputStream,
                    _ => { },
                    _ => { });
        }
예제 #7
0
        /**
         * Gets a {@link BuildResult} from an {@link Image}.
         *
         * @param image the image
         * @param targetFormat the target format of the image
         * @return a new {@link BuildResult} with the image's digest and id
         * @throws IOException if writing the digest or container configuration fails
         */
        public static async Task <BuildResult> FromImageAsync(Image image, ManifestFormat targetFormat)
        {
            ImageToJsonTranslator          imageToJsonTranslator = new ImageToJsonTranslator(image);
            ContainerConfigurationTemplate configurationTemplate = imageToJsonTranslator.GetContainerConfiguration();
            BlobDescriptor containerConfigurationBlobDescriptor  =
                await Digests.ComputeJsonDescriptorAsync(configurationTemplate).ConfigureAwait(false);

            IBuildableManifestTemplate manifestTemplate =
                imageToJsonTranslator.GetManifestTemplate(
                    targetFormat, containerConfigurationBlobDescriptor);
            DescriptorDigest imageDigest =
                await Digests.ComputeJsonDigestAsync(manifestTemplate).ConfigureAwait(false);

            DescriptorDigest imageId = containerConfigurationBlobDescriptor.GetDigest();

            return(new BuildResult(imageDigest, imageId));
        }
예제 #8
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)));
            }
        }
예제 #9
0
        public void TestGetLayerFile()
        {
            DescriptorDigest layerDigest =
                DescriptorDigest.FromHash(
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
            DescriptorDigest diffId =
                DescriptorDigest.FromHash(
                    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");

            Assert.AreEqual(
                Paths.Get(
                    "cache",
                    "directory",
                    "layers",
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
                TEST_CACHE_STORAGE_FILES.GetLayerFile(layerDigest, diffId));
        }
예제 #10
0
        public void TestSelect()
        {
            CacheStorageFiles cacheStorageFiles =
                new CacheStorageFiles(temporaryFolder.NewFolder().ToPath());

            CacheStorageReader cacheStorageReader = new CacheStorageReader(cacheStorageFiles);

            DescriptorDigest selector     = layerDigest1;
            SystemPath       selectorFile = cacheStorageFiles.GetSelectorFile(selector);

            Files.CreateDirectories(selectorFile.GetParent());
            Files.Write(selectorFile, Encoding.UTF8.GetBytes(layerDigest2.GetHash()));

            Maybe <DescriptorDigest> selectedLayerDigest = cacheStorageReader.Select(selector);

            Assert.IsTrue(selectedLayerDigest.IsPresent());
            Assert.AreEqual(layerDigest2, selectedLayerDigest.Get());
        }
        public async Task Test_smokeTestAsync()
        {
            foreach (KeyValuePair <string, string> knownHash in KNOWN_SHA256_HASHES)
            {
                string toHash       = knownHash.Key;
                string expectedHash = knownHash.Value;

                byte[] bytesToHash            = Encoding.UTF8.GetBytes(toHash);
                Stream underlyingOutputStream = new MemoryStream();
                using (CountingDigestOutputStream countingDigestOutputStream = new CountingDigestOutputStream(underlyingOutputStream))
                    using (Stream toHashInputStream = new MemoryStream(bytesToHash))
                    {
                        await toHashInputStream.CopyToAsync(countingDigestOutputStream).ConfigureAwait(false);

                        BlobDescriptor blobDescriptor = countingDigestOutputStream.ComputeDigest();
                        Assert.AreEqual(DescriptorDigest.FromHash(expectedHash), blobDescriptor.GetDigest());
                        Assert.AreEqual(bytesToHash.Length, blobDescriptor.GetSize());
                    }
            }
        }
예제 #12
0
        /**
         * Translates {@link BuildableManifestTemplate} to {@link Image}. Uses the corresponding {@link
         * ContainerConfigurationTemplate} to get the layer diff IDs.
         *
         * @param manifestTemplate the template containing the image layers.
         * @param containerConfigurationTemplate the template containing the diff IDs and container
         *     configuration properties.
         * @return the translated {@link Image}.
         * @throws LayerCountMismatchException if the manifest and configuration contain conflicting layer
         *     information.
         * @throws LayerPropertyNotFoundException if adding image layers fails.
         * @throws BadContainerConfigurationFormatException if the container configuration is in a bad
         *     format
         */
        public static Image ToImage <T>(
            T manifestTemplate,
            ContainerConfigurationTemplate containerConfigurationTemplate) where T : IBuildableManifestTemplate
        {
            containerConfigurationTemplate =
                containerConfigurationTemplate
                ?? throw new ArgumentNullException(nameof(containerConfigurationTemplate));
            IList <ReferenceNoDiffIdLayer> layers = new List <ReferenceNoDiffIdLayer>();

            foreach (ContentDescriptorTemplate layerObjectTemplate in
                     manifestTemplate.Layers)
            {
                if (layerObjectTemplate.Digest == null)
                {
                    throw new ArgumentException(Resources.JsonToImageTranslatorMissingDigestExceptionMessage);
                }

                layers.Add(new ReferenceNoDiffIdLayer(
                               new BlobDescriptor(layerObjectTemplate.Size, layerObjectTemplate.Digest)));
            }

            IList <DescriptorDigest> diffIds = containerConfigurationTemplate.GetDiffIds();

            if (layers.Count != diffIds.Count)
            {
                throw new LayerCountMismatchException(Resources.JsonToImageTranslatorDiffIdMismatchExceptionMessage);
            }

            Image.Builder imageBuilder = Image.CreateBuilder(manifestTemplate.GetFormat());

            for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++)
            {
                ReferenceNoDiffIdLayer noDiffIdLayer = layers[layerIndex];
                DescriptorDigest       diffId        = diffIds[layerIndex];

                imageBuilder.AddLayer(new ReferenceLayer(noDiffIdLayer.GetBlobDescriptor(), diffId));
            }

            ConfigureBuilderWithContainerConfiguration(imageBuilder, containerConfigurationTemplate);
            return(imageBuilder.Build());
        }
예제 #13
0
        public async Task TestGenerateSelector_fileModifiedAsync()
        {
            SystemPath layerFile = temporaryFolder.NewFolder("testFolder").ToPath().Resolve("file");

            Files.Write(layerFile, Encoding.UTF8.GetBytes("hello"));
            Files.SetLastModifiedTime(layerFile, FileTime.From(Instant.FromUnixTimeSeconds(0)));
            LayerEntry       layerEntry       = DefaultLayerEntry(layerFile, AbsoluteUnixPath.Get("/extraction/path"));
            DescriptorDigest expectedSelector =
                await GenerateSelectorAsync(ImmutableArray.Create(layerEntry)).ConfigureAwait(false);

            // Verify that changing modified time generates a different selector
            Files.SetLastModifiedTime(layerFile, FileTime.From(Instant.FromUnixTimeSeconds(1)));
            Assert.AreNotEqual(
                expectedSelector, await GenerateSelectorAsync(ImmutableArray.Create(layerEntry)).ConfigureAwait(false));

            // Verify that changing modified time back generates same selector
            Files.SetLastModifiedTime(layerFile, FileTime.From(Instant.FromUnixTimeSeconds(0)));
            Assert.AreEqual(
                expectedSelector,
                await GenerateSelectorAsync(ImmutableArray.Create(layerEntry)).ConfigureAwait(false));
        }
예제 #14
0
        public void SetUpFakes()
        {
            DescriptorDigest mockDescriptorDigest1 = DescriptorDigest.FromHash(new string('a', 64));
            DescriptorDigest mockDescriptorDigest2 = DescriptorDigest.FromHash(new string('b', 64));
            DescriptorDigest mockDescriptorDigest3 = DescriptorDigest.FromHash(new string('c', 64));

            BlobDescriptor layerBlobDescriptor                  = new BlobDescriptor(0, mockDescriptorDigest1);
            BlobDescriptor referenceLayerBlobDescriptor         = new BlobDescriptor(0, mockDescriptorDigest2);
            BlobDescriptor referenceNoDiffIdLayerBlobDescriptor =
                new BlobDescriptor(0, mockDescriptorDigest3);
            // Intentionally the same digest as the mockLayer.
            BlobDescriptor anotherBlobDescriptor = new BlobDescriptor(0, mockDescriptorDigest1);

            Mock.Get(mockLayer).Setup(m => m.GetBlobDescriptor()).Returns(layerBlobDescriptor);

            Mock.Get(mockReferenceLayer).Setup(m => m.GetBlobDescriptor()).Returns(referenceLayerBlobDescriptor);

            Mock.Get(mockDigestOnlyLayer).Setup(m => m.GetBlobDescriptor()).Returns(referenceNoDiffIdLayerBlobDescriptor);

            Mock.Get(mockLayer2).Setup(m => m.GetBlobDescriptor()).Returns(anotherBlobDescriptor);
        }
예제 #15
0
        private async Task VerifyCachedLayerAsync(CachedLayer cachedLayer, IBlob uncompressedLayerBlob)
        {
            BlobDescriptor layerBlobDescriptor = await GetDigestAsync(Compress(uncompressedLayerBlob)).ConfigureAwait(false);

            BlobDescriptor layerDiffDescriptor = await GetDigestAsync(uncompressedLayerBlob).ConfigureAwait(false);

            DescriptorDigest layerDiffId = layerDiffDescriptor.GetDigest();

            // Verifies cachedLayer is correct.
            Assert.AreEqual(layerBlobDescriptor.GetDigest(), cachedLayer.GetDigest());
            Assert.AreEqual(layerDiffId, cachedLayer.GetDiffId());
            Assert.AreEqual(layerBlobDescriptor.GetSize(), cachedLayer.GetSize());
            CollectionAssert.AreEqual(
                await Blobs.WriteToByteArrayAsync(uncompressedLayerBlob).ConfigureAwait(false),
                await Blobs.WriteToByteArrayAsync(await DecompressAsync(cachedLayer.GetBlob()).ConfigureAwait(false)).ConfigureAwait(false));

            // Verifies that the files are present.
            Assert.IsTrue(
                Files.Exists(
                    cacheStorageFiles.GetLayerFile(cachedLayer.GetDigest(), cachedLayer.GetDiffId())));
        }
예제 #16
0
        /** Checks that the {@link Blob} streams the expected string. */
        private async Task VerifyBlobWriteToAsync(string expected, IBlob blob)
        {
            using (MemoryStream outputStream = new MemoryStream())
            {
                BlobDescriptor blobDescriptor = await blob.WriteToAsync(outputStream).ConfigureAwait(false);

                string output = Encoding.UTF8.GetString(outputStream.ToArray());
                Assert.AreEqual(expected, output);

                byte[] expectedBytes = Encoding.UTF8.GetBytes(expected);
                Assert.AreEqual(expectedBytes.Length, blobDescriptor.GetSize());

                using (MemoryStream stream = new MemoryStream(expectedBytes))
                {
                    BlobDescriptor digestDescriptor = await Digests.ComputeDigestAsync(stream).ConfigureAwait(false);

                    DescriptorDigest expectedDigest =
                        digestDescriptor.GetDigest();
                    Assert.AreEqual(expectedDigest, blobDescriptor.GetDigest());
                }
            }
        }
예제 #17
0
        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));
        }
예제 #18
0
        public async Task TestExecuteAsync_OutputsResult()
        {
            _objectUnderTest.ConfigFile =
                Path.Combine(TestContext.CurrentContext.TestDirectory, "Resources", "trivial-config.json");
            Mock.Get(_objectUnderTest.Containerizer)
            .Setup(c => c.CreateStepsRunner(It.IsAny <BuildConfiguration>()).RunAsync())
            .Returns(
                Task.FromResult(
                    Mock.Of <IBuildResult>(
                        r => r.GetImageDigest()
                        == DescriptorDigest.FromHash(new string('a', DescriptorDigest.HashLength)) &&
                        r.GetImageId()
                        == DescriptorDigest.FromHash(new string('b', DescriptorDigest.HashLength)))));
            await _objectUnderTest.ExecuteAsync(_output, _error).ConfigureAwait(false);

            Assert.That(
                _output.ToString(),
                Contains.Substring($"ImageDigest:sha256:{new string('a', DescriptorDigest.HashLength)}"));
            Assert.That(
                _output.ToString(),
                Contains.Substring($"ImageId:sha256:{new string('b', DescriptorDigest.HashLength)}"));
        }
예제 #19
0
        public void TestToJson()
        {
            // Loads the expected JSON string.
            SystemPath jsonFile     = Paths.Get(TestResources.GetResource("core/json/ocimanifest.json").ToURI());
            string     expectedJson = Encoding.UTF8.GetString(Files.ReadAllBytes(jsonFile));

            // Creates the JSON object to serialize.
            OCIManifestTemplate manifestJson = new OCIManifestTemplate();

            manifestJson.SetContainerConfiguration(
                1000,
                DescriptorDigest.FromDigest(
                    "sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"));

            manifestJson.AddLayer(
                1000_000,
                DescriptorDigest.FromHash(
                    "4945ba5011739b0b98c4a41afe224e417f47c7c99b2ce76830999c9a0861b236"));

            // Serializes the JSON object.
            Assert.AreEqual(expectedJson, JsonTemplateMapper.ToUtf8String(manifestJson));
        }
예제 #20
0
        /**
         * Pushes the BLOB. If the {@code sourceRepository} is provided then the remote registry may skip
         * if the BLOB already exists on the registry.
         *
         * @param blobDigest the digest of the BLOB, used for existence-check
         * @param blob the BLOB to push
         * @param sourceRepository if pushing to the same registry then the source image, or {@code null}
         *     otherwise; used to optimize the BLOB push
         * @param writtenByteCountListener listens on byte count written to the registry during the push
         * @return {@code true} if the BLOB already exists on the registry and pushing was skipped; false
         *     if the BLOB was pushed
         * @throws IOException if communicating with the endpoint fails
         * @throws RegistryException if communicating with the endpoint fails
         */
        public async Task <bool> PushBlobAsync(
            DescriptorDigest blobDigest,
            IBlob blob,
            string sourceRepository,
            Action <long> writtenByteCountListener)
        {
            BlobPusher blobPusher =
                new BlobPusher(registryEndpointRequestProperties, blobDigest, blob, sourceRepository);

            using (TimerEventDispatcher timerEventDispatcher =
                       new TimerEventDispatcher(eventHandlers, "pushBlob"))
            {
                timerEventDispatcher.Lap("pushBlob POST " + blobDigest);

                // POST /v2/<name>/blobs/uploads/ OR
                // POST /v2/<name>/blobs/uploads/?mount={blob.digest}&from={sourceRepository}
                Uri patchLocation = await CallRegistryEndpointAsync(blobPusher.CreateInitializer()).ConfigureAwait(false);

                if (patchLocation == null)
                {
                    // The BLOB exists already.
                    return(true);
                }
                timerEventDispatcher.Lap("pushBlob PATCH " + blobDigest);

                // PATCH <Location> with BLOB
                Uri putLocation =
                    await CallRegistryEndpointAsync(blobPusher.CreateWriter(patchLocation, writtenByteCountListener)).ConfigureAwait(false);

                Preconditions.CheckNotNull(putLocation);
                timerEventDispatcher.Lap("pushBlob PUT " + blobDigest);

                // PUT <Location>?digest={blob.digest}
                await CallRegistryEndpointAsync(blobPusher.CreateCommitter(putLocation)).ConfigureAwait(false);

                return(false);
            }
        }
예제 #21
0
        public void TestFromJson()
        {
            // Loads the JSON string.
            SystemPath jsonFile = Paths.Get(TestResources.GetResource("core/json/ocimanifest.json").ToURI());

            // Deserializes into a manifest JSON object.
            OCIManifestTemplate manifestJson =
                JsonTemplateMapper.ReadJsonFromFile <OCIManifestTemplate>(jsonFile);

            Assert.AreEqual(
                DescriptorDigest.FromDigest(
                    "sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"),
                manifestJson.GetContainerConfiguration().Digest);

            Assert.AreEqual(1000, manifestJson.GetContainerConfiguration().Size);

            Assert.AreEqual(
                DescriptorDigest.FromHash(
                    "4945ba5011739b0b98c4a41afe224e417f47c7c99b2ce76830999c9a0861b236"),
                manifestJson.Layers[0].Digest);

            Assert.AreEqual(1000_000, manifestJson.Layers[0].Size);
        }
예제 #22
0
        public void TestFromJson()
        {
            // Loads the JSON string.
            SystemPath jsonFile = Paths.Get(TestResources.GetResource("core/json/v21manifest.json").ToURI());

            // Deserializes into a manifest JSON object.
            V21ManifestTemplate manifestJson =
                JsonTemplateMapper.ReadJsonFromFile <V21ManifestTemplate>(jsonFile);

            Assert.AreEqual(
                DescriptorDigest.FromDigest(
                    "sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"),
                manifestJson.FsLayers[0].GetDigest());

            ContainerConfigurationTemplate containerConfiguration =
                manifestJson.GetContainerConfiguration().OrElse(null);

            Assert.AreEqual(
                new[] { "JAVA_HOME=/opt/openjdk", "PATH=/opt/openjdk/bin" },
                containerConfiguration.GetContainerEnvironment());
            Assert.AreEqual(
                new[] { "/opt/openjdk/bin/java" }, containerConfiguration.GetContainerEntrypoint());
        }
예제 #23
0
        /**
         * Lists all the layer digests stored.
         *
         * @return the list of layer digests
         * @throws CacheCorruptedException if the cache was found to be corrupted
         * @throws IOException if an I/O exception occurs
         */
        public ISet <DescriptorDigest> FetchDigests()
        {
            IEnumerable <SystemPath> layerDirectories = Files.List(cacheStorageFiles.GetLayersDirectory());

            IList <SystemPath>      layerDirectoriesList = layerDirectories.ToList();
            ISet <DescriptorDigest> layerDigests         = new HashSet <DescriptorDigest>();

            foreach (SystemPath layerDirectory in layerDirectoriesList)
            {
                try
                {
                    layerDigests.Add(DescriptorDigest.FromHash(layerDirectory.GetFileName().ToString()));
                }
                catch (DigestException ex)
                {
                    throw new CacheCorruptedException(
                              cacheStorageFiles.GetCacheDirectory(),
                              Resources.CacheStorageReaderNonDigestFileExceptionMessage,
                              ex);
                }
            }
            return(layerDigests);
        }
예제 #24
0
 /**
  * Gets the BLOB referenced by {@code blobDigest}. Note that the BLOB is only pulled when it is
  * written out.
  *
  * @param blobDigest the digest of the BLOB to download
  * @param blobSizeListener callback to receive the total size of the BLOb to pull
  * @param writtenByteCountListener listens on byte count written to an output stream during the
  *     pull
  * @return a {@link Blob}
  */
 public IBlob PullBlob(
     DescriptorDigest blobDigest,
     Action <long> blobSizeListener,
     Action <long> writtenByteCountListener)
 {
     return(Blobs.From(
                async outputStream =>
     {
         try
         {
             await CallRegistryEndpointAsync(new BlobPuller(
                                                 registryEndpointRequestProperties,
                                                 blobDigest,
                                                 outputStream,
                                                 blobSizeListener,
                                                 writtenByteCountListener)).ConfigureAwait(false);
         }
         catch (RegistryException ex)
         {
             throw new IOException("", ex);
         }
     }, -1));
 }
예제 #25
0
        /**
         * Writes a compressed {@code layerBlob} to the {@code layerDirectory}.
         *
         * @param compressedLayerBlob the compressed layer {@link Blob}
         * @param layerDirectory the directory for the layer
         * @return a {@link WrittenLayer} with the written layer information
         * @throws IOException if an I/O exception occurs
         */
        private async Task <WrittenLayer> WriteCompressedLayerBlobToDirectoryAsync(
            IBlob compressedLayerBlob, SystemPath layerDirectory)
        {
            // Writes the layer file to the temporary directory.
            using (TemporaryFile temporaryLayerFile = CacheStorageFiles.GetTemporaryLayerFile(layerDirectory))
            {
                BlobDescriptor layerBlobDescriptor;
                using (Stream fileOutputStream = Files.NewOutputStream(temporaryLayerFile.Path))
                {
                    layerBlobDescriptor = await compressedLayerBlob.WriteToAsync(fileOutputStream).ConfigureAwait(false);
                }

                // Gets the diff ID.
                DescriptorDigest layerDiffId = await GetDiffIdByDecompressingFileAsync(temporaryLayerFile.Path).ConfigureAwait(false);

                // Renames the temporary layer file to the correct filename.
                SystemPath layerFile = layerDirectory.Resolve(cacheStorageFiles.GetLayerFilename(layerDiffId));
                temporaryLayerFile.MoveIfDoesNotExist(layerFile);

                return(new WrittenLayer(
                           layerBlobDescriptor.GetDigest(), layerDiffId, layerBlobDescriptor.GetSize()));
            }
        }
예제 #26
0
        public void TestToImage_v21()
        {
            // Loads the JSON string.
            SystemPath jsonFile =
                Paths.Get(TestResources.GetResource("core/json/v21manifest.json").ToURI());

            // Deserializes into a manifest JSON object.
            V21ManifestTemplate manifestTemplate =
                JsonTemplateMapper.ReadJsonFromFile <V21ManifestTemplate>(jsonFile);

            Image image = JsonToImageTranslator.ToImage(manifestTemplate);

            IList <ILayer> layers = image.GetLayers();

            Assert.AreEqual(2, layers.Count);
            Assert.AreEqual(
                DescriptorDigest.FromDigest(
                    "sha256:5bd451067f9ab05e97cda8476c82f86d9b69c2dffb60a8ad2fe3723942544ab3"),
                layers[0].GetBlobDescriptor().GetDigest());
            Assert.AreEqual(
                DescriptorDigest.FromDigest(
                    "sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"),
                layers[1].GetBlobDescriptor().GetDigest());
        }
예제 #27
0
        public void TestUseAsMapKey()
        {
            DescriptorDigest descriptorDigestA1 = DescriptorDigest.FromHash(CreateGoodHash('a'));
            DescriptorDigest descriptorDigestA2 = DescriptorDigest.FromHash(CreateGoodHash('a'));
            DescriptorDigest descriptorDigestA3 =
                DescriptorDigest.FromDigest("sha256:" + CreateGoodHash('a'));
            DescriptorDigest descriptorDigestB = DescriptorDigest.FromHash(CreateGoodHash('b'));

            IDictionary <DescriptorDigest, string> digestMap = new Dictionary <DescriptorDigest, string>
            {
                [descriptorDigestA1] = "digest with a"
            };

            Assert.AreEqual("digest with a", digestMap[descriptorDigestA1]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA2]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA3]);
            Assert.IsFalse(digestMap.ContainsKey(descriptorDigestB));

            digestMap[descriptorDigestA2] = "digest with a";
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA1]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA2]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA3]);
            Assert.IsFalse(digestMap.ContainsKey(descriptorDigestB));

            digestMap[descriptorDigestA3] = "digest with a";
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA1]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA2]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA3]);
            Assert.IsFalse(digestMap.ContainsKey(descriptorDigestB));

            digestMap[descriptorDigestB] = "digest with b";
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA1]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA2]);
            Assert.AreEqual("digest with a", digestMap[descriptorDigestA3]);
            Assert.AreEqual("digest with b", digestMap[descriptorDigestB]);
        }
예제 #28
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);
            }
        }
예제 #29
0
        /**
         * Pulls the base image.
         *
         * @param registryAuthorization authentication credentials to possibly use
         * @param progressEventDispatcher the {@link ProgressEventDispatcher} for emitting {@link
         *     ProgressEvent}s
         * @return the pulled image
         * @throws IOException when an I/O exception occurs during the pulling
         * @throws RegistryException if communicating with the registry caused a known error
         * @throws LayerCountMismatchException if the manifest and configuration contain conflicting layer
         *     information
         * @throws LayerPropertyNotFoundException if adding image layers fails
         * @throws BadContainerConfigurationFormatException if the container configuration is in a bad
         *     format
         */
        private async Task <Image> PullBaseImageAsync(
            Authorization registryAuthorization,
            ProgressEventDispatcher progressEventDispatcher)
        {
            RegistryClient registryClient =
                buildConfiguration
                .NewBaseImageRegistryClientFactory()
                .SetAuthorization(registryAuthorization)
                .NewRegistryClient();

            IManifestTemplate manifestTemplate =
                await registryClient.PullManifestAsync(buildConfiguration.GetBaseImageConfiguration().GetImageTag()).ConfigureAwait(false);

            // TODO: Make schema version be enum.
            switch (manifestTemplate.SchemaVersion)
            {
            case 1:
                V21ManifestTemplate v21ManifestTemplate = (V21ManifestTemplate)manifestTemplate;
                await buildConfiguration
                .GetBaseImageLayersCache()
                .WriteMetadataAsync(
                    buildConfiguration.GetBaseImageConfiguration().GetImage(), v21ManifestTemplate).ConfigureAwait(false);

                return(JsonToImageTranslator.ToImage(v21ManifestTemplate));

            case 2:
                IBuildableManifestTemplate buildableManifestTemplate =
                    (IBuildableManifestTemplate)manifestTemplate;
                if (buildableManifestTemplate.GetContainerConfiguration() == null ||
                    buildableManifestTemplate.GetContainerConfiguration().Digest == null)
                {
                    throw new UnknownManifestFormatException(
                              "Invalid container configuration in Docker V2.2/OCI manifest: \n"
                              + JsonTemplateMapper.ToUtf8String(buildableManifestTemplate));
                }

                DescriptorDigest containerConfigurationDigest =
                    buildableManifestTemplate.GetContainerConfiguration().Digest;

                using (ThrottledProgressEventDispatcherWrapper progressEventDispatcherWrapper =
                           new ThrottledProgressEventDispatcherWrapper(
                               progressEventDispatcher.NewChildProducer(),
                               "pull container configuration " + containerConfigurationDigest))
                {
                    string containerConfigurationString =
                        await Blobs.WriteToStringAsync(
                            registryClient.PullBlob(
                                containerConfigurationDigest,
                                progressEventDispatcherWrapper.SetProgressTarget,
                                progressEventDispatcherWrapper.DispatchProgress)).ConfigureAwait(false);

                    ContainerConfigurationTemplate containerConfigurationTemplate =
                        JsonTemplateMapper.ReadJson <ContainerConfigurationTemplate>(
                            containerConfigurationString);
                    await buildConfiguration
                    .GetBaseImageLayersCache()
                    .WriteMetadataAsync(
                        buildConfiguration.GetBaseImageConfiguration().GetImage(),
                        buildableManifestTemplate,
                        containerConfigurationTemplate).ConfigureAwait(false);

                    return(JsonToImageTranslator.ToImage(
                               buildableManifestTemplate, containerConfigurationTemplate));
                }
            }

            throw new InvalidOperationException(Resources.PullBaseImageStepUnknownManifestErrorMessage);
        }
예제 #30
0
 public void SetContainerConfiguration(long size, DescriptorDigest digest)
 {
     Config = new ContentDescriptorTemplate(CONTAINER_CONFIGURATION_MEDIA_TYPE, size, digest);
 }