You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by qi...@apache.org on 2017/03/28 09:24:29 UTC
[2/3] mesos git commit: Updated OCI spec parsing & validation code
with latest OCI image spec.
Updated OCI spec parsing & validation code with latest OCI image spec.
Review: https://reviews.apache.org/r/56852/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0c1d50d2
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0c1d50d2
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0c1d50d2
Branch: refs/heads/master
Commit: 0c1d50d236dbc100b9cbab194daba409483eed7a
Parents: 87ca2fb
Author: Qian Zhang <zh...@gmail.com>
Authored: Tue Mar 28 16:50:11 2017 +0800
Committer: Qian Zhang <zh...@gmail.com>
Committed: Tue Mar 28 16:50:11 2017 +0800
----------------------------------------------------------------------
include/mesos/oci/spec.hpp | 15 +++-
src/oci/spec.cpp | 152 +++++++++++++++++++++++++++-------------
2 files changed, 116 insertions(+), 51 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/0c1d50d2/include/mesos/oci/spec.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/oci/spec.hpp b/include/mesos/oci/spec.hpp
index ea4f29e..d8eef84 100644
--- a/include/mesos/oci/spec.hpp
+++ b/include/mesos/oci/spec.hpp
@@ -26,8 +26,8 @@ namespace v1 {
// Constant strings for OCI image media types:
// https://github.com/opencontainers/image-spec/blob/master/media-types.md
-constexpr char MEDIA_TYPE_MANIFEST_LIST[] =
- "application/vnd.oci.image.manifest.list.v1+json";
+constexpr char MEDIA_TYPE_INDEX[] =
+ "application/vnd.oci.image.index.v1+json";
constexpr char MEDIA_TYPE_MANIFEST[] =
"application/vnd.oci.image.manifest.v1+json";
@@ -36,13 +36,22 @@ constexpr char MEDIA_TYPE_CONFIG[] =
"application/vnd.oci.image.config.v1+json";
constexpr char MEDIA_TYPE_LAYER[] =
+ "application/vnd.oci.image.layer.v1.tar";
+
+constexpr char MEDIA_TYPE_LAYER_GZIP[] =
"application/vnd.oci.image.layer.v1.tar+gzip";
constexpr char MEDIA_TYPE_NONDIST_LAYER[] =
+ "application/vnd.oci.image.layer.nondistributable.v1.tar";
+
+constexpr char MEDIA_TYPE_NONDIST_LAYER_GZIP[] =
"application/vnd.oci.image.layer.nondistributable.v1.tar+gzip";
+// Rootfs type of OCI image configuration.
+constexpr char ROOTFS_TYPE[] = "layers";
+
/**
- * Returns the OCI v1 descriptor, image manifest list, image manifest
+ * Returns the OCI v1 descriptor, image index, image manifest
* and image configuration from the given string.
*/
template <typename T>
http://git-wip-us.apache.org/repos/asf/mesos/blob/0c1d50d2/src/oci/spec.cpp
----------------------------------------------------------------------
diff --git a/src/oci/spec.cpp b/src/oci/spec.cpp
index 0a88edb..06fceb4 100644
--- a/src/oci/spec.cpp
+++ b/src/oci/spec.cpp
@@ -43,25 +43,20 @@ Option<Error> validateDigest(const string& digest)
}
-Option<Error> validate(const ManifestList& manifestList)
+Option<Error> validate(const Index& index)
{
- if (manifestList.schemaversion() != 2) {
+ if (index.schemaversion() != 2) {
return Error(
"Incorrect 'schemaVersion': " +
- stringify(manifestList.schemaversion()));
+ stringify(index.schemaversion()));
}
- foreach (const ManifestDescriptor& manifest, manifestList.manifests()) {
+ foreach (const ManifestDescriptor& manifest, index.manifests()) {
Option<Error> error = validateDigest(manifest.digest());
if (error.isSome()) {
return Error(
"Failed to validate 'digest' of the 'manifest': " + error->message);
}
-
- if (manifest.mediatype() != MEDIA_TYPE_MANIFEST) {
- return Error(
- "Incorrect 'mediaType' of the 'manifest': " + manifest.mediatype());
- }
}
return None();
@@ -101,7 +96,9 @@ Option<Error> validate(const Manifest& manifest)
}
if (layer.mediatype() != MEDIA_TYPE_LAYER &&
- layer.mediatype() != MEDIA_TYPE_NONDIST_LAYER) {
+ layer.mediatype() != MEDIA_TYPE_LAYER_GZIP &&
+ layer.mediatype() != MEDIA_TYPE_NONDIST_LAYER &&
+ layer.mediatype() != MEDIA_TYPE_NONDIST_LAYER_GZIP) {
return Error(
"Incorrect 'mediaType' of the 'layer': " + layer.mediatype());
}
@@ -110,6 +107,16 @@ Option<Error> validate(const Manifest& manifest)
return None();
}
+
+Option<Error> validate(const Configuration& configuration)
+{
+ if (configuration.rootfs().type() != ROOTFS_TYPE) {
+ return Error("Incorrect 'type': " + configuration.rootfs().type());
+ }
+
+ return None();
+}
+
} // namespace internal {
@@ -126,6 +133,28 @@ Try<Descriptor> parse(const string& s)
return Error("Protobuf parse failed: " + descriptor.error());
}
+ // Manually parse 'annotations' field.
+ Result<JSON::Value> annotations = json->find<JSON::Value>("annotations");
+ if (annotations.isError()) {
+ return Error(
+ "Failed to find 'annotations': " + annotations.error());
+ }
+
+ if (annotations.isSome() && !annotations->is<JSON::Null>()) {
+ foreachpair (const string& key,
+ const JSON::Value& value,
+ annotations->as<JSON::Object>().values) {
+ if (!value.is<JSON::String>()) {
+ return Error(
+ "The value of annotation key '" + key + "' is not a JSON string");
+ }
+
+ Label* annotation = descriptor->add_annotations();
+ annotation->set_key(key);
+ annotation->set_value(value.as<JSON::String>().value);
+ }
+ }
+
Option<Error> error = internal::validateDigest(descriptor->digest());
if (error.isSome()) {
return Error(
@@ -137,20 +166,20 @@ Try<Descriptor> parse(const string& s)
template <>
-Try<ManifestList> parse(const string& s)
+Try<Index> parse(const string& s)
{
Try<JSON::Object> json = JSON::parse<JSON::Object>(s);
if (json.isError()) {
return Error("JSON parse failed: " + json.error());
}
- Try<ManifestList> manifestList = protobuf::parse<ManifestList>(json.get());
- if (manifestList.isError()) {
- return Error("Protobuf parse failed: " + manifestList.error());
+ Try<Index> index = protobuf::parse<Index>(json.get());
+ if (index.isError()) {
+ return Error("Protobuf parse failed: " + index.error());
}
- // Manually parse 'manifest.platform.os.version' and
- // 'manifest.platform.os.features'.
+ // Manually parse 'manifest.annotations', 'manifest.platform.os.version'
+ // and 'manifest.platform.os.features'.
Result<JSON::Array> manifests = json->at<JSON::Array>("manifests");
if (manifests.isError()) {
return Error("Failed to find 'manifests': " + manifests.error());
@@ -172,9 +201,9 @@ Try<ManifestList> parse(const string& s)
}
ManifestDescriptor* _manifest = nullptr;
- for (int i = 0; i < manifestList->manifests_size(); i++) {
- if (manifestList->manifests(i).digest() == digest.get()) {
- _manifest = manifestList->mutable_manifests(i);
+ for (int i = 0; i < index->manifests_size(); i++) {
+ if (index->manifests(i).digest() == digest.get()) {
+ _manifest = index->mutable_manifests(i);
break;
}
}
@@ -185,40 +214,61 @@ Try<ManifestList> parse(const string& s)
digest->value + "'");
}
- Result<JSON::Object> platform = manifest.at<JSON::Object>("platform");
- if (platform.isError()) {
- return Error("Failed to find 'platform': " + platform.error());
- } else if (platform.isNone()) {
- return Error("Unable to find 'platform'");
- }
-
- Result<JSON::String> osVersion = platform->at<JSON::String>("os.version");
- if (osVersion.isError()) {
+ Result<JSON::Value> annotations = manifest.find<JSON::Value>("annotations");
+ if (annotations.isError()) {
return Error(
- "Failed to find 'platform.os.version': " + osVersion.error());
+ "Failed to find 'annotations': " + annotations.error());
}
- if (osVersion.isSome()) {
- Platform* platform = _manifest->mutable_platform();
- platform->set_os_version(osVersion->value);
+ if (annotations.isSome() && !annotations->is<JSON::Null>()) {
+ foreachpair (const string& key,
+ const JSON::Value& value,
+ annotations->as<JSON::Object>().values) {
+ if (!value.is<JSON::String>()) {
+ return Error(
+ "The value of annotation key '" + key + "' is not a JSON string");
+ }
+
+ Label* annotation = _manifest->add_annotations();
+ annotation->set_key(key);
+ annotation->set_value(value.as<JSON::String>().value);
+ }
}
- Result<JSON::Array> osFeatures = platform->at<JSON::Array>("os.features");
- if (osFeatures.isError()) {
- return Error(
- "Failed to find 'platform.os.features': " + osFeatures.error());
+ Result<JSON::Object> platform = manifest.at<JSON::Object>("platform");
+ if (platform.isError()) {
+ return Error("Failed to find 'platform': " + platform.error());
}
- if (osFeatures.isSome()) {
- const vector<JSON::Value>& values = osFeatures->values;
- if (values.size() != 0) {
+ if (platform.isSome()) {
+ Result<JSON::String> osVersion = platform->at<JSON::String>("os.version");
+ if (osVersion.isError()) {
+ return Error(
+ "Failed to find 'platform.os.version': " + osVersion.error());
+ }
+
+ if (osVersion.isSome()) {
Platform* platform = _manifest->mutable_platform();
- foreach (const JSON::Value& value, values) {
- if (!value.is<JSON::String>()) {
- return Error("Expecting OS feature to be string type");
- }
+ platform->set_os_version(osVersion->value);
+ }
- platform->add_os_features(value.as<JSON::String>().value);
+ Result<JSON::Array> osFeatures = platform->at<JSON::Array>("os.features");
+ if (osFeatures.isError()) {
+ return Error(
+ "Failed to find 'platform.os.features': " + osFeatures.error());
+ }
+
+ if (osFeatures.isSome()) {
+ const vector<JSON::Value>& values = osFeatures->values;
+ if (values.size() != 0) {
+ Platform* platform = _manifest->mutable_platform();
+ foreach (const JSON::Value& value, values) {
+ if (!value.is<JSON::String>()) {
+ return Error("Expecting OS feature to be string type");
+ }
+
+ platform->add_os_features(value.as<JSON::String>().value);
+ }
}
}
}
@@ -240,19 +290,19 @@ Try<ManifestList> parse(const string& s)
"The value of annotation key '" + key + "' is not a JSON string");
}
- Label* annotation = manifestList->add_annotations();
+ Label* annotation = index->add_annotations();
annotation->set_key(key);
annotation->set_value(value.as<JSON::String>().value);
}
}
- Option<Error> error = internal::validate(manifestList.get());
+ Option<Error> error = internal::validate(index.get());
if (error.isSome()) {
return Error(
- "OCI v1 image manifest list validation failed: " + error->message);
+ "OCI v1 image index validation failed: " + error->message);
}
- return manifestList.get();
+ return index.get();
}
@@ -368,6 +418,12 @@ Try<Configuration> parse(const string& s)
}
}
+ Option<Error> error = internal::validate(configuration.get());
+ if (error.isSome()) {
+ return Error(
+ "OCI v1 image configuration validation failed: " + error->message);
+ }
+
return configuration.get();
}