You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2014/04/30 05:50:38 UTC

[1/5] git commit: Updated uses of http::post.

Repository: mesos
Updated Branches:
  refs/heads/master 406ba14e1 -> 714ed3c7f


Updated uses of http::post.

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


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

Branch: refs/heads/master
Commit: 714ed3c7f98f6d3179ea3d9076cdba7e11ea3925
Parents: 4a9ea8d
Author: Benjamin Hindman <be...@gmail.com>
Authored: Fri Apr 11 22:58:28 2014 -0600
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Tue Apr 29 20:44:58 2014 -0700

----------------------------------------------------------------------
 src/tests/repair_tests.cpp | 57 +++++++++++++++++++++++++++++++----------
 1 file changed, 43 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/714ed3c7/src/tests/repair_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/repair_tests.cpp b/src/tests/repair_tests.cpp
index 0c638c7..5235058 100644
--- a/src/tests/repair_tests.cpp
+++ b/src/tests/repair_tests.cpp
@@ -110,19 +110,35 @@ TEST_F(HealthTest, ObserveEndpoint)
   VALIDATE_BAD_RESPONSE(response, "Missing value for 'monitor'.");
 
   // Malformed value causes error.
-  response = process::http::post(master.get(), "observe", "monitor=foo%");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=foo%");
   VALIDATE_BAD_RESPONSE(response, "Malformed % escape in 'foo%': '%'");
 
   // Empty value causes error.
-  response = process::http::post(master.get(), "observe", "monitor=");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=");
   VALIDATE_BAD_RESPONSE(response, "Empty string for 'monitor'.");
 
   // Missing hosts.
-  response = process::http::post(master.get(), "observe", "monitor=a");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=a");
   VALIDATE_BAD_RESPONSE(response, "Missing value for 'hosts'.");
 
   // Missing level.
-  response = process::http::post(master.get(), "observe", "monitor=a&hosts=b");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=a&hosts=b");
   VALIDATE_BAD_RESPONSE(response, "Missing value for 'level'.");
 
   // Good request is successful.
@@ -131,21 +147,33 @@ TEST_F(HealthTest, ObserveEndpoint)
   expected.hosts.push_back("b");
   expected.isHealthy = true;
 
-  response =
-    process::http::post(master.get(), "observe", "monitor=a&hosts=b&level=ok");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=a&hosts=b&level=ok");
   VALIDATE_GOOD_RESPONSE(response, stringify(expected) );
 
   // ok is case-insensitive.
-  response =
-    process::http::post(master.get(), "observe", "monitor=a&hosts=b&level=Ok");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=a&hosts=b&level=Ok");
   VALIDATE_GOOD_RESPONSE(response, stringify(expected) );
 
-  response =
-    process::http::post(master.get(), "observe", "monitor=a&hosts=b&level=oK");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=a&hosts=b&level=oK");
   VALIDATE_GOOD_RESPONSE(response, stringify(expected) );
 
-  response =
-    process::http::post(master.get(), "observe", "monitor=a&hosts=b&level=OK");
+  response = process::http::post(
+      master.get(),
+      "observe",
+      None(),
+      "monitor=a&hosts=b&level=OK");
   VALIDATE_GOOD_RESPONSE(response, stringify(expected) );
 
   // level != OK  is unhealthy.
@@ -154,15 +182,16 @@ TEST_F(HealthTest, ObserveEndpoint)
     process::http::post(
       master.get(),
       "observe",
+      None(),
       "monitor=a&hosts=b&level=true");
   VALIDATE_GOOD_RESPONSE(response, stringify(expected) );
 
   // Comma seperated hosts are parsed into an array.
   expected.hosts.push_back("e");
