Repository: mesos Updated Branches: refs/heads/master 2a8de6255 -> 7a4a7a53b
Added validation of *_NESTED_CONTAINER calls in the agent API. Review: https://reviews.apache.org/r/52100 Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/7a4a7a53 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/7a4a7a53 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/7a4a7a53 Branch: refs/heads/master Commit: 7a4a7a53b28fa90dcf7ba9626832b3d9b87f8b06 Parents: 31fb89f Author: Benjamin Mahler <bmah...@apache.org> Authored: Tue Sep 20 14:19:14 2016 -0700 Committer: Benjamin Mahler <bmah...@apache.org> Committed: Wed Sep 21 23:07:08 2016 -0700 ---------------------------------------------------------------------- src/Makefile.am | 1 + src/slave/validation.cpp | 62 +++++++++++- src/tests/slave_validation_tests.cpp | 157 ++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/7a4a7a53/src/Makefile.am ---------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index 478fb5a..239e5af 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2132,6 +2132,7 @@ mesos_tests_SOURCES = \ tests/script.cpp \ tests/slave_authorization_tests.cpp \ tests/slave_recovery_tests.cpp \ + tests/slave_validation_tests.cpp \ tests/slave_tests.cpp \ tests/sorter_tests.cpp \ tests/state_tests.cpp \ http://git-wip-us.apache.org/repos/asf/mesos/blob/7a4a7a53/src/slave/validation.cpp ---------------------------------------------------------------------- diff --git a/src/slave/validation.cpp b/src/slave/validation.cpp index d9c1aa8..62b2733 100644 --- a/src/slave/validation.cpp +++ b/src/slave/validation.cpp @@ -18,6 +18,7 @@ #include <mesos/agent/agent.hpp> +#include <stout/stringify.hpp> #include <stout/unreachable.hpp> #include <stout/uuid.hpp> @@ -100,14 +101,67 @@ Option<Error> validate( case mesos::agent::Call::GET_TASKS: return None(); - case mesos::agent::Call::LAUNCH_NESTED_CONTAINER: - return Error("Unimplemented"); + case mesos::agent::Call::LAUNCH_NESTED_CONTAINER: { + if (!call.has_launch_nested_container()) { + return Error("Expecting 'launch_nested_container' to be present"); + } + + const mesos::agent::Call::LaunchNestedContainer& launchNestedContainer = + call.launch_nested_container(); + + // The `ContainerID` must be a RFC-4122 Version 4 UUID + // in standard string format. + Try<UUID> uuid = UUID::fromString( + launchNestedContainer.container_id().value()); + + if (uuid.isError()) { + return Error("'launch_nested_container.container_id.value' must be" + " an RFC-4122 version 4 UUID in string format: " + + uuid.error()); + } + + if (uuid->version() != UUID::version_random_number_based) { + return Error("Expected version 4 UUID but was version" + " " + stringify(uuid->version())); + } + + // A single parent `ContainerID` is expected, so that we know + // which container to place it underneath. + if (!launchNestedContainer.container_id().has_parent()) { + return Error("Expecting 'launch_nested_container.container_id.parent'" + " to be present"); + } else if (launchNestedContainer.container_id().parent().has_parent()) { + return Error("Expecting a single parent ContainerID but" + " 'launch_nested_container.container_id.parent.parent'" + " is set"); + } + + return None(); + } case mesos::agent::Call::WAIT_NESTED_CONTAINER: - return Error("Unimplemented"); + if (!call.has_wait_nested_container()) { + return Error("Expecting 'wait_nested_container' to be present"); + } + + if (call.wait_nested_container().container_id().has_parent()) { + return Error("Not expecting 'wait_nested_container.container_id.parent'" + " to be present"); + } + + return None(); case mesos::agent::Call::KILL_NESTED_CONTAINER: - return Error("Unimplemented"); + if (!call.has_kill_nested_container()) { + return Error("Expecting 'kill_nested_container' to be present"); + } + + if (call.kill_nested_container().container_id().has_parent()) { + return Error("Not expecting 'kill_nested_container.container_id.parent'" + " to be present"); + } + + return None(); } UNREACHABLE(); http://git-wip-us.apache.org/repos/asf/mesos/blob/7a4a7a53/src/tests/slave_validation_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/slave_validation_tests.cpp b/src/tests/slave_validation_tests.cpp new file mode 100644 index 0000000..ee59aee --- /dev/null +++ b/src/tests/slave_validation_tests.cpp @@ -0,0 +1,157 @@ +// 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 <mesos/mesos.hpp> + +#include <mesos/agent/agent.hpp> + +#include <stout/error.hpp> +#include <stout/gtest.hpp> +#include <stout/option.hpp> +#include <stout/uuid.hpp> + +#include "slave/slave.hpp" +#include "slave/validation.hpp" + +namespace agent = mesos::agent; +namespace validation = mesos::internal::slave::validation; + +using mesos::internal::slave::Slave; + +namespace mesos { +namespace internal { +namespace tests { + + +TEST(AgentCallValidationTest, LaunchNestedContainer) +{ + // Missing `launch_nested_container`. + agent::Call call; + call.set_type(agent::Call::LAUNCH_NESTED_CONTAINER); + + Option<Error> error = validation::agent::call::validate(call); + EXPECT_SOME(error); + + // `container_id` is not a valid RFC-4122 Version 4 UUID. + ContainerID badContainerId; + badContainerId.set_value("not-a-uuid"); + + agent::Call::LaunchNestedContainer* launch = + call.mutable_launch_nested_container(); + + launch->mutable_container_id()->CopyFrom(badContainerId); + + error = validation::agent::call::validate(call); + EXPECT_SOME(error); + + // Valid `container_id` but missing `container_id.parent`. + ContainerID containerId; + containerId.set_value(UUID::random().toString()); + + launch->mutable_container_id()->CopyFrom(containerId); + + error = validation::agent::call::validate(call); + EXPECT_SOME(error); + + // Test the valid case. + ContainerID parentContainerId; + parentContainerId.set_value(UUID::random().toString()); + + launch->mutable_container_id()->mutable_parent()->CopyFrom(parentContainerId); + + error = validation::agent::call::validate(call); + EXPECT_NONE(error); + + // Not expecting a `container_id.parent.parent`. + ContainerID grandparentContainerId; + grandparentContainerId.set_value(UUID::random().toString()); + + launch->mutable_container_id()->mutable_parent()->mutable_parent() + ->CopyFrom(grandparentContainerId); + + error = validation::agent::call::validate(call); + EXPECT_SOME(error); +} + + +TEST(AgentCallValidationTest, WaitNestedContainer) +{ + // Missing `wait_nested_container`. + agent::Call call; + call.set_type(agent::Call::WAIT_NESTED_CONTAINER); + + Option<Error> error = validation::agent::call::validate(call); + EXPECT_SOME(error); + + // Test the valid case. + ContainerID containerId; + containerId.set_value(UUID::random().toString()); + + agent::Call::WaitNestedContainer* wait = + call.mutable_wait_nested_container(); + + wait->mutable_container_id()->CopyFrom(containerId); + + error = validation::agent::call::validate(call); + EXPECT_NONE(error); + + // Not expecting a `container_id.parent`. + ContainerID parentContainerId; + parentContainerId.set_value(UUID::random().toString()); + + wait->mutable_container_id()->mutable_parent()->CopyFrom(containerId); + + error = validation::agent::call::validate(call); + EXPECT_SOME(error); +} + + +TEST(AgentCallValidationTest, KillNestedContainer) +{ + // Missing `kill_nested_container`. + agent::Call call; + call.set_type(agent::Call::KILL_NESTED_CONTAINER); + + Option<Error> error = validation::agent::call::validate(call); + EXPECT_SOME(error); + + // Test the valid case. + ContainerID containerId; + containerId.set_value(UUID::random().toString()); + + agent::Call::KillNestedContainer* kill = + call.mutable_kill_nested_container(); + + kill->mutable_container_id()->CopyFrom(containerId); + + error = validation::agent::call::validate(call); + EXPECT_NONE(error); + + // Not expecting a `container_id.parent`. + ContainerID parentContainerId; + parentContainerId.set_value(UUID::random().toString()); + + kill->mutable_container_id()->mutable_parent()->CopyFrom(containerId); + + error = validation::agent::call::validate(call); + EXPECT_SOME(error); +} + +} // namespace tests { +} // namespace internal { +} // namespace mesos {