This is an automated email from the ASF dual-hosted git repository. abudnik pushed a commit to branch 1.7.x in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 0567b31212105821d0b37ad049228dab6e98ed63 Author: Greg Mann <g...@mesosphere.io> AuthorDate: Thu Jul 25 12:17:41 2019 -0700 Moved the Docker executor declaration into a header. This moves the declaration of the Docker executor into the Docker executor header file and moves the code for the Docker executor binary into a new launcher implementation file. This change will enable the Mesos executor driver implementation to make use of the `DockerExecutor` symbol. Review: https://reviews.apache.org/r/71033/ --- src/CMakeLists.txt | 2 +- src/Makefile.am | 3 +- src/docker/CMakeLists.txt | 20 --- src/docker/executor.cpp | 348 +++++++++------------------------------ src/docker/executor.hpp | 53 ++++++ src/launcher/CMakeLists.txt | 5 + src/launcher/docker_executor.cpp | 266 ++++++++++++++++++++++++++++++ 7 files changed, 408 insertions(+), 289 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5bfc8db..8b3e84a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -242,6 +242,7 @@ set(CSI_SRC set(DOCKER_SRC docker/docker.cpp + docker/executor.cpp docker/spec.cpp) set(EXECUTOR_SRC @@ -599,7 +600,6 @@ endif () ############################## add_subdirectory(checks) add_subdirectory(cli) -add_subdirectory(docker) add_subdirectory(examples) add_subdirectory(launcher) add_subdirectory(local) diff --git a/src/Makefile.am b/src/Makefile.am index fb2a27e..4e99723 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1006,6 +1006,7 @@ libmesos_no_3rdparty_la_SOURCES += \ common/validation.cpp \ common/values.cpp \ docker/docker.cpp \ + docker/executor.cpp \ docker/spec.cpp \ exec/exec.cpp \ executor/executor.cpp \ @@ -1743,7 +1744,7 @@ mesos_usage_CPPFLAGS = $(MESOS_CPPFLAGS) mesos_usage_LDADD = libmesos.la $(LDADD) pkglibexec_PROGRAMS += mesos-docker-executor -mesos_docker_executor_SOURCES = docker/executor.cpp +mesos_docker_executor_SOURCES = launcher/docker_executor.cpp mesos_docker_executor_CPPFLAGS = $(MESOS_CPPFLAGS) mesos_docker_executor_LDADD = libmesos.la $(LDADD) diff --git a/src/docker/CMakeLists.txt b/src/docker/CMakeLists.txt deleted file mode 100644 index 1196664..0000000 --- a/src/docker/CMakeLists.txt +++ /dev/null @@ -1,20 +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. - -# THE DOCKER EXECUTOR EXECUTABLE. -################################# -add_executable(mesos-docker-executor executor.cpp) -target_link_libraries(mesos-docker-executor PRIVATE mesos) diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp index ed1b718..642ed65 100644 --- a/src/docker/executor.cpp +++ b/src/docker/executor.cpp @@ -854,291 +854,105 @@ private: }; -class DockerExecutor : public Executor +DockerExecutor::DockerExecutor( + const Owned<Docker>& docker, + const string& container, + const string& sandboxDirectory, + const string& mappedDirectory, + const Duration& shutdownGracePeriod, + const string& launcherDir, + const map<string, string>& taskEnvironment, + const Option<ContainerDNSInfo>& defaultContainerDNS, + bool cgroupsEnableCfs) { -public: - DockerExecutor( - const Owned<Docker>& docker, - const string& container, - const string& sandboxDirectory, - const string& mappedDirectory, - const Duration& shutdownGracePeriod, - const string& launcherDir, - const map<string, string>& taskEnvironment, - const Option<ContainerDNSInfo>& defaultContainerDNS, - bool cgroupsEnableCfs) - { - process = Owned<DockerExecutorProcess>(new DockerExecutorProcess( - docker, - container, - sandboxDirectory, - mappedDirectory, - shutdownGracePeriod, - launcherDir, - taskEnvironment, - defaultContainerDNS, - cgroupsEnableCfs)); - - spawn(process.get()); - } - - ~DockerExecutor() override - { - terminate(process.get()); - wait(process.get()); - } - - void registered( - ExecutorDriver* driver, - const ExecutorInfo& executorInfo, - const FrameworkInfo& frameworkInfo, - const SlaveInfo& slaveInfo) override - { - dispatch(process.get(), - &DockerExecutorProcess::registered, - driver, - executorInfo, - frameworkInfo, - slaveInfo); - } - - void reregistered( - ExecutorDriver* driver, - const SlaveInfo& slaveInfo) override - { - dispatch(process.get(), - &DockerExecutorProcess::reregistered, - driver, - slaveInfo); - } - - void disconnected(ExecutorDriver* driver) override - { - dispatch(process.get(), &DockerExecutorProcess::disconnected, driver); - } - - void launchTask(ExecutorDriver* driver, const TaskInfo& task) override - { - dispatch(process.get(), &DockerExecutorProcess::launchTask, driver, task); - } - - void killTask(ExecutorDriver* driver, const TaskID& taskId) override - { - dispatch(process.get(), &DockerExecutorProcess::killTask, driver, taskId); - } - - void frameworkMessage(ExecutorDriver* driver, const string& data) override - { - dispatch(process.get(), - &DockerExecutorProcess::frameworkMessage, - driver, - data); - } - - void shutdown(ExecutorDriver* driver) override - { - dispatch(process.get(), &DockerExecutorProcess::shutdown, driver); - } - - void error(ExecutorDriver* driver, const string& data) override - { - dispatch(process.get(), &DockerExecutorProcess::error, driver, data); - } - -private: - Owned<DockerExecutorProcess> process; -}; - - -} // namespace docker { -} // namespace internal { -} // namespace mesos { + process = Owned<DockerExecutorProcess>(new DockerExecutorProcess( + docker, + container, + sandboxDirectory, + mappedDirectory, + shutdownGracePeriod, + launcherDir, + taskEnvironment, + defaultContainerDNS, + cgroupsEnableCfs)); + + spawn(process.get()); +} -int main(int argc, char** argv) +DockerExecutor::~DockerExecutor() { - GOOGLE_PROTOBUF_VERIFY_VERSION; - -#ifdef __WINDOWS__ - // We need a handle to the job object which this container is associated with. - // Without this handle, the job object would be destroyed by the OS when the - // agent exits (or crashes), making recovery impossible. By holding a handle, - // we tie the lifetime of the job object to the container itself. In this way, - // a recovering agent can reattach to the container by opening a new handle to - // the job object. - const pid_t pid = ::GetCurrentProcessId(); - const Try<std::wstring> name = os::name_job(pid); - if (name.isError()) { - cerr << "Failed to create job object name from pid: " << name.error() - << endl; - return EXIT_FAILURE; - } - - // NOTE: This handle will not be destructed, even though it is a - // `SharedHandle`, because it will (purposefully) never go out of scope. - Try<SharedHandle> handle = os::open_job(JOB_OBJECT_QUERY, false, name.get()); - if (handle.isError()) { - cerr << "Failed to open job object '" << stringify(name.get()) - << "' for the current container: " << handle.error() << endl; - return EXIT_FAILURE; - } -#endif // __WINDOWS__ - - mesos::internal::docker::Flags flags; - - // Load flags from environment and command line. - Try<flags::Warnings> load = flags.load(None(), &argc, &argv); - - if (flags.help) { - cout << flags.usage() << endl; - return EXIT_SUCCESS; - } - - if (load.isError()) { - cerr << flags.usage(load.error()) << endl; - return EXIT_FAILURE; - } - - mesos::internal::logging::initialize(argv[0], true, flags); // Catch signals. - - // Log any flag warnings (after logging is initialized). - foreach (const flags::Warning& warning, load->warnings) { - LOG(WARNING) << warning.message; - } - - VLOG(1) << stringify(flags); - - if (flags.docker.isNone()) { - EXIT(EXIT_FAILURE) << flags.usage("Missing required option --docker"); - } - - if (flags.container.isNone()) { - EXIT(EXIT_FAILURE) << flags.usage("Missing required option --container"); - } + terminate(process.get()); + wait(process.get()); +} - if (flags.sandbox_directory.isNone()) { - EXIT(EXIT_FAILURE) - << flags.usage("Missing required option --sandbox_directory"); - } - if (flags.mapped_directory.isNone()) { - EXIT(EXIT_FAILURE) - << flags.usage("Missing required option --mapped_directory"); - } +void DockerExecutor::registered( + ExecutorDriver* driver, + const ExecutorInfo& executorInfo, + const FrameworkInfo& frameworkInfo, + const SlaveInfo& slaveInfo) +{ + dispatch(process.get(), + &DockerExecutorProcess::registered, + driver, + executorInfo, + frameworkInfo, + slaveInfo); +} - map<string, string> taskEnvironment; - if (flags.task_environment.isSome()) { - // Parse the string as JSON. - Try<JSON::Object> json = - JSON::parse<JSON::Object>(flags.task_environment.get()); - - if (json.isError()) { - EXIT(EXIT_FAILURE) - << flags.usage("Failed to parse --task_environment: " + json.error()); - } - // Convert from JSON to map. - foreachpair ( - const string& key, - const JSON::Value& value, - json->values) { - if (!value.is<JSON::String>()) { - EXIT(EXIT_FAILURE) << flags.usage( - "Value of key '" + key + "' in --task_environment is not a string"); - } +void DockerExecutor::reregistered( + ExecutorDriver* driver, + const SlaveInfo& slaveInfo) +{ + dispatch(process.get(), + &DockerExecutorProcess::reregistered, + driver, + slaveInfo); +} - // Save the parsed and validated key/value. - taskEnvironment[key] = value.as<JSON::String>().value; - } - } - Option<mesos::internal::ContainerDNSInfo> defaultContainerDNS; - if (flags.default_container_dns.isSome()) { - Try<mesos::internal::ContainerDNSInfo> parse = - flags::parse<mesos::internal::ContainerDNSInfo>( - flags.default_container_dns.get()); +void DockerExecutor::disconnected(ExecutorDriver* driver) +{ + dispatch(process.get(), &DockerExecutorProcess::disconnected, driver); +} - if (parse.isError()) { - EXIT(EXIT_FAILURE) << flags.usage( - "Failed to parse --default_container_dns: " + parse.error()); - } - defaultContainerDNS = parse.get(); - } +void DockerExecutor::launchTask(ExecutorDriver* driver, const TaskInfo& task) +{ + dispatch(process.get(), &DockerExecutorProcess::launchTask, driver, task); +} - // Get executor shutdown grace period from the environment. - // - // NOTE: We avoided introducing a docker executor flag for this - // because the docker executor exits if it sees an unknown flag. - // This makes it difficult to add or remove docker executor flags - // that are unconditionally set by the agent. - Duration shutdownGracePeriod = - mesos::internal::slave::DEFAULT_EXECUTOR_SHUTDOWN_GRACE_PERIOD; - Option<string> value = os::getenv("MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD"); - if (value.isSome()) { - Try<Duration> parse = Duration::parse(value.get()); - if (parse.isError()) { - EXIT(EXIT_FAILURE) - << "Failed to parse value '" << value.get() << "'" - << " of 'MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD': " << parse.error(); - } - shutdownGracePeriod = parse.get(); - } +void DockerExecutor::killTask(ExecutorDriver* driver, const TaskID& taskId) +{ + dispatch(process.get(), &DockerExecutorProcess::killTask, driver, taskId); +} - // If the deprecated flag is set, respect it and choose the bigger value. - // - // TODO(alexr): Remove this after the deprecation cycle (started in 1.0). - if (flags.stop_timeout.isSome() && - flags.stop_timeout.get() > shutdownGracePeriod) { - shutdownGracePeriod = flags.stop_timeout.get(); - } - if (flags.launcher_dir.isNone()) { - EXIT(EXIT_FAILURE) << flags.usage("Missing required option --launcher_dir"); - } +void DockerExecutor::frameworkMessage( + ExecutorDriver* driver, + const string& data) +{ + dispatch(process.get(), + &DockerExecutorProcess::frameworkMessage, + driver, + data); +} - process::initialize(); - // The 2nd argument for docker create is set to false so we skip - // validation when creating a docker abstraction, as the slave - // should have already validated docker. - Try<Owned<Docker>> docker = Docker::create( - flags.docker.get(), - flags.docker_socket.get(), - false); +void DockerExecutor::shutdown(ExecutorDriver* driver) +{ + dispatch(process.get(), &DockerExecutorProcess::shutdown, driver); +} - if (docker.isError()) { - EXIT(EXIT_FAILURE) - << "Unable to create docker abstraction: " << docker.error(); - } - Owned<mesos::internal::docker::DockerExecutor> executor( - new mesos::internal::docker::DockerExecutor( - docker.get(), - flags.container.get(), - flags.sandbox_directory.get(), - flags.mapped_directory.get(), - shutdownGracePeriod, - flags.launcher_dir.get(), - taskEnvironment, - defaultContainerDNS, - flags.cgroups_enable_cfs)); - - Owned<mesos::MesosExecutorDriver> driver( - new mesos::MesosExecutorDriver(executor.get())); - - bool success = driver->run() == mesos::DRIVER_STOPPED; - - // NOTE: We need to delete the executor and driver before we call - // `process::finalize` because the executor/driver will try to terminate - // and wait on a libprocess actor in their destructor. - driver.reset(); - executor.reset(); - - // NOTE: We need to finalize libprocess, on Windows especially, - // as any binary that uses the networking stack on Windows must - // also clean up the networking stack before exiting. - process::finalize(true); - return success ? EXIT_SUCCESS : EXIT_FAILURE; +void DockerExecutor::error(ExecutorDriver* driver, const string& data) +{ + dispatch(process.get(), &DockerExecutorProcess::error, driver, data); } + +} // namespace docker { +} // namespace internal { +} // namespace mesos { diff --git a/src/docker/executor.hpp b/src/docker/executor.hpp index f21e84c..dfb8ad0 100644 --- a/src/docker/executor.hpp +++ b/src/docker/executor.hpp @@ -22,10 +22,15 @@ #include <map> #include <string> +#include <mesos/executor.hpp> + +#include <process/owned.hpp> #include <process/process.hpp> #include <stout/option.hpp> +#include "docker/docker.hpp" + #include "logging/flags.hpp" namespace mesos { @@ -102,6 +107,54 @@ struct Flags : public virtual mesos::internal::logging::Flags Option<Duration> stop_timeout; }; + +class DockerExecutorProcess; + + +class DockerExecutor : public Executor +{ +public: + DockerExecutor( + const process::Owned<Docker>& docker, + const std::string& container, + const std::string& sandboxDirectory, + const std::string& mappedDirectory, + const Duration& shutdownGracePeriod, + const std::string& launcherDir, + const std::map<std::string, std::string>& taskEnvironment, + const Option<ContainerDNSInfo>& defaultContainerDNS, + bool cgroupsEnableCfs); + + ~DockerExecutor() override; + + void registered( + ExecutorDriver* driver, + const ExecutorInfo& executorInfo, + const FrameworkInfo& frameworkInfo, + const SlaveInfo& slaveInfo) override; + + void reregistered( + ExecutorDriver* driver, + const SlaveInfo& slaveInfo) override; + + void disconnected(ExecutorDriver* driver) override; + + void launchTask(ExecutorDriver* driver, const TaskInfo& task) override; + + void killTask(ExecutorDriver* driver, const TaskID& taskId) override; + + void frameworkMessage( + ExecutorDriver* driver, + const std::string& data) override; + + void shutdown(ExecutorDriver* driver) override; + + void error(ExecutorDriver* driver, const std::string& data) override; + +private: + process::Owned<DockerExecutorProcess> process; +}; + } // namespace docker { } // namespace internal { } // namespace mesos { diff --git a/src/launcher/CMakeLists.txt b/src/launcher/CMakeLists.txt index 2ffa946..73587f4 100644 --- a/src/launcher/CMakeLists.txt +++ b/src/launcher/CMakeLists.txt @@ -24,3 +24,8 @@ target_link_libraries(mesos-executor PRIVATE mesos) add_executable(mesos-fetcher fetcher.cpp) target_link_libraries(mesos-fetcher PRIVATE mesos) + +# THE DOCKER EXECUTOR EXECUTABLE. +################################# +add_executable(mesos-docker-executor docker_executor.cpp) +target_link_libraries(mesos-docker-executor PRIVATE mesos) diff --git a/src/launcher/docker_executor.cpp b/src/launcher/docker_executor.cpp new file mode 100644 index 0000000..3f12c78 --- /dev/null +++ b/src/launcher/docker_executor.cpp @@ -0,0 +1,266 @@ +// 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 <stdio.h> + +#include <map> +#include <string> + +#include <mesos/executor.hpp> +#include <mesos/mesos.hpp> + +#include <process/collect.hpp> +#include <process/delay.hpp> +#include <process/id.hpp> +#include <process/loop.hpp> +#include <process/owned.hpp> +#include <process/process.hpp> +#include <process/protobuf.hpp> +#include <process/reap.hpp> +#include <process/subprocess.hpp> + +#include <stout/error.hpp> +#include <stout/flags.hpp> +#include <stout/json.hpp> +#include <stout/lambda.hpp> +#include <stout/os.hpp> +#include <stout/protobuf.hpp> +#include <stout/try.hpp> +#ifdef __WINDOWS__ +#include <stout/windows.hpp> +#endif // __WINDOWS__ + +#include <stout/os/killtree.hpp> + +#ifdef __WINDOWS__ +#include <stout/os/windows/jobobject.hpp> +#endif // __WINDOWS__ + +#include "checks/checks_runtime.hpp" +#include "checks/health_checker.hpp" + +#include "common/protobuf_utils.hpp" +#include "common/status_utils.hpp" + +#include "docker/docker.hpp" +#include "docker/executor.hpp" + +#include "logging/flags.hpp" +#include "logging/logging.hpp" + +#include "messages/flags.hpp" +#include "messages/messages.hpp" + +#include "slave/constants.hpp" + +using namespace mesos; +using namespace process; + +using std::cerr; +using std::cout; +using std::endl; +using std::map; +using std::string; +using std::vector; + + +int main(int argc, char** argv) +{ + GOOGLE_PROTOBUF_VERIFY_VERSION; + +#ifdef __WINDOWS__ + // We need a handle to the job object which this container is associated with. + // Without this handle, the job object would be destroyed by the OS when the + // agent exits (or crashes), making recovery impossible. By holding a handle, + // we tie the lifetime of the job object to the container itself. In this way, + // a recovering agent can reattach to the container by opening a new handle to + // the job object. + const pid_t pid = ::GetCurrentProcessId(); + const Try<std::wstring> name = os::name_job(pid); + if (name.isError()) { + cerr << "Failed to create job object name from pid: " << name.error() + << endl; + return EXIT_FAILURE; + } + + // NOTE: This handle will not be destructed, even though it is a + // `SharedHandle`, because it will (purposefully) never go out of scope. + Try<SharedHandle> handle = os::open_job(JOB_OBJECT_QUERY, false, name.get()); + if (handle.isError()) { + cerr << "Failed to open job object '" << stringify(name.get()) + << "' for the current container: " << handle.error() << endl; + return EXIT_FAILURE; + } +#endif // __WINDOWS__ + + mesos::internal::docker::Flags flags; + + // Load flags from environment and command line. + Try<flags::Warnings> load = flags.load(None(), &argc, &argv); + + if (flags.help) { + cout << flags.usage() << endl; + return EXIT_SUCCESS; + } + + if (load.isError()) { + cerr << flags.usage(load.error()) << endl; + return EXIT_FAILURE; + } + + mesos::internal::logging::initialize(argv[0], true, flags); // Catch signals. + + // Log any flag warnings (after logging is initialized). + foreach (const flags::Warning& warning, load->warnings) { + LOG(WARNING) << warning.message; + } + + VLOG(1) << stringify(flags); + + if (flags.docker.isNone()) { + EXIT(EXIT_FAILURE) << flags.usage("Missing required option --docker"); + } + + if (flags.container.isNone()) { + EXIT(EXIT_FAILURE) << flags.usage("Missing required option --container"); + } + + if (flags.sandbox_directory.isNone()) { + EXIT(EXIT_FAILURE) + << flags.usage("Missing required option --sandbox_directory"); + } + + if (flags.mapped_directory.isNone()) { + EXIT(EXIT_FAILURE) + << flags.usage("Missing required option --mapped_directory"); + } + + map<string, string> taskEnvironment; + if (flags.task_environment.isSome()) { + // Parse the string as JSON. + Try<JSON::Object> json = + JSON::parse<JSON::Object>(flags.task_environment.get()); + + if (json.isError()) { + EXIT(EXIT_FAILURE) + << flags.usage("Failed to parse --task_environment: " + json.error()); + } + + // Convert from JSON to map. + foreachpair ( + const string& key, + const JSON::Value& value, + json->values) { + if (!value.is<JSON::String>()) { + EXIT(EXIT_FAILURE) << flags.usage( + "Value of key '" + key + "' in --task_environment is not a string"); + } + + // Save the parsed and validated key/value. + taskEnvironment[key] = value.as<JSON::String>().value; + } + } + + Option<mesos::internal::ContainerDNSInfo> defaultContainerDNS; + if (flags.default_container_dns.isSome()) { + Try<mesos::internal::ContainerDNSInfo> parse = + flags::parse<mesos::internal::ContainerDNSInfo>( + flags.default_container_dns.get()); + + if (parse.isError()) { + EXIT(EXIT_FAILURE) << flags.usage( + "Failed to parse --default_container_dns: " + parse.error()); + } + + defaultContainerDNS = parse.get(); + } + + // Get executor shutdown grace period from the environment. + // + // NOTE: We avoided introducing a docker executor flag for this + // because the docker executor exits if it sees an unknown flag. + // This makes it difficult to add or remove docker executor flags + // that are unconditionally set by the agent. + Duration shutdownGracePeriod = + mesos::internal::slave::DEFAULT_EXECUTOR_SHUTDOWN_GRACE_PERIOD; + Option<string> value = os::getenv("MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD"); + if (value.isSome()) { + Try<Duration> parse = Duration::parse(value.get()); + if (parse.isError()) { + EXIT(EXIT_FAILURE) + << "Failed to parse value '" << value.get() << "'" + << " of 'MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD': " << parse.error(); + } + + shutdownGracePeriod = parse.get(); + } + + // If the deprecated flag is set, respect it and choose the bigger value. + // + // TODO(alexr): Remove this after the deprecation cycle (started in 1.0). + if (flags.stop_timeout.isSome() && + flags.stop_timeout.get() > shutdownGracePeriod) { + shutdownGracePeriod = flags.stop_timeout.get(); + } + + if (flags.launcher_dir.isNone()) { + EXIT(EXIT_FAILURE) << flags.usage("Missing required option --launcher_dir"); + } + + process::initialize(); + + // The 2nd argument for docker create is set to false so we skip + // validation when creating a docker abstraction, as the slave + // should have already validated docker. + Try<Owned<Docker>> docker = Docker::create( + flags.docker.get(), + flags.docker_socket.get(), + false); + + if (docker.isError()) { + EXIT(EXIT_FAILURE) + << "Unable to create docker abstraction: " << docker.error(); + } + + Owned<mesos::internal::docker::DockerExecutor> executor( + new mesos::internal::docker::DockerExecutor( + docker.get(), + flags.container.get(), + flags.sandbox_directory.get(), + flags.mapped_directory.get(), + shutdownGracePeriod, + flags.launcher_dir.get(), + taskEnvironment, + defaultContainerDNS, + flags.cgroups_enable_cfs)); + + Owned<mesos::MesosExecutorDriver> driver( + new mesos::MesosExecutorDriver(executor.get())); + + bool success = driver->run() == mesos::DRIVER_STOPPED; + + // NOTE: We need to delete the executor and driver before we call + // `process::finalize` because the executor/driver will try to terminate + // and wait on a libprocess actor in their destructor. + driver.reset(); + executor.reset(); + + // NOTE: We need to finalize libprocess, on Windows especially, + // as any binary that uses the networking stack on Windows must + // also clean up the networking stack before exiting. + process::finalize(true); + return success ? EXIT_SUCCESS : EXIT_FAILURE; +}