-  response =
-    process::http::post(
+  response = process::http::post(
       master.get(),
       "observe",
+      None(),
       "monitor=a&hosts=b,e&level=true");
   VALIDATE_GOOD_RESPONSE(response, stringify(expected) );
 


[5/5] git commit: Added 'mesos-usage' for use by external containerizers.

Posted by be...@apache.org.
Added 'mesos-usage' for use by external containerizers.

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


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

Branch: refs/heads/master
Commit: 1c0f56f6a626645115e4ff73373e9117310e4e6a
Parents: 054e194
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Apr 6 16:58:50 2014 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Tue Apr 29 20:44:58 2014 -0700

----------------------------------------------------------------------
 include/mesos/mesos.proto                   |   2 +-
 src/Makefile.am                             |   9 +-
 src/slave/containerizer/isolators/posix.hpp |  63 ++----------
 src/usage/main.cpp                          | 121 +++++++++++++++++++++++
 src/usage/usage.hpp                         |  92 +++++++++++++++++
 5 files changed, 229 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1c0f56f6/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index 52257ec..e48e50a 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -310,7 +310,7 @@ message ResourceStatistics {
   optional double cpus_system_time_secs = 3;
 
   // Number of CPUs allocated.
-  required double cpus_limit = 4;
+  optional double cpus_limit = 4;
 
   // cpu.stat on process throttling (for contention issues).
   optional uint32 cpus_nr_periods = 7;

http://git-wip-us.apache.org/repos/asf/mesos/blob/1c0f56f6/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 7f9ece1..f461a15 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -302,7 +302,9 @@ libmesos_no_3rdparty_la_SOURCES += common/attributes.hpp		\
 	tests/containerizer.hpp						\
 	tests/isolator.hpp						\
 	tests/mesos.hpp							\
-	tests/zookeeper_test_server.hpp zookeeper/authentication.hpp	\
+	tests/zookeeper_test_server.hpp					\
+	usage/usage.hpp							\
+	zookeeper/authentication.hpp					\
 	zookeeper/contender.hpp						\
 	zookeeper/detector.hpp						\
 	zookeeper/group.hpp zookeeper/watcher.hpp			\
@@ -477,6 +479,11 @@ mesos_executor_SOURCES = launcher/executor.cpp
 mesos_executor_CPPFLAGS = $(MESOS_CPPFLAGS)
 mesos_executor_LDADD = libmesos.la
 
+pkglibexec_PROGRAMS += mesos-usage
+mesos_usage_SOURCES = usage/main.cpp
+mesos_usage_CPPFLAGS = $(MESOS_CPPFLAGS)
+mesos_usage_LDADD = libmesos.la
+
 bin_PROGRAMS += mesos-log
 mesos_log_SOURCES = log/main.cpp
 mesos_log_CPPFLAGS = $(MESOS_CPPFLAGS)

http://git-wip-us.apache.org/repos/asf/mesos/blob/1c0f56f6/src/slave/containerizer/isolators/posix.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/isolators/posix.hpp b/src/slave/containerizer/isolators/posix.hpp
index 318a1bf..17bbd10 100644
--- a/src/slave/containerizer/isolators/posix.hpp
+++ b/src/slave/containerizer/isolators/posix.hpp
@@ -20,12 +20,15 @@
 #define __POSIX_ISOLATOR_HPP__
 
 #include <stout/hashmap.hpp>
+
 #include <stout/os/pstree.hpp>
 
 #include <process/future.hpp>
 
 #include "slave/containerizer/isolator.hpp"
 
+#include "usage/usage.hpp"
+
 namespace mesos {
 namespace internal {
 namespace slave {
@@ -156,36 +159,8 @@ public:
       return ResourceStatistics();
     }
 
-    Try<os::ProcessTree> tree = os::pstree(pids.get(containerId).get());
-
-    if (!tree.isSome()) {
-      return ResourceStatistics();
-    }
-
-    ResourceStatistics result;
-
-    std::deque<os::ProcessTree> trees;
-    trees.push_back(tree.get());
-
-    while (!trees.empty()) {
-      os::ProcessTree root = trees.front();
-
-      // We only show utime and stime when both are available, otherwise
-      // we're exposing a partial view of the CPU times.
-      if (root.process.utime.isSome() && root.process.stime.isSome()) {
-        result.set_cpus_user_time_secs(
-            result.cpus_user_time_secs() + root.process.utime.get().secs());
-        result.set_cpus_system_time_secs(
-            result.cpus_system_time_secs() + root.process.stime.get().secs());
-      }
-
-      trees.pop_front();
-      foreach (const os::ProcessTree& child, root.children) {
-        trees.push_back(child);
-      }
-    }
-
-    return result;
+    // Use 'mesos-usage' but only request 'cpus_' values.
+    return mesos::internal::usage(pids.get(containerId).get(), false, true);
   }
 
 private:
@@ -212,32 +187,8 @@ public:
       return ResourceStatistics();
     }
 
-    Try<os::ProcessTree> tree = os::pstree(pids.get(containerId).get());
-
-    if (!tree.isSome()) {
-      return ResourceStatistics();
-    }
-
-    ResourceStatistics result;
-
-    std::deque<os::ProcessTree> trees;
-    trees.push_back(tree.get());
-
-    while (!trees.empty()) {
-      os::ProcessTree root = trees.front();
-
-      if (root.process.rss.isSome()) {
-        result.set_mem_rss_bytes(
-            result.mem_rss_bytes() + root.process.rss.get().bytes());
-      }
-
-      trees.pop_front();
-      foreach (const os::ProcessTree& child, root.children) {
-        trees.push_back(child);
-      }
-    }
-
-    return result;
+    // Use 'mesos-usage' but only request 'mem_' values.
+    return mesos::internal::usage(pids.get(containerId).get(), true, false);
   }
 
 private:

http://git-wip-us.apache.org/repos/asf/mesos/blob/1c0f56f6/src/usage/main.cpp
----------------------------------------------------------------------
diff --git a/src/usage/main.cpp b/src/usage/main.cpp
new file mode 100644
index 0000000..97f55e9
--- /dev/null
+++ b/src/usage/main.cpp
@@ -0,0 +1,121 @@
+/**
+ * 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 <unistd.h> // For pid_t and STDOUT_FILENO.
+
+#include <iostream>
+
+#include <stout/duration.hpp>
+#include <stout/flags.hpp>
+#include <stout/json.hpp>
+#include <stout/option.hpp>
+#include <stout/protobuf.hpp>
+#include <stout/try.hpp>
+
+#include "usage/usage.hpp"
+
+using namespace mesos;
+
+using std::cerr;
+using std::cout;
+using std::endl;
+
+
+class Flags : public virtual flags::FlagsBase
+{
+public:
+  Flags()
+  {
+    add(&Flags::pid,
+        "pid",
+        "Root pid for aggregating usage/statistics");
+
+    add(&Flags::recordio,
+        "recordio",
+        "Whether or not to output ResourceStatistics protobuf\n"
+        "using the \"recordio\" format, i.e., the size as a \n"
+        "4 byte unsigned integer followed by the serialized\n"
+        "protobuf itself. By default the ResourceStatistics\n"
+        "will be output as JSON",
+        false);
+  }
+
+  Option<pid_t> pid;
+  bool recordio;
+};
+
+
+void usage(const char* argv0, const flags::FlagsBase& flags)
+{
+  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
+       << endl
+       << "Supported options:" << endl
+       << flags.usage();
+}
+
+
+int main(int argc, char** argv)
+{
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  Flags flags;
+
+  bool help;
+  flags.add(&help,
+            "help",
+            "Prints this help message",
+            false);
+
+  Try<Nothing> load = flags.load(None(), argc, argv);
+
+  if (load.isError()) {
+    cerr << load.error() << endl;
+    usage(argv[0], flags);
+    return -1;
+  }
+
+  if (help) {
+    usage(argv[0], flags);
+    return 0;
+  }
+
+  if (flags.pid.isNone()) {
+    cerr << "Missing pid" << endl;
+    usage(argv[0], flags);
+    return -1;
+  }
+
+  Try<ResourceStatistics> statistics = mesos::internal::usage(flags.pid.get());
+
+  if (statistics.isError()) {
+    cerr << "Failed to get usage: " << statistics.error() << endl;
+    return -1;
+  }
+
+  if (flags.recordio) {
+    Try<Nothing> write = protobuf::write(STDOUT_FILENO, statistics.get());
+    if (write.isError()) {
+      cerr << "Failed to write record: " << write.error() << endl;
+      return -1;
+    }
+  } else {
+    cout << stringify(JSON::Protobuf(statistics.get())) << endl;
+  }
+
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/mesos/blob/1c0f56f6/src/usage/usage.hpp
----------------------------------------------------------------------
diff --git a/src/usage/usage.hpp b/src/usage/usage.hpp
new file mode 100644
index 0000000..af04a6a
--- /dev/null
+++ b/src/usage/usage.hpp
@@ -0,0 +1,92 @@
+/**
+ * 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 __USAGE_HPP__
+#define __USAGE_HPP__
+
+#include <unistd.h> // For pid_t.
+
+#include <deque>
+
+#include <mesos/mesos.hpp>
+
+#include <process/clock.hpp>
+
+#include <stout/foreach.hpp>
+#include <stout/os.hpp>
+
+namespace mesos {
+namespace internal {
+
+// Collects resource usage of a process tree rooted at 'pid'. Only
+// collects the 'mem_*' values if 'mem' is true and the 'cpus_*'
+// values if 'cpus' is true.
+ResourceStatistics usage(pid_t pid, bool mem = true, bool cpus = true)
+{
+  Try<os::ProcessTree> pstree = os::pstree(pid);
+
+  if (pstree.isError()) {
+    return ResourceStatistics();
+  }
+
+  ResourceStatistics statistics;
+
+  // The timestamp is the only required field.
+  statistics.set_timestamp(process::Clock::now().secs());
+
+  std::deque<os::ProcessTree> trees;
+  trees.push_back(pstree.get());
+
+  while (!trees.empty()) {
+    const os::ProcessTree& tree = trees.front();
+
+    if (mem) {
+      if (tree.process.rss.isSome()) {
+        statistics.set_mem_rss_bytes(
+            statistics.mem_rss_bytes() + tree.process.rss.get().bytes());
+      }
+    }
+
+    // We only show utime and stime when both are available, otherwise
+    // we're exposing a partial view of the CPU times.
+    if (cpus) {
+      if (tree.process.utime.isSome() && tree.process.stime.isSome()) {
+        statistics.set_cpus_user_time_secs(
+            statistics.cpus_user_time_secs() +
+            tree.process.utime.get().secs());
+
+        statistics.set_cpus_system_time_secs(
+            statistics.cpus_system_time_secs() +
+            tree.process.stime.get().secs());
+      }
+    }
+
+    foreach (const os::ProcessTree& child, tree.children) {
+      trees.push_back(child);
+    }
+
+    trees.pop_front();
+  }
+
+  return statistics;
+}
+
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __USAGE_HPP__


[2/5] git commit: Added test for slave stopping before containerizer launches.

Posted by be...@apache.org.
Added test for slave stopping before containerizer launches.

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


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

Branch: refs/heads/master
Commit: 46afda855b9a1f516c0353c637d495fb3b0fcb65
Parents: 1c0f56f
Author: Benjamin Hindman <be...@gmail.com>
Authored: Wed Apr 9 14:52:45 2014 -0600
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Tue Apr 29 20:44:58 2014 -0700

----------------------------------------------------------------------
 src/tests/containerizer.cpp        | 40 ++++++++++++-----
 src/tests/containerizer.hpp        | 28 ++++++++----
 src/tests/slave_recovery_tests.cpp | 79 +++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/46afda85/src/tests/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.cpp b/src/tests/containerizer.cpp
index 50803a0..7dacab5 100644
--- a/src/tests/containerizer.cpp
+++ b/src/tests/containerizer.cpp
@@ -22,6 +22,10 @@
 using std::map;
 using std::string;
 
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+
 using namespace process;
 
 namespace mesos {
@@ -69,7 +73,7 @@ TestContainerizer::~TestContainerizer()
 }
 
 
-Future<Nothing> TestContainerizer::launch(
+Future<Nothing> TestContainerizer::_launch(
     const ContainerID& containerId,
     const ExecutorInfo& executorInfo,
     const string& directory,
@@ -161,8 +165,11 @@ Future<Nothing> TestContainerizer::launch(
 Future<containerizer::Termination> TestContainerizer::wait(
     const ContainerID& containerId)
 {
-  CHECK(promises.contains(containerId))
-    << "Container " << containerId << " not started";
+  // An unknown container is possible for tests where we "drop" the
+  // 'launch' in order to verify recovery still works correctly.
+  if (!promises.contains(containerId)) {
+    return Failure("Unknown container: " + stringify(containerId));
+  }
 
   return promises[containerId]->future();
 }
@@ -210,14 +217,25 @@ Future<hashset<ContainerID> > TestContainerizer::containers()
 
 void TestContainerizer::setup()
 {
-  EXPECT_CALL(*this, recover(testing::_))
-    .WillRepeatedly(testing::Return(Nothing()));
-
-  EXPECT_CALL(*this, usage(testing::_))
-    .WillRepeatedly(testing::Return(ResourceStatistics()));
-
-  EXPECT_CALL(*this, update(testing::_, testing::_))
-    .WillRepeatedly(testing::Return(Nothing()));
+  // NOTE: We use 'EXPECT_CALL' and 'WillRepeatedly' here instead of
+  // 'ON_CALL' and 'WillByDefault' because the latter gives the gmock
+  // warning "Uninteresting mock function call" unless each tests puts
+  // the expectations in place which would make the tests much more
+  // verbose.
+  // See groups.google.com/forum/#!topic/googlemock/EX4kLxddlko for a
+  // suggestion for how we might be able to use 'NiceMock' here
+  // instead.
+  EXPECT_CALL(*this, recover(_))
+    .WillRepeatedly(Return(Nothing()));
+
+  EXPECT_CALL(*this, usage(_))
+    .WillRepeatedly(Return(ResourceStatistics()));
+
+  EXPECT_CALL(*this, update(_, _))
+    .WillRepeatedly(Return(Nothing()));
+
+  EXPECT_CALL(*this, launch(_, _, _, _, _, _, _))
+    .WillRepeatedly(Invoke(this, &TestContainerizer::_launch));
 }
 
 } // namespace tests {

http://git-wip-us.apache.org/repos/asf/mesos/blob/46afda85/src/tests/containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.hpp b/src/tests/containerizer.hpp
index 2b7ee0d..8e21bd1 100644
--- a/src/tests/containerizer.hpp
+++ b/src/tests/containerizer.hpp
@@ -64,14 +64,16 @@ public:
 
   virtual ~TestContainerizer();
 
-  virtual process::Future<Nothing> launch(
-      const ContainerID& containerId,
-      const ExecutorInfo& executorInfo,
-      const std::string& directory,
-      const Option<std::string>& user,
-      const SlaveID& slaveId,
-      const process::PID<slave::Slave>& slavePid,
-      bool checkpoint);
+  MOCK_METHOD7(
+      launch,
+      process::Future<Nothing>(
+          const ContainerID&,
+          const ExecutorInfo&,
+          const std::string&,
+          const Option<std::string>&,
+          const SlaveID&,
+          const process::PID<slave::Slave>&,
+          bool checkpoint));
 
   virtual process::Future<Nothing> launch(
       const ContainerID& containerId,
@@ -109,6 +111,16 @@ public:
 private:
   void setup();
 
+  // Default 'launch' implementation.
+  process::Future<Nothing> _launch(
+      const ContainerID& containerId,
+      const ExecutorInfo& executorInfo,
+      const std::string& directory,
+      const Option<std::string>& user,
+      const SlaveID& slaveId,
+      const process::PID<slave::Slave>& slavePid,
+      bool checkpoint);
+
   hashmap<ExecutorID, Executor*> executors;
 
   hashmap<std::pair<FrameworkID, ExecutorID>, ContainerID> containers_;

http://git-wip-us.apache.org/repos/asf/mesos/blob/46afda85/src/tests/slave_recovery_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_recovery_tests.cpp b/src/tests/slave_recovery_tests.cpp
index cd28c8b..21b1345 100644
--- a/src/tests/slave_recovery_tests.cpp
+++ b/src/tests/slave_recovery_tests.cpp
@@ -52,6 +52,7 @@
 
 #include "messages/messages.hpp"
 
+#include "tests/containerizer.hpp"
 #include "tests/mesos.hpp"
 #include "tests/utils.hpp"
 
@@ -73,6 +74,7 @@ using std::vector;
 
 using testing::_;
 using testing::AtMost;
+using testing::DoAll;
 using testing::Eq;
 using testing::Return;
 using testing::SaveArg;
@@ -3087,3 +3089,80 @@ TYPED_TEST(SlaveRecoveryTest, ResourceStatistics)
 
   delete containerizer2.get();
 }
+
+
+// The slave is stopped after it dispatched Containerizer::launch but
+// before the containerizer has processed the launch. When the slave
+// comes back up it should send a TASK_LOST for the task.
+// NOTE: This is a 'TYPED_TEST' but we don't use 'TypeParam'.
+TYPED_TEST(SlaveRecoveryTest, RestartBeforeContainerizerLaunch)
+{
+  Try<PID<Master> > master = this->StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = this->CreateSlaveFlags();
+
+  TestContainerizer* containerizer1 = new TestContainerizer();
+
+  Try<PID<Slave> > slave = this->StartSlave(containerizer1, flags);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  // Enable checkpointing for the framework.
+  FrameworkInfo frameworkInfo;
+  frameworkInfo.CopyFrom(DEFAULT_FRAMEWORK_INFO);
+  frameworkInfo.set_checkpoint(true);
+
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(_, _, _));
+
+  Future<vector<Offer> > offers;
+  EXPECT_CALL(sched, resourceOffers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return());      // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
+  vector<TaskInfo> tasks;
+  tasks.push_back(task); // Long-running task.
+
+  // Expect the launch but don't do anything.
+  Future<Nothing> launch;
+  EXPECT_CALL(*containerizer1, launch(_, _, _, _, _, _, _))
+    .WillOnce(DoAll(FutureSatisfy(&launch),
+                    Return(Future<Nothing>())));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  // Once we get the launch restart the slave.
+  AWAIT_READY(launch);
+
+  this->Stop(slave.get());
+  delete containerizer1;
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  TestContainerizer* containerizer2 = new TestContainerizer();
+
+  slave = this->StartSlave(containerizer2, flags);
+  ASSERT_SOME(slave);
+
+  // Scheduler should receive an update for the lost task.
+  AWAIT_READY(status);
+  ASSERT_EQ(TASK_LOST, status.get().state());
+
+  driver.stop();
+  driver.join();
+
+  this->Shutdown();
+  delete containerizer2;
+}


[4/5] git commit: Allowed passing headers to http::get/post.

Posted by be...@apache.org.
Allowed passing headers to http::get/post.

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


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

Branch: refs/heads/master
Commit: 4a9ea8dce4e6345bf529a882e6449adf00ef064d
Parents: 46afda8
Author: Benjamin Hindman <be...@gmail.com>
Authored: Fri Apr 11 13:36:15 2014 -0600
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Tue Apr 29 20:44:58 2014 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/include/process/http.hpp |  4 +-
 3rdparty/libprocess/src/http.cpp             | 61 ++++++++++++++++-------
 3rdparty/libprocess/src/tests/http_tests.cpp | 17 ++++++-
 3 files changed, 61 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/4a9ea8dc/3rdparty/libprocess/include/process/http.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/http.hpp b/3rdparty/libprocess/include/process/http.hpp
index f85c065..b3b9111 100644
--- a/3rdparty/libprocess/include/process/http.hpp
+++ b/3rdparty/libprocess/include/process/http.hpp
@@ -488,7 +488,8 @@ inline Try<std::string> decode(const std::string& s)
 Future<Response> get(
     const UPID& upid,
     const Option<std::string>& path = None(),
-    const Option<std::string>& query = None());
+    const Option<std::string>& query = None(),
+    const Option<hashmap<std::string, std::string> >& headers = None());
 
 
 // Sends a blocking HTTP POST request to the process with the given upid.
@@ -496,6 +497,7 @@ Future<Response> get(
 Future<Response> post(
     const UPID& upid,
     const Option<std::string>& path = None(),
+    const Option<hashmap<std::string, std::string> >& headers = None(),
     const Option<std::string>& body = None(),
     const Option<std::string>& contentType = None());
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/4a9ea8dc/3rdparty/libprocess/src/http.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/http.cpp b/3rdparty/libprocess/src/http.cpp
index f8b93dc..eb20380 100644
--- a/3rdparty/libprocess/src/http.cpp
+++ b/3rdparty/libprocess/src/http.cpp
@@ -61,6 +61,7 @@ Future<Response> request(
     const string& method,
     const Option<string>& path,
     const Option<string>& query,
+    const Option<hashmap<string, string> >& _headers,
     const Option<string>& body,
     const Option<string>& contentType)
 {
@@ -103,28 +104,44 @@ Future<Response> request(
 
   out << " HTTP/1.1\r\n";
 
-  // Call inet_ntop since inet_ntoa is not thread-safe!
-  char ip[INET_ADDRSTRLEN];
-  PCHECK(inet_ntop(AF_INET, (in_addr *) &upid.ip, ip, INET_ADDRSTRLEN) != NULL);
+  // Set up the headers as necessary.
+  hashmap<string, string> headers;
 
-  out << "Host: " << ip << ":" << upid.port << "\r\n"
-      << "Connection: close\r\n";
+  if (_headers.isSome()) {
+    headers = _headers.get();
+  }
 
-  if (body.isNone() && contentType.isSome()) {
-    os::close(s);
-    return Failure("Attempted to do a POST with a Content-Type but no body");
+  // Need to specify the 'Host' header. We use inet_ntop since
+  // inet_ntoa is not thread-safe!
+  char ip[INET_ADDRSTRLEN];
+  if (inet_ntop(AF_INET, (in_addr*) &upid.ip, ip, INET_ADDRSTRLEN) == NULL) {
+    return Failure(ErrnoError("Failed to create 'Host' header"));
   }
 
+  headers["Host"] = string(ip) + ":" + stringify(upid.port);
+
+  // Tell the server to close the connection when it's done.
+  headers["Connection"] = "close";
+
+  // Overwrite Content-Type if necessary.
   if (contentType.isSome()) {
-    out << "Content-Type: " << contentType.get() << "\r\n";
+    headers["Content-Type"] = contentType.get();
+  }
+
+  // Make sure the Content-Length is set correctly if necessary.
+  if (body.isSome()) {
+    headers["Content-Length"] = stringify(body.get().length());
   }
 
-  if (body.isNone()) {
-    out << "\r\n";
-  } else {
-    out << "Content-Length: " << body.get().length() << "\r\n"
-        << "\r\n"
-        << body.get();
+  // Emit the headers.
+  foreachpair (const string& key, const string& value, headers) {
+    out << key << ": " << value << "\r\n";
+  }
+
+  out << "\r\n";
+
+  if (body.isSome()) {
+    out << body.get();
   }
 
   Try<Nothing> nonblock = os::nonblock(s);
@@ -149,19 +166,27 @@ Future<Response> request(
 Future<Response> get(
     const UPID& upid,
     const Option<string>& path,
-    const Option<string>& query)
+    const Option<string>& query,
+    const Option<hashmap<string, string> >& headers)
 {
-  return internal::request(upid, "GET", path, query, None(), None());
+  return internal::request(
+      upid, "GET", path, query, headers, None(), None());
 }
 
 
 Future<Response> post(
     const UPID& upid,
     const Option<string>& path,
+    const Option<hashmap<string, string> >& headers,
     const Option<string>& body,
     const Option<string>& contentType)
 {
-  return internal::request(upid, "POST", path, None(), body, contentType);
+  if (body.isNone() && contentType.isSome()) {
+    return Failure("Attempted to do a POST with a Content-Type but no body");
+  }
+
+  return internal::request(
+      upid, "POST", path, None(), headers, body, contentType);
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/4a9ea8dc/3rdparty/libprocess/src/tests/http_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/http_tests.cpp b/3rdparty/libprocess/src/tests/http_tests.cpp
index 983e2a0..fd7c252 100644
--- a/3rdparty/libprocess/src/tests/http_tests.cpp
+++ b/3rdparty/libprocess/src/tests/http_tests.cpp
@@ -265,7 +265,7 @@ TEST(HTTP, Post)
 
   // Test the case where there is a content type but no body.
   Future<http::Response> future =
-    http::post(process.self(), "post", None(), "text/plain");
+    http::post(process.self(), "post", None(), None(), "text/plain");
 
   AWAIT_EXPECT_FAILED(future);
 
@@ -273,7 +273,20 @@ TEST(HTTP, Post)
     .WillOnce(Invoke(validatePost));
 
   future =
-    http::post(process.self(), "post", "This is the payload.", "text/plain");
+    http::post(process.self(), "post", None(), "This is the payload.", "text/plain");
+
+  AWAIT_READY(future);
+  ASSERT_EQ(http::statuses[200], future.get().status);
+
+  // Now test passing headers instead.
+  hashmap<string, string> headers;
+  headers["Content-Type"] = "text/plain";
+
+  EXPECT_CALL(process, post(_))
+    .WillOnce(Invoke(validatePost));
+
+  future =
+    http::post(process.self(), "post", headers, "This is the payload.");
 
   AWAIT_READY(future);
   ASSERT_EQ(http::statuses[200], future.get().status);


[3/5] git commit: Better error message for protobuf::write.

Posted by be...@apache.org.
Better error message for protobuf::write.

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


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

Branch: refs/heads/master
Commit: 054e1944e7f6f244efb4ecbf568e448059080c09
Parents: 406ba14
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Apr 6 18:56:08 2014 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Tue Apr 29 20:44:58 2014 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/3rdparty/stout/include/stout/protobuf.hpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/054e1944/3rdparty/libprocess/3rdparty/stout/include/stout/protobuf.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/protobuf.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/protobuf.hpp
index ea5665a..ddc13e9 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/protobuf.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/protobuf.hpp
@@ -47,7 +47,8 @@ namespace protobuf {
 inline Try<Nothing> write(int fd, const google::protobuf::Message& message)
 {
   if (!message.IsInitialized()) {
-    return Error("Uninitialized protocol buffer");
+    return Error(message.InitializationErrorString() +
+                 " is required but not initialized");
   }
 
   // First write the size of the protobuf.