You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by tn...@apache.org on 2015/11/24 23:47:45 UTC
[3/3] mesos git commit: Refactored Docker registry client to use
protobuf messages.
Refactored Docker registry client to use protobuf messages.
Review: https://reviews.apache.org/r/39712
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/48bc61a2
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/48bc61a2
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/48bc61a2
Branch: refs/heads/master
Commit: 48bc61a2e37d8845d3d6a3beaa9cd89ffe9ee09e
Parents: 95c5691
Author: Gilbert Song <so...@gmail.com>
Authored: Tue Nov 24 14:23:42 2015 -0800
Committer: Timothy Chen <tn...@gmail.com>
Committed: Tue Nov 24 22:47:30 2015 +0000
----------------------------------------------------------------------
.../provisioner/docker/registry_client.cpp | 128 ++--------
.../provisioner/docker/registry_client.hpp | 26 +-
.../provisioner/docker/registry_puller.cpp | 45 ++--
.../containerizer/provisioner_docker_tests.cpp | 238 +++++++++----------
4 files changed, 162 insertions(+), 275 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/48bc61a2/src/slave/containerizer/mesos/provisioner/docker/registry_client.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/registry_client.cpp b/src/slave/containerizer/mesos/provisioner/docker/registry_client.cpp
index 99a421b..e69bab4 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/registry_client.cpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/registry_client.cpp
@@ -37,6 +37,7 @@
#include <stout/try.hpp>
#include "slave/containerizer/mesos/provisioner/docker/registry_client.hpp"
+#include "slave/containerizer/mesos/provisioner/docker/spec.hpp"
#include "slave/containerizer/mesos/provisioner/docker/token_manager.hpp"
using std::string;
@@ -69,7 +70,7 @@ public:
const http::URL& authenticationServer,
const Option<Credentials>& credentials);
- Future<Manifest> getManifest(
+ Future<DockerImageManifest> getManifest(
const Image::Name& imageName);
Future<size_t> getBlob(
@@ -169,7 +170,7 @@ RegistryClient::~RegistryClient()
}
-Future<Manifest> RegistryClient::getManifest(
+Future<DockerImageManifest> RegistryClient::getManifest(
const Image::Name& imageName)
{
return dispatch(
@@ -551,111 +552,6 @@ Future<http::Response> RegistryClientProcess::doHttpGet(
}
-Try<Manifest> Manifest::create(const string& jsonString)
-{
- Try<JSON::Object> manifestJSON = JSON::parse<JSON::Object>(jsonString);
-
- if (manifestJSON.isError()) {
- return Error(manifestJSON.error());
- }
-
- Result<JSON::String> name = manifestJSON.get().find<JSON::String>("name");
- if (name.isNone()) {
- return Error("Failed to find \"name\" in manifest response");
- }
-
- Result<JSON::Array> fsLayersJSON =
- manifestJSON.get().find<JSON::Array>("fsLayers");
-
- if (fsLayersJSON.isNone()) {
- return Error("Failed to find \"fsLayers\" in manifest response");
- }
-
- Result<JSON::Array> historyArray =
- manifestJSON.get().find<JSON::Array>("history");
-
- if (historyArray.isNone()) {
- return Error("Failed to find \"history\" in manifest response");
- }
-
- if (historyArray.get().values.size() != fsLayersJSON.get().values.size()) {
- return Error(
- "\"history\" and \"fsLayers\" array count mismatch"
- "in manifest response");
- }
-
- vector<FileSystemLayerInfo> fsLayers;
-
- // We add layers in reverse order because 'fsLayers' in the manifest
- // response is ordered with the latest layer on the top. When we apply the
- // layer changes, we want the filesystem modification order to be the same
- // as its history(oldest layer applied first).
- for (size_t index = fsLayersJSON.get().values.size(); index-- > 0; ) {
- const JSON::Value& layer = fsLayersJSON.get().values[index];
-
- if (!layer.is<JSON::Object>()) {
- return Error(
- "Failed to parse layer as a JSON object for index: " +
- stringify(index));
- }
-
- const JSON::Object& layerInfoJSON = layer.as<JSON::Object>();
-
- // Get blobsum for layer.
- const Result<JSON::String> blobSumInfo =
- layerInfoJSON.find<JSON::String>("blobSum");
-
- if (blobSumInfo.isNone()) {
- return Error("Failed to find \"blobSum\" in manifest response");
- }
-
- // Get history for layer.
- if (!historyArray.get().values[index].is<JSON::Object>()) {
- return Error(
- "Failed to parse history as a JSON object for index: " +
- stringify(index));
- }
- const JSON::Object& historyObj =
- historyArray.get().values[index].as<JSON::Object>();
-
- // Get layer id.
- const Result<JSON::String> v1CompatibilityJSON =
- historyObj.find<JSON::String>("v1Compatibility");
-
- if (!v1CompatibilityJSON.isSome()) {
- return Error(
- "Failed to obtain layer v1 compability json in manifest for layer: "
- + stringify(index));
- }
-
- Try<JSON::Object> v1CompatibilityObj =
- JSON::parse<JSON::Object>(v1CompatibilityJSON.get().value);
-
- if (!v1CompatibilityObj.isSome()) {
- return Error(
- "Failed to parse v1 compability json in manifest for layer: "
- + stringify(index));
- }
-
- const Result<JSON::String> id =
- v1CompatibilityObj.get().find<JSON::String>("id");
-
- if (!id.isSome()) {
- return Error(
- "Failed to find \"id\" in manifest for layer: " + stringify(index));
- }
-
- fsLayers.emplace_back(
- FileSystemLayerInfo{
- blobSumInfo.get().value,
- id.get().value,
- });
- }
-
- return Manifest{name.get().value, fsLayers};
-}
-
-
// TODO(tnachen): Support other Docker registry API versions.
string RegistryClientProcess::getAPIVersion() const
{
@@ -676,7 +572,7 @@ string RegistryClientProcess::getRepositoryPath(
}
-Future<Manifest> RegistryClientProcess::getManifest(
+Future<DockerImageManifest> RegistryClientProcess::getManifest(
const Image::Name& imageName)
{
http::URL manifestURL(registryServer_);
@@ -685,16 +581,28 @@ Future<Manifest> RegistryClientProcess::getManifest(
return doHttpGet(manifestURL, None(), false, true, None())
.then(defer(self(), [this] (
- const http::Response& response) -> Future<Manifest> {
+ const http::Response& response) -> Future<DockerImageManifest> {
// TODO(jojy): We dont use the digest that is returned in header.
// This is a good place to validate the manifest.
- Try<Manifest> manifest = Manifest::create(response.body);
+ Try<DockerImageManifest> manifest =
+ spec::parse(JSON::parse<JSON::Object>(response.body).get());
if (manifest.isError()) {
return Failure(
"Failed to parse manifest response: " + manifest.error());
}
+ // We reverse the order of fsLayers and history because in
+ // manifest response the latest layer is on the top.
+ // We assume fslayers and history has the same length as
+ // it's already checked in spec::parse.
+ for (int i = 0; i < manifest.get().fslayers_size() / 2; i++) {
+ manifest.get().mutable_fslayers()->SwapElements(i,
+ manifest.get().fslayers_size() - 1 - i);
+ manifest.get().mutable_history()->SwapElements(i,
+ manifest.get().fslayers_size() - 1 - i);
+ }
+
return manifest.get();
}));
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/48bc61a2/src/slave/containerizer/mesos/provisioner/docker/registry_client.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/registry_client.hpp b/src/slave/containerizer/mesos/provisioner/docker/registry_client.hpp
index 2287327..9b02b6f 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/registry_client.hpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/registry_client.hpp
@@ -44,30 +44,6 @@ class RegistryClientProcess;
// TODO(bmahler): Replace these with the existing protobuf counterparts.
-struct FileSystemLayerInfo
-{
- // TODO(jojy): This includes both the checksum and
- // the type of the checksum; separate these.
- const std::string checksumInfo;
- const std::string layerId;
-};
-
-
-/**
- * Response for a "GET Manifest" request.
- *
- * Reference:
- * https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-1.md
- */
-struct Manifest
-{
- static Try<Manifest> create(const std::string& jsonString);
-
- const std::string name;
- const std::vector<FileSystemLayerInfo> fsLayerInfos;
-};
-
-
/**
* Authentication credentials for the client sessions.
*/
@@ -103,7 +79,7 @@ public:
* @return Manifest on success.
* Failure on process failure.
*/
- process::Future<Manifest> getManifest(
+ process::Future<DockerImageManifest> getManifest(
const Image::Name& imageName);
http://git-wip-us.apache.org/repos/asf/mesos/blob/48bc61a2/src/slave/containerizer/mesos/provisioner/docker/registry_puller.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/registry_puller.cpp b/src/slave/containerizer/mesos/provisioner/docker/registry_puller.cpp
index 94b7539..89f61c2 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/registry_puller.cpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/registry_puller.cpp
@@ -47,8 +47,6 @@ namespace internal {
namespace slave {
namespace docker {
-using FileSystemLayerInfo = registry::FileSystemLayerInfo;
-using Manifest = registry::Manifest;
using RegistryClient = registry::RegistryClient;
@@ -69,10 +67,11 @@ private:
Future<pair<string, string>> downloadLayer(
const Image::Name& imageName,
const Path& directory,
- const FileSystemLayerInfo& layer);
+ const string& blobSum,
+ const string& id);
Future<list<pair<string, string>>> downloadLayers(
- const Manifest& manifest,
+ const DockerImageManifest& manifest,
const Image::Name& imageName,
const Path& downloadDir);
@@ -190,46 +189,47 @@ RegistryPullerProcess::RegistryPullerProcess(
Future<pair<string, string>> RegistryPullerProcess::downloadLayer(
const Image::Name& imageName,
const Path& directory,
- const FileSystemLayerInfo& layer)
+ const string& blobSum,
+ const string& layerId)
{
- VLOG(1) << "Downloading layer '" << layer.layerId
+ VLOG(1) << "Downloading layer '" << layerId
<< "' for image '" << stringify(imageName) << "'";
- if (downloadTracker_.contains(layer.layerId)) {
+ if (downloadTracker_.contains(layerId)) {
VLOG(1) << "Download already in progress for image '"
- << stringify(imageName) << "', layer '" << layer.layerId << "'";
+ << stringify(imageName) << "', layer '" << layerId << "'";
- return downloadTracker_.at(layer.layerId)->future();
+ return downloadTracker_.at(layerId)->future();
}
Owned<Promise<pair<string, string>>> downloadPromise(
new Promise<pair<string, string>>());
- downloadTracker_.insert({layer.layerId, downloadPromise});
+ downloadTracker_.insert({layerId, downloadPromise});
- const Path downloadFile(path::join(directory, layer.layerId + ".tar"));
+ const Path downloadFile(path::join(directory, layerId + ".tar"));
registryClient_->getBlob(
imageName,
- layer.checksumInfo,
+ blobSum,
downloadFile)
.onAny(process::defer(
self(),
- [this, layer, downloadPromise, downloadFile](
+ [this, layerId, downloadPromise, downloadFile](
const Future<size_t>& future) {
- downloadTracker_.erase(layer.layerId);
+ downloadTracker_.erase(layerId);
if (!future.isReady()) {
downloadPromise->fail(
- "Failed to download layer '" + layer.layerId + "': " +
+ "Failed to download layer '" + layerId + "': " +
(future.isFailed() ? future.failure() : "future discarded"));
} else if (future.get() == 0) {
// We don't expect Docker registry to return empty response
// even with empty layers.
downloadPromise->fail(
- "Failed to download layer '" + layer.layerId + "': no content");
+ "Failed to download layer '" + layerId + "': no content");
} else {
- downloadPromise->set({layer.layerId, downloadFile});
+ downloadPromise->set({layerId, downloadFile});
}
}));
@@ -244,7 +244,7 @@ Future<list<pair<string, string>>> RegistryPullerProcess::pull(
// TODO(jojy): Have one outgoing manifest request per image.
return registryClient_->getManifest(imageName)
.then(process::defer(self(), [this, directory, imageName](
- const Manifest& manifest) {
+ const DockerImageManifest& manifest) {
return downloadLayers(manifest, imageName, directory);
}))
.then(process::defer(self(), [this, directory](
@@ -262,15 +262,18 @@ Future<list<pair<string, string>>> RegistryPullerProcess::pull(
Future<list<pair<string, string>>> RegistryPullerProcess::downloadLayers(
- const Manifest& manifest,
+ const DockerImageManifest& manifest,
const Image::Name& imageName,
const Path& directory)
{
list<Future<pair<string, string>>> downloadFutures;
- foreach (const FileSystemLayerInfo& layer, manifest.fsLayerInfos) {
+ for (int i = 0; i < manifest.fslayers_size(); i++) {
downloadFutures.push_back(
- downloadLayer(imageName, directory, layer));
+ downloadLayer(imageName,
+ directory,
+ manifest.fslayers(i).blobsum(),
+ manifest.history(i).v1compatibility().id()));
}
// TODO(jojy): Delete downloaded files in the directory on discard and
http://git-wip-us.apache.org/repos/asf/mesos/blob/48bc61a2/src/tests/containerizer/provisioner_docker_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/provisioner_docker_tests.cpp b/src/tests/containerizer/provisioner_docker_tests.cpp
index 88b914d..34d9762 100644
--- a/src/tests/containerizer/provisioner_docker_tests.cpp
+++ b/src/tests/containerizer/provisioner_docker_tests.cpp
@@ -688,7 +688,7 @@ TEST_F(RegistryClientTest, SimpleGetManifest)
ASSERT_SOME(registryClient);
- Future<Manifest> manifestResponse =
+ Future<DockerImageManifest> manifestResponse =
registryClient.get()->getManifest(parseImageName("library/busybox"));
const string unauthResponseHeaders = "Www-Authenticate: Bearer"
@@ -734,74 +734,75 @@ TEST_F(RegistryClientTest, SimpleGetManifest)
manifestHttpRequest = Socket(socket.get()).recv();
AWAIT_ASSERT_READY(manifestHttpRequest);
- const string manifestJSON = " \
- { \
- \"schemaVersion\": 1, \
- \"name\": \"library/busybox\", \
- \"tag\": \"latest\", \
- \"architecture\": \"amd64\", \
- \"fsLayers\": [ \
- { \
- \"blobSum\": \
- \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\" \
- }, \
- { \
- \"blobSum\": \
- \"sha256:1db09adb5ddd7f1a07b6d585a7db747a51c7bd17418d47e91f901bdf420abd66\" \
- }, \
- { \
- \"blobSum\": \
- \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\" \
- } \
- ], \
- \"history\": [ \
- { \
- \"v1Compatibility\": \
- \"{\\\"id\\\": \
- \\\"1ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\\\", \
- \\\"parent\\\": \
- \\\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\\\" \
- }\" \
- }, \
- { \
- \"v1Compatibility\": \
- \"{\\\"id\\\": \
- \\\"2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\\\", \
- \\\"parent\\\": \
- \\\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\\\" \
- }\" \
- }, \
- { \
- \"v1Compatibility\": \
- \"{\\\"id\\\": \
- \\\"3ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\\\", \
- \\\"parent\\\": \
- \\\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\\\" \
- }\" \
- } \
- ], \
- \"signatures\": [ \
- { \
- \"header\": { \
- \"jwk\": { \
- \"crv\": \"P-256\", \
- \"kid\": \
- \"OOI5:SI3T:LC7D:O7DX:FY6S:IAYW:WDRN:VQEM:BCFL:OIST:Q3LO:GTQQ\", \
- \"kty\": \"EC\", \
- \"x\": \"J2N5ePGhlblMI2cdsR6NrAG_xbNC_X7s1HRtk5GXvzM\", \
- \"y\": \"Idr-tEBjnNnfq6_71aeXBi3Z9ah_rrE209l4wiaohk0\" \
- }, \
- \"alg\": \"ES256\" \
- }, \
- \"signature\": \
-\"65vq57TakC_yperuhfefF4uvTbKO2L45gYGDs5bIEgOEarAs7_"
-"4dbEV5u-W7uR8gF6EDKfowUCmTq3a5vEOJ3w\", \
- \"protected\": \
- \"eyJmb3JtYXRMZW5ndGgiOjUwNTgsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS"
- "0wOC0xMVQwMzo0Mjo1OVoifQ\" \
- } \
- ] \
- }";
+ const string manifestJSON =
+ "{"
+ " \"schemaVersion\": 1,"
+ " \"name\": \"library/busybox\","
+ " \"tag\": \"latest\","
+ " \"architecture\": \"amd64\","
+ " \"fsLayers\": ["
+ " {"
+ " \"blobSum\": "
+ "\"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\""
+ " },"
+ " {"
+ " \"blobSum\": "
+ "\"sha256:1db09adb5ddd7f1a07b6d585a7db747a51c7bd17418d47e91f901bdf420abd66\""
+ " },"
+ " {"
+ " \"blobSum\": "
+ "\"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\""
+ " }"
+ " ],"
+ " \"history\": ["
+ " {"
+ " \"v1Compatibility\": "
+ " {"
+ " \"id\": "
+ "\"1ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
+ " \"parent\": "
+ "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
+ " }"
+ " },"
+ " {"
+ " \"v1Compatibility\": "
+ " {"
+ " \"id\": "
+ "\"2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
+ " \"parent\": "
+ "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
+ " }"
+ " },"
+ " {"
+ " \"v1Compatibility\": "
+ " {"
+ " \"id\": "
+ "\"3ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
+ " \"parent\": "
+ "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
+ " }"
+ " }"
+ " ],"
+ " \"signatures\": ["
+ " {"
+ " \"header\": {"
+ " \"jwk\": {"
+ " \"crv\": \"P-256\","
+ " \"kid\": "
+ "\"OOI5:SI3T:LC7D:O7DX:FY6S:IAYW:WDRN:VQEM:BCFL:OIST:Q3LO:GTQQ\","
+ " \"kty\": \"EC\","
+ " \"x\": \"J2N5ePGhlblMI2cdsR6NrAG_xbNC_X7s1HRtk5GXvzM\","
+ " \"y\": \"Idr-tEBjnNnfq6_71aeXBi3Z9ah_rrE209l4wiaohk0\""
+ " },"
+ " \"alg\": \"ES256\""
+ " },"
+ " \"signature\": \"65vq57TakC_yperuhfefF4uvTbKO2L45gYGDs5bIEgO"
+ "EarAs7_4dbEV5u-W7uR8gF6EDKfowUCmTq3a5vEOJ3w\","
+ " \"protected\": \"eyJmb3JtYXRMZW5ndGgiOjYwNjMsImZvcm1hdFRhaWwiOiJ"
+ "DbjAiLCJ0aW1lIjoiMjAxNC0wOS0xMVQxNzoxNDozMFoifQ\""
+ " }"
+ " ]"
+ "}";
const string manifestHttpResponse =
string("HTTP/1.1 200 OK\r\n") +
@@ -817,16 +818,16 @@ TEST_F(RegistryClientTest, SimpleGetManifest)
AWAIT_ASSERT_READY(manifestResponse);
- ASSERT_EQ(
- manifestResponse.get().fsLayerInfos[2].layerId,
+ EXPECT_EQ(
+ manifestResponse.get().history(2).v1compatibility().id(),
"1ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea");
- ASSERT_EQ(
- manifestResponse.get().fsLayerInfos[1].layerId,
+ EXPECT_EQ(
+ manifestResponse.get().history(1).v1compatibility().id(),
"2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea");
- ASSERT_EQ(
- manifestResponse.get().fsLayerInfos[0].layerId,
+ EXPECT_EQ(
+ manifestResponse.get().history(0).v1compatibility().id(),
"3ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea");
}
@@ -1063,50 +1064,49 @@ TEST_F(RegistryClientTest, SimpleRegistryPuller)
registryPullerHttpRequestFuture = Socket(socket.get()).recv();
AWAIT_ASSERT_READY(registryPullerHttpRequestFuture);
- const string manifestResponse = " \
- { \
- \"schemaVersion\": 1, \
- \"name\": \"library/busybox\", \
- \"tag\": \"latest\", \
- \"architecture\": \"amd64\", \
- \"fsLayers\": [ \
- { \
- \"blobSum\": \
- \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\" \
- } \
- ], \
- \"history\": [ \
- { \
- \"v1Compatibility\": \
- \"{\\\"id\\\": \
- \\\"1ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\\\", \
- \\\"parent\\\": \
- \\\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\\\" \
- }\" \
- } \
- ], \
- \"signatures\": [ \
- { \
- \"header\": { \
- \"jwk\": { \
- \"crv\": \"P-256\", \
- \"kid\": \
- \"OOI5:SI3T:LC7D:O7DX:FY6S:IAYW:WDRN:VQEM:BCFL:OIST:Q3LO:GTQQ\", \
- \"kty\": \"EC\", \
- \"x\": \"J2N5ePGhlblMI2cdsR6NrAG_xbNC_X7s1HRtk5GXvzM\", \
- \"y\": \"Idr-tEBjnNnfq6_71aeXBi3Z9ah_rrE209l4wiaohk0\" \
- }, \
- \"alg\": \"ES256\" \
- }, \
- \"signature\": \
-\"65vq57TakC_yperuhfefF4uvTbKO2L45gYGDs5bIEgOEarAs7_"
-"4dbEV5u-W7uR8gF6EDKfowUCmTq3a5vEOJ3w\", \
- \"protected\": \
- \"eyJmb3JtYXRMZW5ndGgiOjUwNTgsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS"
- "0wOC0xMVQwMzo0Mjo1OVoifQ\" \
- } \
- ] \
- }";
+ const string manifestResponse =
+ "{"
+ " \"schemaVersion\": 1,"
+ " \"name\": \"library/busybox\","
+ " \"tag\": \"latest\","
+ " \"architecture\": \"amd64\","
+ " \"fsLayers\": ["
+ " {"
+ " \"blobSum\": "
+ "\"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\""
+ " }"
+ " ],"
+ " \"history\": ["
+ " {"
+ " \"v1Compatibility\": "
+ " {"
+ " \"id\": "
+ "\"1ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
+ " \"parent\": "
+ "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
+ " }"
+ " }"
+ " ],"
+ " \"signatures\": ["
+ " {"
+ " \"header\": {"
+ " \"jwk\": {"
+ " \"crv\": \"P-256\","
+ " \"kid\": "
+ "\"OOI5:SI3T:LC7D:O7DX:FY6S:IAYW:WDRN:VQEM:BCFL:OIST:Q3LO:GTQQ\","
+ " \"kty\": \"EC\","
+ " \"x\": \"J2N5ePGhlblMI2cdsR6NrAG_xbNC_X7s1HRtk5GXvzM\","
+ " \"y\": \"Idr-tEBjnNnfq6_71aeXBi3Z9ah_rrE209l4wiaohk0\""
+ " },"
+ " \"alg\": \"ES256\""
+ " },"
+ " \"signature\": \"65vq57TakC_yperuhfefF4uvTbKO2L45gYGDs5bIEgO"
+ "EarAs7_4dbEV5u-W7uR8gF6EDKfowUCmTq3a5vEOJ3w\","
+ " \"protected\": \"eyJmb3JtYXRMZW5ndGgiOjYwNjMsImZvcm1hdFRhaWwiOiJ"
+ "DbjAiLCJ0aW1lIjoiMjAxNC0wOS0xMVQxNzoxNDozMFoifQ\""
+ " }"
+ " ]"
+ "}";
const string manifestHttpResponse =
string("HTTP/1.1 200 OK\r\n") +