You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2016/01/04 18:28:45 UTC

[1/5] mesos git commit: Renamed FsLayers in docker v2 image manifest to FsLayer.

Repository: mesos
Updated Branches:
  refs/heads/master 4706504c5 -> b51a87229


Renamed FsLayers in docker v2 image manifest to FsLayer.

Review: https://reviews.apache.org/r/41839


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/570f78e5
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/570f78e5
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/570f78e5

Branch: refs/heads/master
Commit: 570f78e533cd9b509a811744022f670f9cdffb83
Parents: 4706504
Author: Jie Yu <yu...@gmail.com>
Authored: Thu Dec 31 23:12:24 2015 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Mon Jan 4 09:25:35 2016 -0800

----------------------------------------------------------------------
 src/slave/containerizer/mesos/provisioner/docker/spec.cpp | 4 ++--
 src/slave/containerizer/mesos/provisioner/docker/v2.proto | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/570f78e5/src/slave/containerizer/mesos/provisioner/docker/spec.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/spec.cpp b/src/slave/containerizer/mesos/provisioner/docker/spec.cpp
index 5bbd98c..4695b9d 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/spec.cpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/spec.cpp
@@ -87,8 +87,8 @@ Option<Error> validate(const docker::v2::ImageManifest& manifest)
                  "with corresponding 'history'");
   }
 
-  // FsLayers field validation.
-  foreach (const docker::v2::ImageManifest::FsLayers& fslayer,
+  // Verify 'fsLayers' field.
+  foreach (const docker::v2::ImageManifest::FsLayer& fslayer,
            manifest.fslayers()) {
     const string& blobSum = fslayer.blobsum();
     if (!strings::contains(blobSum, ":")) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/570f78e5/src/slave/containerizer/mesos/provisioner/docker/v2.proto
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/v2.proto b/src/slave/containerizer/mesos/provisioner/docker/v2.proto
index fdf159d..f9e5715 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/v2.proto
+++ b/src/slave/containerizer/mesos/provisioner/docker/v2.proto
@@ -27,11 +27,11 @@ message ImageManifest {
   required string tag = 2;
   required string architecture = 3;
 
-  message FsLayers {
+  message FsLayer {
     required string blobSum = 1;
   }
 
-  repeated FsLayers fsLayers = 4;
+  repeated FsLayer fsLayers = 4;
 
   message History {
     message V1Compatibility {


[5/5] mesos git commit: Moved docker spec tests to a separate file.

Posted by ji...@apache.org.
Moved docker spec tests to a separate file.

Review: https://reviews.apache.org/r/41843


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/b51a8722
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/b51a8722
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/b51a8722

Branch: refs/heads/master
Commit: b51a8722943c85264655ef1ce4bf0b95219c0ffc
Parents: df2223b
Author: Jie Yu <yu...@gmail.com>
Authored: Fri Jan 1 13:19:01 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Mon Jan 4 09:26:25 2016 -0800

----------------------------------------------------------------------
 src/Makefile.am                                 |   1 +
 src/tests/containerizer/docker_spec_tests.cpp   | 336 +++++++++++++++++++
 .../containerizer/provisioner_docker_tests.cpp  | 328 ------------------
 3 files changed, 337 insertions(+), 328 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/b51a8722/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index bdac044..e08e867 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1776,6 +1776,7 @@ mesos_tests_SOURCES =						\
   tests/common/recordio_tests.cpp				\
   tests/containerizer/composing_containerizer_tests.cpp		\
   tests/containerizer/docker_containerizer_tests.cpp		\
+  tests/containerizer/docker_spec_tests.cpp			\
   tests/containerizer/docker_tests.cpp				\
   tests/containerizer/external_containerizer_test.cpp		\
   tests/containerizer/isolator_tests.cpp			\

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51a8722/src/tests/containerizer/docker_spec_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/docker_spec_tests.cpp b/src/tests/containerizer/docker_spec_tests.cpp
new file mode 100644
index 0000000..d4ec2cf
--- /dev/null
+++ b/src/tests/containerizer/docker_spec_tests.cpp
@@ -0,0 +1,336 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gtest/gtest.h>
+
+#include <stout/gtest.hpp>
+#include <stout/json.hpp>
+
+#include "docker/spec.hpp"
+
+namespace spec = docker::spec;
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+class DockerSpecTest : public ::testing::Test {};
+
+
+TEST_F(DockerSpecTest, ParseV1ImageManifest)
+{
+  Try<JSON::Object> json = JSON::parse<JSON::Object>(
+      R"~(
+      {
+        "container": "7f652467f9e6d1b3bf51172868b9b0c2fa1c711b112f4e987029b1624dd6295f",
+        "parent": "cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54",
+        "created": "2015-09-21T20:15:47.866196515Z",
+        "config": {
+          "Hostname": "5f8e0e129ff1",
+          "Entrypoint": null,
+          "Env": null,
+          "OnBuild": null,
+          "OpenStdin": false,
+          "MacAddress": "",
+          "User": "",
+          "VolumeDriver": "",
+          "AttachStderr": false,
+          "AttachStdout": false,
+          "PublishService": "",
+          "NetworkDisabled": false,
+          "StdinOnce": false,
+          "Cmd": [ "sh" ],
+          "WorkingDir": "",
+          "AttachStdin": false,
+          "Volumes": null,
+          "Tty": false,
+          "Domainname": "",
+          "Image": "cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54",
+          "Labels": null,
+          "ExposedPorts": null
+        },
+        "container_config": {
+          "Hostname": "5f8e0e129ff1",
+          "Entrypoint": [ "./bin/start" ],
+          "Env": [
+            "LANG=C.UTF-8",
+            "JAVA_VERSION=8u66",
+            "JAVA_DEBIAN_VERSION=8u66-b01-1~bpo8+1",
+            "CA_CERTIFICATES_JAVA_VERSION=20140324"
+          ],
+          "OnBuild": null,
+          "OpenStdin": false,
+          "MacAddress": "",
+          "User": "",
+          "VolumeDriver": "",
+          "AttachStderr": false,
+          "AttachStdout": false,
+          "PublishService": "",
+          "NetworkDisabled": false,
+          "StdinOnce": false,
+          "Cmd": [
+            "/bin/sh",
+            "-c",
+            "#(nop) CMD [\"sh\"]"
+          ],
+          "WorkingDir": "/marathon",
+          "AttachStdin": false,
+          "Volumes": null,
+          "Tty": false,
+          "Domainname": "",
+          "Image": "cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54",
+          "Labels": null,
+          "ExposedPorts": null
+        },
+        "architecture": "amd64",
+        "docker_version": "1.8.2",
+        "os": "linux",
+        "id": "d7057cb020844f245031d27b76cb18af05db1cc3a96a29fa7777af75f5ac91a3",
+        "Size": 0
+      })~");
+
+  ASSERT_SOME(json);
+
+  Try<spec::v1::ImageManifest> manifest = spec::v1::parse(json.get());
+  ASSERT_SOME(manifest);
+
+  EXPECT_EQ(
+      "7f652467f9e6d1b3bf51172868b9b0c2fa1c711b112f4e987029b1624dd6295f",
+      manifest.get().container());
+
+  EXPECT_EQ(
+      "cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54",
+      manifest.get().parent());
+
+  EXPECT_EQ(
+      "./bin/start",
+      manifest.get().container_config().entrypoint(0));
+
+  EXPECT_EQ(
+      "LANG=C.UTF-8",
+      manifest.get().container_config().env(0));
+
+  EXPECT_EQ(
+      "JAVA_VERSION=8u66",
+      manifest.get().container_config().env(1));
+
+  EXPECT_EQ(
+      "JAVA_DEBIAN_VERSION=8u66-b01-1~bpo8+1",
+      manifest.get().container_config().env(2));
+
+  EXPECT_EQ(
+      "CA_CERTIFICATES_JAVA_VERSION=20140324",
+      manifest.get().container_config().env(3));
+
+  EXPECT_EQ("/bin/sh", manifest.get().container_config().cmd(0));
+  EXPECT_EQ("-c", manifest.get().container_config().cmd(1));
+
+  EXPECT_EQ(
+      "#(nop) CMD [\"sh\"]",
+      manifest.get().container_config().cmd(2));
+
+  EXPECT_EQ("sh", manifest.get().config().cmd(0));
+
+  EXPECT_EQ("1.8.2", manifest.get().docker_version());
+  EXPECT_EQ("amd64", manifest.get().architecture());
+  EXPECT_EQ("linux", manifest.get().os());
+  EXPECT_EQ(0u, manifest.get().size());
+}
+
+
+TEST_F(DockerSpecTest, ParseV2ImageManifest)
+{
+  Try<JSON::Object> json = JSON::parse<JSON::Object>(
+      R"~(
+      {
+        "name": "dmcgowan/test-image",
+        "tag": "latest",
+        "architecture": "amd64",
+        "fsLayers": [
+          { "blobSum": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" },
+          { "blobSum": "sha256:cea0d2071b01b0a79aa4a05ea56ab6fdf3fafa03369d9f4eea8d46ea33c43e5f" },
+          { "blobSum": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" },
+          { "blobSum": "sha256:2a7812e636235448785062100bb9103096aa6655a8f6bb9ac9b13fe8290f66df" }
+        ],
+        "history": [
+          {
+            "v1Compatibility": {
+              "id": "2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea",
+              "parent": "cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff"
+            }
+          },
+          {
+            "v1Compatibility": {
+              "id": "2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea",
+              "parent": "cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff"
+            }
+          },
+          {
+            "v1Compatibility": {
+              "id": "2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea",
+              "parent": "cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff"
+            }
+          },
+          {
+            "v1Compatibility": {
+              "id": "2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea",
+              "parent": "cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff"
+            }
+          }
+        ],
+        "schemaVersion": 1,
+        "signatures": [
+          {
+            "header": {
+              "jwk": {
+                "crv": "P-256",
+                "kid": "LYRA:YAG2:QQKS:376F:QQXY:3UNK:SXH7:K6ES:Y5AU:XUN5:ZLVY:KBYL",
+                "kty": "EC",
+                "x": "Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ",
+                "y": "zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8"
+              },
+              "alg": "ES256"
+            },
+            "signature": "m3bgdBXZYRQ4ssAbrgj8Kjl7GNgrKQvmCSY-00yzQosKi-8UBrIRrn3Iu5alj82B6u_jNrkGCjEx3TxrfT1rig",
+            "protected": "eyJmb3JtYXRMZW5ndGgiOjYwNjMsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNC0wOS0xMVQxNzoxNDozMFoifQ"
+          }
+        ]
+      })~");
+
+  ASSERT_SOME(json);
+
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
+  ASSERT_SOME(manifest);
+
+  EXPECT_EQ(manifest.get().name(), "dmcgowan/test-image");
+  EXPECT_EQ(manifest.get().tag(), "latest");
+  EXPECT_EQ(manifest.get().architecture(), "amd64");
+
+  EXPECT_EQ(
+      manifest.get().fslayers(0).blobsum(),
+      "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); // NOLINT(whitespace/line_length)
+
+  EXPECT_EQ(
+      manifest.get().fslayers(1).blobsum(),
+      "sha256:cea0d2071b01b0a79aa4a05ea56ab6fdf3fafa03369d9f4eea8d46ea33c43e5f"); // NOLINT(whitespace/line_length)
+
+  EXPECT_EQ(
+      manifest.get().fslayers(2).blobsum(),
+      "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); // NOLINT(whitespace/line_length)
+
+  EXPECT_EQ(
+      manifest.get().fslayers(3).blobsum(),
+      "sha256:2a7812e636235448785062100bb9103096aa6655a8f6bb9ac9b13fe8290f66df"); // NOLINT(whitespace/line_length)
+
+  EXPECT_EQ(
+      manifest.get().history(1).v1compatibility().id(),
+      "2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea");
+
+  EXPECT_EQ(
+      manifest.get().history(2).v1compatibility().parent(),
+      "cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff");
+
+  EXPECT_EQ(manifest.get().schemaversion(), 1u);
+
+  EXPECT_EQ(
+      manifest.get().signatures(0).header().jwk().kid(),
+      "LYRA:YAG2:QQKS:376F:QQXY:3UNK:SXH7:K6ES:Y5AU:XUN5:ZLVY:KBYL");
+
+  EXPECT_EQ(
+      manifest.get().signatures(0).signature(),
+      "m3bgdBXZYRQ4ssAbrgj8Kjl7GNgrKQvmCSY-00yzQosKi-8UBrIRrn3Iu5alj82B6u_jNrkGCjEx3TxrfT1rig"); // NOLINT(whitespace/line_length)
+}
+
+
+TEST_F(DockerSpecTest, ParseInvalidV2ImageManifest)
+{
+  // This is an invalid manifest. The size of the repeated fields
+  // 'history' and 'fsLayers' must be >= 1. The 'signatures' and
+  // 'schemaVersion' fields are not set.
+  Try<JSON::Object> json = JSON::parse<JSON::Object>(
+      R"~(
+      {
+        "name": "dmcgowan/test-image",
+        "tag": "latest",
+        "architecture": "amd64"
+      })~");
+
+  ASSERT_SOME(json);
+
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
+  EXPECT_ERROR(manifest);
+}
+
+
+TEST_F(DockerSpecTest, ValidateV2ImageManifestFsLayersNonEmpty)
+{
+  Try<JSON::Object> json = JSON::parse<JSON::Object>(
+    R"~(
+    {
+      "name": "dmcgowan/test-image",
+      "tag": "latest",
+      "architecture": "amd64",
+      "schemaVersion": 1,
+      "signatures": [
+        {
+          "header": {
+            "jwk": {
+              "crv": "P-256",
+              "kid": "LYRA:YAG2:QQKS:376F:QQXY:3UNK:SXH7:K6ES:Y5AU:XUN5:ZLVY:KBYL",
+              "kty": "EC",
+              "x": "Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ",
+              "y": "zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8"
+            },
+            "alg": "ES256"
+          },
+          "signature": "m3bgdBXZYRQ4ssAbrgj8Kjl7GNgrKQvmCSY-00yzQosKi-8UBrIRrn3Iu5alj82B6u_jNrkGCjEx3TxrfT1rig",
+          "protected": "eyJmb3JtYXRMZW5ndGgiOjYwNjMsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNC0wOS0xMVQxNzoxNDozMFoifQ"
+        }
+      ]
+    })~");
+
+  ASSERT_SOME(json);
+
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
+  EXPECT_ERROR(manifest);
+}
+
+
+TEST_F(DockerSpecTest, ValidateV2ImageManifestSignaturesNonEmpty)
+{
+  Try<JSON::Object> json = JSON::parse<JSON::Object>(
+    R"~(
+    {
+      "name": "dmcgowan/test-image",
+      "tag": "latest",
+      "architecture": "amd64",
+      "fsLayers": [
+        {
+          "blobSum": "sha256:2a7812e636235448785062100bb9103096aa6655a8f6bb9ac9b13fe8290f66df"
+        }
+      ],
+      "schemaVersion": 1
+    })~");
+
+  ASSERT_SOME(json);
+
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
+  EXPECT_ERROR(manifest);
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/b51a8722/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 2d1b2be..959540f 100644
--- a/src/tests/containerizer/provisioner_docker_tests.cpp
+++ b/src/tests/containerizer/provisioner_docker_tests.cpp
@@ -308,334 +308,6 @@ TEST_F(RegistryTokenTest, NotBeforeInFuture)
 }
 
 
-class DockerSpecTest : public ::testing::Test {};
-
-
-TEST_F(DockerSpecTest, SerializeV1DockerManifest)
-{
-  JSON::Value manifestJson = JSON::parse(
-    "{"
-    "    \"container\": "
-    "\"7f652467f9e6d1b3bf51172868b9b0c2fa1c711b112f4e987029b1624dd6295f\","
-    "    \"parent\": "
-    "\"cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54\","
-    "    \"created\": \"2015-09-21T20:15:47.866196515Z\","
-    "    \"config\": {"
-    "        \"Hostname\": \"5f8e0e129ff1\","
-    "        \"Entrypoint\": null,"
-    "        \"Env\": null,"
-    "        \"OnBuild\": null,"
-    "        \"OpenStdin\": false,"
-    "        \"MacAddress\": \"\","
-    "        \"User\": \"\","
-    "        \"VolumeDriver\": \"\","
-    "        \"AttachStderr\": false,"
-    "        \"AttachStdout\": false,"
-    "        \"PublishService\": \"\","
-    "        \"NetworkDisabled\": false,"
-    "        \"StdinOnce\": false,"
-    "        \"Cmd\": ["
-    "            \"sh\""
-    "        ],"
-    "        \"WorkingDir\": \"\","
-    "        \"AttachStdin\": false,"
-    "        \"Volumes\": null,"
-    "        \"Tty\": false,"
-    "        \"Domainname\": \"\","
-    "        \"Image\": "
-    "\"cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54\","
-    "        \"Labels\": null,"
-    "        \"ExposedPorts\": null"
-    "    },"
-    "    \"container_config\": {"
-    "        \"Hostname\": \"5f8e0e129ff1\","
-    "        \"Entrypoint\": ["
-    "            \"./bin/start\""
-    "        ],"
-    "        \"Env\": ["
-    "            \"LANG=C.UTF-8\","
-    "            \"JAVA_VERSION=8u66\","
-    "            \"JAVA_DEBIAN_VERSION=8u66-b01-1~bpo8+1\","
-    "            \"CA_CERTIFICATES_JAVA_VERSION=20140324\""
-    "        ],"
-    "        \"OnBuild\": null,"
-    "        \"OpenStdin\": false,"
-    "        \"MacAddress\": \"\","
-    "        \"User\": \"\","
-    "        \"VolumeDriver\": \"\","
-    "        \"AttachStderr\": false,"
-    "        \"AttachStdout\": false,"
-    "        \"PublishService\": \"\","
-    "        \"NetworkDisabled\": false,"
-    "        \"StdinOnce\": false,"
-    "        \"Cmd\": ["
-    "            \"/bin/sh\","
-    "            \"-c\","
-    "            \"#(nop) CMD [\\\"sh\\\"]\""
-    "        ],"
-    "        \"WorkingDir\": \"/marathon\","
-    "        \"AttachStdin\": false,"
-    "        \"Volumes\": null,"
-    "        \"Tty\": false,"
-    "        \"Domainname\": \"\","
-    "        \"Image\": "
-    "\"cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54\","
-    "        \"Labels\": null,"
-    "        \"ExposedPorts\": null"
-    "    },"
-    "    \"architecture\": \"amd64\","
-    "    \"docker_version\": \"1.8.2\","
-    "    \"os\": \"linux\","
-    "    \"id\": "
-    "\"d7057cb020844f245031d27b76cb18af05db1cc3a96a29fa7777af75f5ac91a3\","
-    "    \"Size\": 0"
-    "}").get();
-
-  Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
-  ASSERT_SOME(json);
-
-  Try<spec::v1::ImageManifest> manifest = spec::v1::parse(json.get());
-  ASSERT_SOME(manifest);
-
-  EXPECT_EQ(
-      "7f652467f9e6d1b3bf51172868b9b0c2fa1c711b112f4e987029b1624dd6295f",
-      manifest.get().container());
-  EXPECT_EQ(
-      "cfa753dfea5e68a24366dfba16e6edf573daa447abf65bc11619c1a98a3aff54",
-      manifest.get().parent());
-
-  EXPECT_EQ(
-      "./bin/start",
-      manifest.get().container_config().entrypoint(0));
-
-  EXPECT_EQ(
-      "LANG=C.UTF-8",
-      manifest.get().container_config().env(0));
-  EXPECT_EQ(
-      "JAVA_VERSION=8u66",
-      manifest.get().container_config().env(1));
-  EXPECT_EQ(
-      "JAVA_DEBIAN_VERSION=8u66-b01-1~bpo8+1",
-      manifest.get().container_config().env(2));
-  EXPECT_EQ(
-      "CA_CERTIFICATES_JAVA_VERSION=20140324",
-      manifest.get().container_config().env(3));
-
-  EXPECT_EQ("/bin/sh", manifest.get().container_config().cmd(0));
-  EXPECT_EQ("-c", manifest.get().container_config().cmd(1));
-  EXPECT_EQ(
-      "#(nop) CMD [\"sh\"]",
-      manifest.get().container_config().cmd(2));
-
-  EXPECT_EQ("sh", manifest.get().config().cmd(0));
-
-  EXPECT_EQ("1.8.2", manifest.get().docker_version());
-  EXPECT_EQ("amd64", manifest.get().architecture());
-  EXPECT_EQ("linux", manifest.get().os());
-  EXPECT_EQ(0u, manifest.get().size());
-}
-
-
-TEST_F(DockerSpecTest, SerializeV2DockerManifest)
-{
-  JSON::Value manifestJson = JSON::parse(
-    "{"
-    "   \"name\": \"dmcgowan/test-image\","
-    "   \"tag\": \"latest\","
-    "   \"architecture\": \"amd64\","
-    "   \"fsLayers\": ["
-    "      {"
-    "         \"blobSum\": "
-  "\"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\""
-    "      },"
-    "      {"
-    "         \"blobSum\": "
-  "\"sha256:cea0d2071b01b0a79aa4a05ea56ab6fdf3fafa03369d9f4eea8d46ea33c43e5f\""
-    "      },"
-    "      {"
-    "         \"blobSum\": "
-  "\"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\""
-    "      },"
-    "      {"
-    "         \"blobSum\": "
-  "\"sha256:2a7812e636235448785062100bb9103096aa6655a8f6bb9ac9b13fe8290f66df\""
-    "      }"
-    "   ],"
-    "   \"history\": ["
-    "      {"
-    "         \"v1Compatibility\": "
-    "           {"
-    "             \"id\": "
-    "\"2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
-    "             \"parent\": "
-    "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
-    "           }"
-    "      },"
-    "      {"
-    "         \"v1Compatibility\": "
-    "           {"
-    "             \"id\": "
-    "\"2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
-    "             \"parent\": "
-    "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
-    "           }"
-    "      },"
-    "      {"
-    "         \"v1Compatibility\": "
-    "           {"
-    "             \"id\": "
-    "\"2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
-    "             \"parent\": "
-    "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
-    "           }"
-    "      },"
-    "      {"
-    "         \"v1Compatibility\": "
-    "           {"
-    "             \"id\": "
-    "\"2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea\","
-    "             \"parent\": "
-    "\"cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff\""
-    "           }"
-    "      }"
-    "   ],"
-    "   \"schemaVersion\": 1,"
-    "   \"signatures\": ["
-    "      {"
-    "         \"header\": {"
-    "            \"jwk\": {"
-    "               \"crv\": \"P-256\","
-    "               \"kid\": "
-    "\"LYRA:YAG2:QQKS:376F:QQXY:3UNK:SXH7:K6ES:Y5AU:XUN5:ZLVY:KBYL\","
-    "               \"kty\": \"EC\","
-    "               \"x\": \"Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ\","
-    "               \"y\": \"zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8\""
-    "            },"
-    "            \"alg\": \"ES256\""
-    "         },"
-    "         \"signature\": \"m3bgdBXZYRQ4ssAbrgj8Kjl7GNgrKQvmCSY-00yzQosKi-8"
-    "UBrIRrn3Iu5alj82B6u_jNrkGCjEx3TxrfT1rig\","
-    "         \"protected\": \"eyJmb3JtYXRMZW5ndGgiOjYwNjMsImZvcm1hdFRhaWwiOiJ"
-    "DbjAiLCJ0aW1lIjoiMjAxNC0wOS0xMVQxNzoxNDozMFoifQ\""
-    "      }"
-    "   ]"
-    "}").get();
-
-  Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
-  ASSERT_SOME(json);
-
-  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
-  ASSERT_SOME(manifest);
-
-  EXPECT_EQ(manifest.get().name(), "dmcgowan/test-image");
-  EXPECT_EQ(manifest.get().tag(), "latest");
-  EXPECT_EQ(manifest.get().architecture(), "amd64");
-
-  EXPECT_EQ(manifest.get().fslayers(0).blobsum(),
-    "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
-  EXPECT_EQ(manifest.get().fslayers(1).blobsum(),
-    "sha256:cea0d2071b01b0a79aa4a05ea56ab6fdf3fafa03369d9f4eea8d46ea33c43e5f");
-  EXPECT_EQ(manifest.get().fslayers(2).blobsum(),
-    "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
-  EXPECT_EQ(manifest.get().fslayers(3).blobsum(),
-    "sha256:2a7812e636235448785062100bb9103096aa6655a8f6bb9ac9b13fe8290f66df");
-
-  EXPECT_EQ(manifest.get().history(1).v1compatibility().id(),
-    "2ce2e90b0bc7224de3db1f0d646fe8e2c4dd37f1793928287f6074bc451a57ea");
-  EXPECT_EQ(manifest.get().history(2).v1compatibility().parent(),
-    "cf2616975b4a3cba083ca99bc3f0bf25f5f528c3c52be1596b30f60b0b1c37ff");
-
-  EXPECT_EQ(manifest.get().schemaversion(), 1u);
-
-  EXPECT_EQ(manifest.get().signatures(0).header().jwk().kid(),
-    "LYRA:YAG2:QQKS:376F:QQXY:3UNK:SXH7:K6ES:Y5AU:XUN5:ZLVY:KBYL");
-  EXPECT_EQ(manifest.get().signatures(0).signature(),
-    "m3bgdBXZYRQ4ssAbrgj8Kjl7GNgrKQvmCSY-00yzQosKi-8"
-    "UBrIRrn3Iu5alj82B6u_jNrkGCjEx3TxrfT1rig");
-}
-
-// Test invalid JSON object, expecting an error.
-TEST_F(DockerSpecTest, SerializeV2DockerInvalidManifest)
-{
-  // This is an invalid manifest. The repeated fields 'history' and 'fsLayers'
-  // must be >= 1. The 'signatures' and 'schemaVersion' are not set.
-  JSON::Value manifestJson = JSON::parse(
-    "{"
-    "   \"name\": \"dmcgowan/test-image\","
-    "   \"tag\": \"latest\","
-    "   \"architecture\": \"amd64\""
-    "}").get();
-
-  Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
-  ASSERT_SOME(json);
-
-
-  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
-  EXPECT_ERROR(manifest);
-}
-
-// Test Manifest Validation with empty repeated 'fsLayers' field.
-TEST_F(DockerSpecTest, ValidationV2DockerManifestFsLayersNonEmpty)
-{
-  JSON::Value manifestJson = JSON::parse(
-    "{"
-    "   \"name\": \"dmcgowan/test-image\","
-    "   \"tag\": \"latest\","
-    "   \"architecture\": \"amd64\","
-    "   \"schemaVersion\": 1,"
-    "   \"signatures\": ["
-    "      {"
-    "         \"header\": {"
-    "            \"jwk\": {"
-    "               \"crv\": \"P-256\","
-    "               \"kid\": "
-    "\"LYRA:YAG2:QQKS:376F:QQXY:3UNK:SXH7:K6ES:Y5AU:XUN5:ZLVY:KBYL\","
-    "               \"kty\": \"EC\","
-    "               \"x\": \"Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ\","
-    "               \"y\": \"zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8\""
-    "            },"
-    "            \"alg\": \"ES256\""
-    "         },"
-    "         \"signature\": \"m3bgdBXZYRQ4ssAbrgj8Kjl7GNgrKQvmCSY-00yzQosKi-8"
-    "UBrIRrn3Iu5alj82B6u_jNrkGCjEx3TxrfT1rig\","
-    "         \"protected\": \"eyJmb3JtYXRMZW5ndGgiOjYwNjMsImZvcm1hdFRhaWwiOiJ"
-    "DbjAiLCJ0aW1lIjoiMjAxNC0wOS0xMVQxNzoxNDozMFoifQ\""
-    "      }"
-    "   ]"
-    "}").get();
-
-  Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
-  ASSERT_SOME(json);
-
-  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
-  EXPECT_ERROR(manifest);
-}
-
-// Test Manifest Validation with empty repeated 'signatures' field.
-TEST_F(DockerSpecTest, ValidationV2DockerManifestSignaturesNonEmpty)
-{
-  JSON::Value manifestJson = JSON::parse(
-    "{"
-    "   \"name\": \"dmcgowan/test-image\","
-    "   \"tag\": \"latest\","
-    "   \"architecture\": \"amd64\","
-    "   \"fsLayers\": ["
-    "      {"
-    "         \"blobSum\": "
-  "\"sha256:2a7812e636235448785062100bb9103096aa6655a8f6bb9ac9b13fe8290f66df\""
-    "      }"
-    "   ],"
-    "   \"schemaVersion\": 1"
-    "}").get();
-
-  Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
-  ASSERT_SOME(json);
-
-  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
-  EXPECT_ERROR(manifest);
-}
-
-
 #ifdef USE_SSL_SOCKET
 
 // Test suite for docker registry tests.


[4/5] mesos git commit: Small style fixes in docker tests.

Posted by ji...@apache.org.
Small style fixes in docker tests.

Review: https://reviews.apache.org/r/41842


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/df2223bf
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/df2223bf
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/df2223bf

Branch: refs/heads/master
Commit: df2223bf4521ccc8fb74b58a2eccff0769441586
Parents: ad9e8f5
Author: Jie Yu <yu...@gmail.com>
Authored: Fri Jan 1 13:17:23 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Mon Jan 4 09:26:25 2016 -0800

----------------------------------------------------------------------
 src/tests/containerizer/docker_tests.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/df2223bf/src/tests/containerizer/docker_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/docker_tests.cpp b/src/tests/containerizer/docker_tests.cpp
index 83eceac..72961af 100644
--- a/src/tests/containerizer/docker_tests.cpp
+++ b/src/tests/containerizer/docker_tests.cpp
@@ -70,6 +70,7 @@ class DockerTest : public MesosTest
   }
 };
 
+
 // This test tests the functionality of the docker's interfaces.
 TEST_F(DockerTest, ROOT_DOCKER_interface)
 {
@@ -457,6 +458,7 @@ TEST_F(DockerTest, ROOT_DOCKER_MountAbsolute)
 
 class DockerImageTest : public MesosTest {};
 
+
 // This test verifies that docker image constructor is able to read
 // entrypoint and environment from a docker inspect JSON object.
 TEST_F(DockerImageTest, ParseInspectonImage)
@@ -566,7 +568,6 @@ TEST_F(DockerImageTest, ParseInspectonImage)
             image.get().environment.get().at("CA_CERTIFICATES_JAVA_VERSION"));
 }
 
-
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {


[3/5] mesos git commit: Renamed Signatures in docker v2 image manifest to Signature.

Posted by ji...@apache.org.
Renamed Signatures in docker v2 image manifest to Signature.

Review: https://reviews.apache.org/r/41841


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/ad9e8f5a
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/ad9e8f5a
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/ad9e8f5a

Branch: refs/heads/master
Commit: ad9e8f5aa0627c3c63faf9a2ebdc1e50d3bf722a
Parents: 92fec0c
Author: Jie Yu <yu...@gmail.com>
Authored: Fri Jan 1 10:45:57 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Mon Jan 4 09:26:24 2016 -0800

----------------------------------------------------------------------
 src/docker/v2.proto | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/ad9e8f5a/src/docker/v2.proto
----------------------------------------------------------------------
diff --git a/src/docker/v2.proto b/src/docker/v2.proto
index 97bdf08..a1c3563 100644
--- a/src/docker/v2.proto
+++ b/src/docker/v2.proto
@@ -43,7 +43,7 @@ message ImageManifest {
   repeated History history = 5;
   required uint32 schemaVersion = 6;
 
-  message Signatures {
+  message Signature {
 
     //JOSE (A JSON Web Signature).
     message Header {
@@ -66,5 +66,5 @@ message ImageManifest {
     required string protected = 3;
   }
 
-  repeated Signatures signatures = 7;
+  repeated Signature signatures = 7;
 }


[2/5] mesos git commit: Moved docker spec to the top level.

Posted by ji...@apache.org.
Moved docker spec to the top level.

Review: https://reviews.apache.org/r/41840


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/92fec0cb
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/92fec0cb
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/92fec0cb

Branch: refs/heads/master
Commit: 92fec0cb30e44b6bdc8d0113f3f62315a6f8ecb5
Parents: 570f78e
Author: Jie Yu <yu...@gmail.com>
Authored: Fri Jan 1 10:09:33 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Mon Jan 4 09:26:23 2016 -0800

----------------------------------------------------------------------
 src/Makefile.am                                 |  22 ++--
 src/docker/spec.cpp                             | 111 ++++++++++++++++
 src/docker/spec.hpp                             |  64 ++++++++++
 src/docker/v1.hpp                               |  23 ++++
 src/docker/v1.proto                             |  68 ++++++++++
 src/docker/v2.hpp                               |  23 ++++
 src/docker/v2.proto                             |  70 ++++++++++
 .../mesos/provisioner/docker/message.hpp        |   2 -
 .../provisioner/docker/registry_client.cpp      |  12 +-
 .../provisioner/docker/registry_client.hpp      |   4 +-
 .../provisioner/docker/registry_puller.cpp      |  11 +-
 .../mesos/provisioner/docker/spec.cpp           | 127 -------------------
 .../mesos/provisioner/docker/spec.hpp           |  65 ----------
 .../mesos/provisioner/docker/v1.proto           |  70 ----------
 .../mesos/provisioner/docker/v2.proto           |  72 -----------
 .../containerizer/provisioner_docker_tests.cpp  |  48 +++----
 16 files changed, 411 insertions(+), 381 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index b58d6b5..bdac044 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -202,6 +202,10 @@ CXX_PROTOS =								\
   ../include/mesos/v1/scheduler/scheduler.pb.h
 
 CXX_PROTOS +=								\
+  docker/v1.pb.cc							\
+  docker/v1.pb.h							\
+  docker/v2.pb.cc							\
+  docker/v2.pb.h							\
   master/registry.pb.cc							\
   master/registry.pb.h							\
   messages/flags.pb.cc							\
@@ -209,11 +213,7 @@ CXX_PROTOS +=								\
   messages/messages.pb.cc						\
   messages/messages.pb.h						\
   slave/containerizer/mesos/provisioner/docker/message.pb.cc		\
-  slave/containerizer/mesos/provisioner/docker/message.pb.h		\
-  slave/containerizer/mesos/provisioner/docker/v1.pb.cc			\
-  slave/containerizer/mesos/provisioner/docker/v1.pb.h			\
-  slave/containerizer/mesos/provisioner/docker/v2.pb.cc			\
-  slave/containerizer/mesos/provisioner/docker/v2.pb.h
+  slave/containerizer/mesos/provisioner/docker/message.pb.h
 
 CXX_LOG_PROTOS =							\
   messages/log.pb.cc							\
@@ -533,12 +533,12 @@ nodist_libmesos_no_3rdparty_la_SOURCES = $(CXX_PROTOS)
 
 
 libmesos_no_3rdparty_la_SOURCES =					\
+  docker/v1.proto							\
+  docker/v2.proto							\
   master/registry.proto							\
   messages/flags.proto							\
   messages/messages.proto						\
-  slave/containerizer/mesos/provisioner/docker/message.proto		\
-  slave/containerizer/mesos/provisioner/docker/v1.proto			\
-  slave/containerizer/mesos/provisioner/docker/v2.proto
+  slave/containerizer/mesos/provisioner/docker/message.proto
 
 # TODO(tillt): Remove authentication/cram_md5/* which will enable us to
 # lose the immediate cyrus-sasl2 dependency.
@@ -557,6 +557,7 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   common/type_utils.cpp							\
   common/values.cpp							\
   docker/docker.cpp							\
+  docker/spec.cpp							\
   exec/exec.cpp								\
   files/files.cpp							\
   hdfs/hdfs.cpp								\
@@ -629,7 +630,6 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   slave/containerizer/mesos/provisioner/docker/puller.cpp		\
   slave/containerizer/mesos/provisioner/docker/registry_client.cpp	\
   slave/containerizer/mesos/provisioner/docker/registry_puller.cpp	\
-  slave/containerizer/mesos/provisioner/docker/spec.cpp			\
   slave/containerizer/mesos/provisioner/docker/store.cpp		\
   slave/containerizer/mesos/provisioner/docker/token_manager.cpp	\
   slave/resource_estimators/noop.cpp					\
@@ -666,6 +666,9 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   credentials/credentials.hpp						\
   docker/docker.hpp							\
   docker/executor.hpp							\
+  docker/spec.hpp							\
+  docker/v1.hpp								\
+  docker/v2.hpp								\
   examples/test_anonymous_module.hpp					\
   examples/test_module.hpp						\
   examples/utils.hpp							\
@@ -739,7 +742,6 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   slave/containerizer/mesos/provisioner/docker/puller.hpp		\
   slave/containerizer/mesos/provisioner/docker/registry_client.hpp	\
   slave/containerizer/mesos/provisioner/docker/registry_puller.hpp	\
-  slave/containerizer/mesos/provisioner/docker/spec.hpp			\
   slave/containerizer/mesos/provisioner/docker/store.hpp		\
   slave/containerizer/mesos/provisioner/docker/token_manager.hpp	\
   slave/qos_controllers/noop.hpp					\

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/docker/spec.cpp
----------------------------------------------------------------------
diff --git a/src/docker/spec.cpp b/src/docker/spec.cpp
new file mode 100644
index 0000000..6c1d4b6
--- /dev/null
+++ b/src/docker/spec.cpp
@@ -0,0 +1,111 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stout/foreach.hpp>
+#include <stout/json.hpp>
+#include <stout/none.hpp>
+#include <stout/protobuf.hpp>
+#include <stout/strings.hpp>
+
+#include "docker/spec.hpp"
+
+using std::string;
+
+namespace docker {
+namespace spec {
+namespace v1 {
+
+Option<Error> validate(const ImageManifest& manifest)
+{
+  // TODO(gilbert): Add validations.
+  return None();
+}
+
+
+Try<ImageManifest> parse(const JSON::Object& json)
+{
+  Try<ImageManifest> manifest = protobuf::parse<ImageManifest>(json);
+  if (manifest.isError()) {
+    return Error("Protobuf parse failed: " + manifest.error());
+  }
+
+  Option<Error> error = validate(manifest.get());
+  if (error.isSome()) {
+    return Error("Docker v1 image manifest validation failed: " +
+                 error.get().message);
+  }
+
+  return manifest.get();
+}
+
+} // namespace v1 {
+
+
+namespace v2 {
+
+Option<Error> validate(const ImageManifest& manifest)
+{
+  // Validate required fields are present,
+  // e.g., repeated fields that has to be >= 1.
+  if (manifest.fslayers_size() <= 0) {
+    return Error("'fsLayers' field size must be at least one");
+  }
+
+  if (manifest.history_size() <= 0) {
+    return Error("'history' field size must be at least one");
+  }
+
+  if (manifest.signatures_size() <= 0) {
+    return Error("'signatures' field size must be at least one");
+  }
+
+  // Verify that blobSum and v1Compatibility numbers are equal.
+  if (manifest.fslayers_size() != manifest.history_size()) {
+    return Error("The size of 'fsLayers' should be equal "
+                 "to the size of 'history'");
+  }
+
+  // Verify 'fsLayers' field.
+  foreach (const ImageManifest::FsLayer& fslayer, manifest.fslayers()) {
+    const string& blobSum = fslayer.blobsum();
+    if (!strings::contains(blobSum, ":")) {
+      return Error("Incorrect 'blobSum' format: " + blobSum);
+    }
+  }
+
+  return None();
+}
+
+
+Try<ImageManifest> parse(const JSON::Object& json)
+{
+  Try<ImageManifest> manifest = protobuf::parse<ImageManifest>(json);
+  if (manifest.isError()) {
+    return Error("Protobuf parse failed: " + manifest.error());
+  }
+
+  Option<Error> error = validate(manifest.get());
+  if (error.isSome()) {
+    return Error("Docker v2 image manifest validation failed: " +
+                 error.get().message);
+  }
+
+  return manifest.get();
+}
+
+} // namespace v2 {
+} // namespace spec {
+} // namespace docker {

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/docker/spec.hpp
----------------------------------------------------------------------
diff --git a/src/docker/spec.hpp b/src/docker/spec.hpp
new file mode 100644
index 0000000..74968f2
--- /dev/null
+++ b/src/docker/spec.hpp
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __DOCKER_SPEC_HPP__
+#define __DOCKER_SPEC_HPP__
+
+#include <stout/error.hpp>
+#include <stout/json.hpp>
+#include <stout/option.hpp>
+
+#include "docker/v1.hpp"
+#include "docker/v2.hpp"
+
+namespace docker {
+namespace spec {
+namespace v1 {
+
+/**
+ * Validates if the specified docker v1 image manifest conforms to the
+ * Docker v1 spec. Returns the error if the validation fails.
+ */
+Option<Error> validate(const ImageManifest& manifest);
+
+
+/**
+ * Returns the docker v1 image manifest from the given JSON object.
+ */
+Try<ImageManifest> parse(const JSON::Object& json);
+
+} // namespace v1 {
+
+
+namespace v2 {
+
+/**
+ * Validates if the specified v2 image manifest conforms to the Docker
+ * v2 spec. Returns the error if the validation fails.
+ */
+Option<Error> validate(const ImageManifest& manifest);
+
+
+/**
+ * Returns the docker v1 image manifest from the given JSON object.
+ */
+Try<ImageManifest> parse(const JSON::Object& json);
+
+} // namespace v2 {
+} // namespace spec {
+} // namespace docker {
+
+#endif // __DOCKER_SPEC_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/docker/v1.hpp
----------------------------------------------------------------------
diff --git a/src/docker/v1.hpp b/src/docker/v1.hpp
new file mode 100644
index 0000000..b7ec35f
--- /dev/null
+++ b/src/docker/v1.hpp
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __DOCKER_V1_HPP__
+#define __DOCKER_V1_HPP__
+
+// ONLY USEFUL AFTER RUNNING PROTOC.
+#include "docker/v1.pb.h"
+
+#endif // __DOCKER_V1_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/docker/v1.proto
----------------------------------------------------------------------
diff --git a/src/docker/v1.proto b/src/docker/v1.proto
new file mode 100644
index 0000000..fab3b08
--- /dev/null
+++ b/src/docker/v1.proto
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package docker.spec.v1;
+
+/**
+ * Protobuf for the Docker v1 image manifest JSON schema:
+ * https://github.com/docker/docker/blob/master/image/spec/v1.md
+ */
+message ImageManifest {
+  // Following docker code to define and order protobuf fields.
+  // https://github.com/docker/docker/blob/master/image/image.go
+  optional string id = 1;
+  optional string parent = 2;
+
+  // This field is used to comment user added comment. It is not
+  // covered in docker v1 doc, but it is included in docker code.
+  optional string comment = 3;
+
+  optional string created = 4;
+
+  // Container is the id of the container used to commit. It is
+  // not covered in docker v1 doc, but included in docker code.
+  optional string container = 5;
+
+  // TODO(gilbert): Add other config fields.
+  // Currently necessary rumtime config fields only. Please see:
+  // https://github.com/docker/docker/blob/master/runconfig/config.go
+  message Config {
+    optional string Hostname = 1;
+    repeated string Entrypoint = 2;
+    repeated string Env = 3;
+    optional string User = 4;
+    repeated string Cmd = 5;
+    optional string WorkingDir = 6;
+    optional string Volumes = 7;
+
+    // Name of the image as it was passed by the operator.
+    optional string Image = 8;
+
+    // TODO(gilbert): Create a message including string-message
+    // pair to match ExposedPoarts' map (map[nat.Port]struct{}).
+  }
+
+  optional Config container_config = 6;
+
+  optional string docker_version = 7;
+  optional string author = 8;
+
+  optional Config config = 9;
+
+  optional string architecture = 10;
+  optional string os = 11;
+  optional uint32 Size = 12;
+}

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/docker/v2.hpp
----------------------------------------------------------------------
diff --git a/src/docker/v2.hpp b/src/docker/v2.hpp
new file mode 100644
index 0000000..4b14969
--- /dev/null
+++ b/src/docker/v2.hpp
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __DOCKER_V2_HPP__
+#define __DOCKER_V2_HPP__
+
+// ONLY USEFUL AFTER RUNNING PROTOC.
+#include "docker/v2.pb.h"
+
+#endif // __DOCKER_V2_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/docker/v2.proto
----------------------------------------------------------------------
diff --git a/src/docker/v2.proto b/src/docker/v2.proto
new file mode 100644
index 0000000..97bdf08
--- /dev/null
+++ b/src/docker/v2.proto
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package docker.spec.v2;
+
+/**
+ * Protobuf for the Docker v2 image manifest JSON schema:
+ * https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-1.md
+ */
+message ImageManifest {
+  required string name = 1;
+  required string tag = 2;
+  required string architecture = 3;
+
+  message FsLayer {
+    required string blobSum = 1;
+  }
+
+  repeated FsLayer fsLayers = 4;
+
+  message History {
+    message V1Compatibility {
+      required string id = 1;
+      required string parent = 2;
+    }
+
+    required V1Compatibility v1Compatibility = 1;
+  }
+
+  repeated History history = 5;
+  required uint32 schemaVersion = 6;
+
+  message Signatures {
+
+    //JOSE (A JSON Web Signature).
+    message Header {
+
+      //JSON Web Key.
+      message Jwk {
+        required string crv = 1;
+        required string kid = 2;
+        required string kty = 3;
+        required string x = 4;
+        required string y = 5;
+      }
+
+      optional Jwk jwk = 1;
+      required string alg = 2;
+    }
+
+    required Header header = 1;
+    required string signature = 2;
+    required string protected = 3;
+  }
+
+  repeated Signatures signatures = 7;
+}

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/slave/containerizer/mesos/provisioner/docker/message.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/message.hpp b/src/slave/containerizer/mesos/provisioner/docker/message.hpp
index 5c07143..162e4c6 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/message.hpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/message.hpp
@@ -21,8 +21,6 @@
 
 // ONLY USEFUL AFTER RUNNING PROTOC.
 #include "slave/containerizer/mesos/provisioner/docker/message.pb.h"
-#include "slave/containerizer/mesos/provisioner/docker/v1.pb.h"
-#include "slave/containerizer/mesos/provisioner/docker/v2.pb.h"
 
 namespace mesos {
 namespace internal {

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/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 4e305ad..b74c760 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/registry_client.cpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/registry_client.cpp
@@ -37,7 +37,6 @@
 #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;
@@ -49,6 +48,7 @@ using process::Owned;
 using process::Process;
 
 namespace http = process::http;
+namespace spec = docker::spec;
 
 using http::Pipe;
 
@@ -67,7 +67,7 @@ public:
       const http::URL& authenticationServer,
       const Option<Credentials>& credentials);
 
-  Future<v2::ImageManifest> getManifest(
+  Future<spec::v2::ImageManifest> getManifest(
       const Image::Name& imageName);
 
   Future<size_t> getBlob(
@@ -167,7 +167,7 @@ RegistryClient::~RegistryClient()
 }
 
 
-Future<v2::ImageManifest> RegistryClient::getManifest(
+Future<spec::v2::ImageManifest> RegistryClient::getManifest(
     const Image::Name& imageName)
 {
   return dispatch(
@@ -534,7 +534,7 @@ string RegistryClientProcess::getRepositoryPath(
 }
 
 
-Future<v2::ImageManifest> RegistryClientProcess::getManifest(
+Future<spec::v2::ImageManifest> RegistryClientProcess::getManifest(
     const Image::Name& imageName)
 {
   http::URL manifestURL(registryServer_);
@@ -543,11 +543,11 @@ Future<v2::ImageManifest> RegistryClientProcess::getManifest(
 
   return doHttpGet(manifestURL, None(), false, true, None())
     .then(defer(self(), [this] (
-        const http::Response& response) -> Future<v2::ImageManifest> {
+        const http::Response& response) -> Future<spec::v2::ImageManifest> {
       // TODO(jojy): We dont use the digest that is returned in header.
       // This is a good place to validate the manifest.
 
-      Try<v2::ImageManifest> manifest =
+      Try<spec::v2::ImageManifest> manifest =
         spec::v2::parse(JSON::parse<JSON::Object>(response.body).get());
       if (manifest.isError()) {
         return Failure(

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/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 e73d4d7..bd6dace 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/registry_client.hpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/registry_client.hpp
@@ -29,6 +29,8 @@
 #include <process/http.hpp>
 #include <process/process.hpp>
 
+#include "docker/spec.hpp"
+
 #include "slave/containerizer/mesos/provisioner/docker/message.hpp"
 
 namespace mesos {
@@ -79,7 +81,7 @@ public:
    * @return Manifest on success.
    *         Failure on process failure.
    */
-  process::Future<v2::ImageManifest> getManifest(
+  process::Future<::docker::spec::v2::ImageManifest> getManifest(
       const Image::Name& imageName);
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/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 049d46c..bd2c836 100644
--- a/src/slave/containerizer/mesos/provisioner/docker/registry_puller.cpp
+++ b/src/slave/containerizer/mesos/provisioner/docker/registry_puller.cpp
@@ -28,6 +28,9 @@
 #include "slave/containerizer/mesos/provisioner/docker/paths.hpp"
 #include "slave/containerizer/mesos/provisioner/docker/registry_client.hpp"
 
+namespace http = process::http;
+namespace spec = docker::spec;
+
 using std::list;
 using std::pair;
 using std::string;
@@ -40,8 +43,6 @@ using process::Process;
 using process::Promise;
 using process::Subprocess;
 
-namespace http = process::http;
-
 namespace mesos {
 namespace internal {
 namespace slave {
@@ -71,7 +72,7 @@ private:
       const string& id);
 
   Future<list<pair<string, string>>> downloadLayers(
-      const v2::ImageManifest& manifest,
+      const spec::v2::ImageManifest& manifest,
       const Image::Name& imageName,
       const Path& downloadDir);
 
@@ -230,7 +231,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 v2::ImageManifest& manifest) {
+        const spec::v2::ImageManifest& manifest) {
       return downloadLayers(manifest, imageName, directory);
     }))
     .then(process::defer(self(), [this, directory](
@@ -248,7 +249,7 @@ Future<list<pair<string, string>>> RegistryPullerProcess::pull(
 
 
 Future<list<pair<string, string>>> RegistryPullerProcess::downloadLayers(
-    const v2::ImageManifest& manifest,
+    const spec::v2::ImageManifest& manifest,
     const Image::Name& imageName,
     const Path& directory)
 {

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/slave/containerizer/mesos/provisioner/docker/spec.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/spec.cpp b/src/slave/containerizer/mesos/provisioner/docker/spec.cpp
deleted file mode 100644
index 4695b9d..0000000
--- a/src/slave/containerizer/mesos/provisioner/docker/spec.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <stout/foreach.hpp>
-#include <stout/json.hpp>
-#include <stout/protobuf.hpp>
-#include <stout/strings.hpp>
-
-#include "slave/containerizer/mesos/provisioner/docker/spec.hpp"
-
-using std::string;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace docker {
-namespace spec {
-
-namespace v1 {
-
-// Validate if the specified v1 image manifest conforms to
-// the Docker v1 spec.
-Option<Error> validate(const docker::v1::ImageManifest& manifest)
-{
-  // TODO(gilbert): Add constraints to validate manifest.
-  return None();
-}
-
-
-Try<docker::v1::ImageManifest> parse(const JSON::Object& json)
-{
-  Try<docker::v1::ImageManifest> manifest =
-    protobuf::parse<docker::v1::ImageManifest>(json);
-
-  if (manifest.isError()) {
-    return Error("Protobuf parse failed: " + manifest.error());
-  }
-
-  Option<Error> error = validate(manifest.get());
-  if (error.isSome()) {
-    return Error("Docker v1 Image Manifest Validation failed: " +
-                 error.get().message);
-  }
-
-  return manifest.get();
-}
-
-} // namespace v1 {
-
-
-namespace v2 {
-
-// Validate if the specified v2 image manifest conforms to
-// the Docker v2 spec.
-Option<Error> validate(const docker::v2::ImageManifest& manifest)
-{
-  // Validate required fields are present,
-  // e.g., repeated fields that has to be >= 1.
-  if (manifest.fslayers_size() <= 0) {
-    return Error("'fsLayers' field size must be at least one");
-  }
-
-  if (manifest.history_size() <= 0) {
-    return Error("'history' field size must be at least one");
-  }
-
-  if (manifest.signatures_size() <= 0) {
-    return Error("'signatures' field size must be at least one");
-  }
-
-  // Verify that blobSum and v1Compatibility numbers are equal.
-  if (manifest.fslayers_size() != manifest.history_size()) {
-    return Error("There should be equal size of 'fsLayers' "
-                 "with corresponding 'history'");
-  }
-
-  // Verify 'fsLayers' field.
-  foreach (const docker::v2::ImageManifest::FsLayer& fslayer,
-           manifest.fslayers()) {
-    const string& blobSum = fslayer.blobsum();
-    if (!strings::contains(blobSum, ":")) {
-      return Error("Incorrect 'blobSum' format: " + blobSum);
-    }
-  }
-
-  return None();
-}
-
-
-Try<docker::v2::ImageManifest> parse(const JSON::Object& json)
-{
-  Try<docker::v2::ImageManifest> manifest =
-    protobuf::parse<docker::v2::ImageManifest>(json);
-
-  if (manifest.isError()) {
-    return Error("Protobuf parse failed: " + manifest.error());
-  }
-
-  Option<Error> error = validate(manifest.get());
-  if (error.isSome()) {
-    return Error("Docker v2 Image Manifest Validation failed: " +
-                 error.get().message);
-  }
-
-  return manifest.get();
-}
-
-} // namespace v2 {
-
-} // namespace spec {
-} // namespace docker {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/slave/containerizer/mesos/provisioner/docker/spec.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/spec.hpp b/src/slave/containerizer/mesos/provisioner/docker/spec.hpp
deleted file mode 100644
index 1bd4ac1..0000000
--- a/src/slave/containerizer/mesos/provisioner/docker/spec.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef __PROVISIONER_DOCKER_SPEC_HPP__
-#define __PROVISIONER_DOCKER_SPEC_HPP__
-
-#include <stout/error.hpp>
-#include <stout/json.hpp>
-#include <stout/option.hpp>
-
-#include <mesos/mesos.hpp>
-
-#include "slave/containerizer/mesos/provisioner/docker/message.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace docker {
-namespace spec {
-
-namespace v1 {
-
-// Validate if the specified v1 image manifest conforms to
-// the Docker v1 spec.
-Option<Error> validate(const docker::v1::ImageManifest& manifest);
-
-// Parse the v1::ImageManifest from the specified JSON object.
-Try<docker::v1::ImageManifest> parse(const JSON::Object& json);
-
-} // namespace v1 {
-
-
-namespace v2 {
-
-// Validate if the specified v2 image manifest conforms to
-// the Docker v2 spec.
-Option<Error> validate(const docker::v2::ImageManifest& manifest);
-
-// TODO(gilbert): Add validations here, e.g., Manifest, Blob, Layout, ImageID.
-
-// Parse the v2::ImageManifest from the specified JSON object.
-Try<docker::v2::ImageManifest> parse(const JSON::Object& json);
-
-} // namespace v2 {
-
-} // namespace spec {
-} // namespace docker {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __PROVISIONER_DOCKER_SPEC_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/slave/containerizer/mesos/provisioner/docker/v1.proto
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/v1.proto b/src/slave/containerizer/mesos/provisioner/docker/v1.proto
deleted file mode 100644
index 5aec78b..0000000
--- a/src/slave/containerizer/mesos/provisioner/docker/v1.proto
+++ /dev/null
@@ -1,70 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import "mesos/mesos.proto";
-
-package mesos.internal.slave.docker.v1;
-
-/**
- * Protobuf for the Docker v1 image manifest JSON schema:
- * https://github.com/docker/docker/blob/master/image/spec/v1.md
- */
-message ImageManifest {
-  // Following docker code to define and order protobuf fields.
-  // https://github.com/docker/docker/blob/master/image/image.go
-  optional string id = 1;
-  optional string parent = 2;
-
-  // This field is used to comment user added comment. It is not
-  // covered in docker v1 doc, but it is included in docker code.
-  optional string comment = 3;
-
-  optional string created = 4;
-
-  // Container is the id of the container used to commit. It is
-  // not covered in docker v1 doc, but included in docker code.
-  optional string container = 5;
-
-  // TODO(gilbert): Add other config fields.
-  // Currently necessary rumtime config fields only. Please see:
-  // https://github.com/docker/docker/blob/master/runconfig/config.go
-  message Config {
-    optional string Hostname = 1;
-    repeated string Entrypoint = 2;
-    repeated string Env = 3;
-    optional string User = 4;
-    repeated string Cmd = 5;
-    optional string WorkingDir = 6;
-    optional string Volumes = 7;
-
-    // Name of the image as it was passed by the operator.
-    optional string Image = 8;
-
-    // TODO(gilbert): Create a message including string-message
-    // pair to match ExposedPoarts' map (map[nat.Port]struct{}).
-  }
-
-  optional Config container_config = 6;
-
-  optional string docker_version = 7;
-  optional string author = 8;
-
-  optional Config config = 9;
-
-  optional string architecture = 10;
-  optional string os = 11;
-  optional uint32 Size = 12;
-}

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/src/slave/containerizer/mesos/provisioner/docker/v2.proto
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/docker/v2.proto b/src/slave/containerizer/mesos/provisioner/docker/v2.proto
deleted file mode 100644
index f9e5715..0000000
--- a/src/slave/containerizer/mesos/provisioner/docker/v2.proto
+++ /dev/null
@@ -1,72 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import "mesos/mesos.proto";
-
-package mesos.internal.slave.docker.v2;
-
-/**
- * Protobuf for the Docker v2 image manifest JSON schema:
- * https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-1.md
- */
-message ImageManifest {
-  required string name = 1;
-  required string tag = 2;
-  required string architecture = 3;
-
-  message FsLayer {
-    required string blobSum = 1;
-  }
-
-  repeated FsLayer fsLayers = 4;
-
-  message History {
-    message V1Compatibility {
-      required string id = 1;
-      required string parent = 2;
-    }
-
-    required V1Compatibility v1Compatibility = 1;
-  }
-
-  repeated History history = 5;
-  required uint32 schemaVersion = 6;
-
-  message Signatures {
-
-    //JOSE (A JSON Web Signature).
-    message Header {
-
-      //JSON Web Key.
-      message Jwk {
-        required string crv = 1;
-        required string kid = 2;
-        required string kty = 3;
-        required string x = 4;
-        required string y = 5;
-      }
-
-      optional Jwk jwk = 1;
-      required string alg = 2;
-    }
-
-    required Header header = 1;
-    required string signature = 2;
-    required string protected = 3;
-  }
-
-  repeated Signatures signatures = 7;
-}

http://git-wip-us.apache.org/repos/asf/mesos/blob/92fec0cb/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 d51f342..2d1b2be 100644
--- a/src/tests/containerizer/provisioner_docker_tests.cpp
+++ b/src/tests/containerizer/provisioner_docker_tests.cpp
@@ -32,24 +32,30 @@
 #include <process/clock.hpp>
 #include <process/future.hpp>
 #include <process/gmock.hpp>
+#include <process/io.hpp>
 #include <process/owned.hpp>
 #include <process/socket.hpp>
 #include <process/subprocess.hpp>
 
 #include <process/ssl/gtest.hpp>
 
+#include "docker/spec.hpp"
+
 #include "slave/containerizer/mesos/provisioner/docker/metadata_manager.hpp"
 #include "slave/containerizer/mesos/provisioner/docker/paths.hpp"
 #include "slave/containerizer/mesos/provisioner/docker/puller.hpp"
 #include "slave/containerizer/mesos/provisioner/docker/registry_client.hpp"
 #include "slave/containerizer/mesos/provisioner/docker/registry_puller.hpp"
-#include "slave/containerizer/mesos/provisioner/docker/spec.hpp"
 #include "slave/containerizer/mesos/provisioner/docker/store.hpp"
 #include "slave/containerizer/mesos/provisioner/docker/token_manager.hpp"
 
 #include "tests/mesos.hpp"
 #include "tests/utils.hpp"
 
+namespace io = process::io;
+namespace slave = mesos::internal::slave;
+namespace spec = ::docker::spec;
+
 using std::list;
 using std::map;
 using std::pair;
@@ -59,14 +65,20 @@ using std::vector;
 using process::Clock;
 using process::Future;
 using process::Owned;
+using process::Promise;
+using process::Subprocess;
 
 using process::network::Socket;
 
-using namespace process;
-using namespace mesos::internal::slave;
-using namespace mesos::internal::slave::docker;
-using namespace mesos::internal::slave::docker::paths;
-using namespace mesos::internal::slave::docker::registry;
+using slave::docker::parseImageName;
+using slave::docker::Puller;
+using slave::docker::RegistryPuller;
+
+using slave::docker::paths::getImageLayerRootfsPath;
+
+using slave::docker::registry::RegistryClient;
+using slave::docker::registry::Token;
+using slave::docker::registry::TokenManager;
 
 namespace mesos {
 namespace internal {
@@ -382,9 +394,7 @@ TEST_F(DockerSpecTest, SerializeV1DockerManifest)
   Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
   ASSERT_SOME(json);
 
-  Try<slave::docker::v1::ImageManifest> manifest =
-    spec::v1::parse(json.get());
-
+  Try<spec::v1::ImageManifest> manifest = spec::v1::parse(json.get());
   ASSERT_SOME(manifest);
 
   EXPECT_EQ(
@@ -514,9 +524,7 @@ TEST_F(DockerSpecTest, SerializeV2DockerManifest)
   Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
   ASSERT_SOME(json);
 
-  Try<slave::docker::v2::ImageManifest> manifest =
-    spec::v2::parse(json.get());
-
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
   ASSERT_SOME(manifest);
 
   EXPECT_EQ(manifest.get().name(), "dmcgowan/test-image");
@@ -562,9 +570,7 @@ TEST_F(DockerSpecTest, SerializeV2DockerInvalidManifest)
   ASSERT_SOME(json);
 
 
-  Try<slave::docker::v2::ImageManifest> manifest =
-    spec::v2::parse(json.get());
-
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
   EXPECT_ERROR(manifest);
 }
 
@@ -601,9 +607,7 @@ TEST_F(DockerSpecTest, ValidationV2DockerManifestFsLayersNonEmpty)
   Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
   ASSERT_SOME(json);
 
-  Try<slave::docker::v2::ImageManifest> manifest =
-    spec::v2::parse(json.get());
-
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
   EXPECT_ERROR(manifest);
 }
 
@@ -627,9 +631,7 @@ TEST_F(DockerSpecTest, ValidationV2DockerManifestSignaturesNonEmpty)
   Try<JSON::Object> json = JSON::parse<JSON::Object>(stringify(manifestJson));
   ASSERT_SOME(json);
 
-  Try<slave::docker::v2::ImageManifest> manifest =
-    spec::v2::parse(json.get());
-
+  Try<spec::v2::ImageManifest> manifest = spec::v2::parse(json.get());
   EXPECT_ERROR(manifest);
 }
 
@@ -799,7 +801,7 @@ TEST_F(RegistryClientTest, SimpleGetManifest)
 
   ASSERT_SOME(registryClient);
 
-  Future<v2::ImageManifest> manifestResponse =
+  Future<spec::v2::ImageManifest> manifestResponse =
     registryClient.get()->getManifest(parseImageName("library/busybox"));
 
   const string unauthResponseHeaders = "Www-Authenticate: Bearer"
@@ -1129,7 +1131,7 @@ TEST_F(RegistryClientTest, SimpleRegistryPuller)
 
   Future<Socket> blobServerAcceptSock = blobServer.get().accept();
 
-  Flags flags;
+  slave::Flags flags;
   process::network::Address address = server.get().address().get();
   const string url = "https://" + address.hostname().get() + ":" +
                      stringify(address.port);