Renamed appc.{hpp|cpp} to
slave/containerizer/provisioners/appc/provisioner.{hpp|cpp}.
Review: https://reviews.apache.org/r/38239
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0636f2b3
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0636f2b3
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0636f2b3
Branch: refs/heads/master
Commit: 0636f2b3ba97af9a088fd6aa347be4d486d49fdd
Parents: 8949b1a
Author: Jiang Yan Xu <[email protected]>
Authored: Wed Sep 9 16:18:53 2015 -0700
Committer: Jiang Yan Xu <[email protected]>
Committed: Thu Sep 10 10:42:06 2015 -0700
----------------------------------------------------------------------
src/Makefile.am | 8 +-
src/slave/containerizer/provisioner.cpp | 2 +-
src/slave/containerizer/provisioners/appc.cpp | 380 -------------------
src/slave/containerizer/provisioners/appc.hpp | 78 ----
.../provisioners/appc/provisioner.cpp | 379 ++++++++++++++++++
.../provisioners/appc/provisioner.hpp | 78 ++++
6 files changed, 462 insertions(+), 463 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/0636f2b3/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index cea470e..8963cea 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -482,9 +482,9 @@ libmesos_no_3rdparty_la_SOURCES =
\
slave/containerizer/mesos/containerizer.cpp \
slave/containerizer/mesos/launch.cpp \
slave/containerizer/provisioner.cpp \
- slave/containerizer/provisioners/appc.cpp \
- slave/containerizer/provisioners/paths.cpp \
+ slave/containerizer/provisioners/paths.cpp \
slave/containerizer/provisioners/appc/paths.cpp \
+ slave/containerizer/provisioners/appc/provisioner.cpp \
slave/containerizer/provisioners/appc/spec.cpp \
slave/containerizer/provisioners/appc/store.cpp \
slave/containerizer/provisioners/backend.cpp \
@@ -763,9 +763,9 @@ libmesos_no_3rdparty_la_SOURCES +=
\
slave/containerizer/launcher.hpp \
slave/containerizer/linux_launcher.hpp \
slave/containerizer/provisioner.hpp \
- slave/containerizer/provisioners/appc.hpp \
- slave/containerizer/provisioners/paths.hpp \
+ slave/containerizer/provisioners/paths.hpp \
slave/containerizer/provisioners/appc/paths.hpp \
+ slave/containerizer/provisioners/appc/provisioner.hpp \
slave/containerizer/provisioners/appc/spec.hpp \
slave/containerizer/provisioners/appc/store.hpp \
slave/containerizer/provisioners/backend.hpp \
http://git-wip-us.apache.org/repos/asf/mesos/blob/0636f2b3/src/slave/containerizer/provisioner.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioner.cpp
b/src/slave/containerizer/provisioner.cpp
index 95894c0..2ac9008 100644
--- a/src/slave/containerizer/provisioner.cpp
+++ b/src/slave/containerizer/provisioner.cpp
@@ -22,7 +22,7 @@
#include "slave/containerizer/provisioner.hpp"
-#include "slave/containerizer/provisioners/appc.hpp"
+#include "slave/containerizer/provisioners/appc/provisioner.hpp"
using namespace process;
http://git-wip-us.apache.org/repos/asf/mesos/blob/0636f2b3/src/slave/containerizer/provisioners/appc.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/appc.cpp
b/src/slave/containerizer/provisioners/appc.cpp
deleted file mode 100644
index d54b688..0000000
--- a/src/slave/containerizer/provisioners/appc.cpp
+++ /dev/null
@@ -1,380 +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 <mesos/type_utils.hpp>
-
-#include <process/collect.hpp>
-#include <process/defer.hpp>
-#include <process/dispatch.hpp>
-#include <process/process.hpp>
-
-#include <stout/foreach.hpp>
-#include <stout/hashset.hpp>
-#include <stout/os.hpp>
-#include <stout/stringify.hpp>
-#include <stout/strings.hpp>
-#include <stout/uuid.hpp>
-
-#include "slave/containerizer/provisioners/appc.hpp"
-
-#include "slave/containerizer/provisioners/backend.hpp"
-#include "slave/containerizer/provisioners/paths.hpp"
-
-#include "slave/containerizer/provisioners/appc/paths.hpp"
-#include "slave/containerizer/provisioners/appc/spec.hpp"
-#include "slave/containerizer/provisioners/appc/store.hpp"
-
-#include "slave/paths.hpp"
-
-using namespace process;
-using namespace mesos::internal::slave;
-
-using std::list;
-using std::string;
-using std::vector;
-
-using mesos::slave::ContainerState;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace appc {
-
-class AppcProvisionerProcess : public Process<AppcProvisionerProcess>
-{
-public:
- AppcProvisionerProcess(
- const Flags& flags,
- const string& root,
- const Owned<Store>& store,
- const hashmap<string, Owned<Backend>>& backends);
-
- Future<Nothing> recover(
- const list<ContainerState>& states,
- const hashset<ContainerID>& orphans);
-
- Future<string> provision(const ContainerID& containerId, const Image& image);
-
- Future<bool> destroy(const ContainerID& containerId);
-
-private:
- Future<string> _provision(const vector<string>& layers, const string&
rootfs);
-
- const Flags flags;
-
- // Absolute path to the Appc provisioner root directory. It can be derived
- // from '--work_dir' but we keep a separate copy here because we converted
- // it into an absolute path so managed rootfs paths match the ones in
- // 'mountinfo' (important if mount-based backends are used).
- const string root;
-
- const Owned<Store> store;
- const hashmap<string, Owned<Backend>> backends;
-
- struct Info
- {
- // Mappings: backend -> rootfsId -> rootfsPath.
- hashmap<string, hashmap<string, string>> rootfses;
- };
-
- hashmap<ContainerID, Owned<Info>> infos;
-};
-
-
-// NOTE: Successful creation of the provisioner means its managed
-// directory under --work_dir is also created.
-Try<Owned<Provisioner>> AppcProvisioner::create(
- const Flags& flags,
- Fetcher* fetcher)
-{
- string _root =
- slave::paths::getProvisionerDir(flags.work_dir, Image::APPC);
-
- Try<Nothing> mkdir = os::mkdir(_root);
- if (mkdir.isError()) {
- return Error("Failed to create provisioner root directory '" +
- _root + "': " + mkdir.error());
- }
-
- Result<string> root = os::realpath(_root);
- if (root.isError()) {
- return Error(
- "Failed to resolve the realpath of provisioner root directory '" +
- _root + "': " + root.error());
- }
-
- CHECK_SOME(root); // Can't be None since we just created it.
-
- Try<Owned<Store>> store = Store::create(flags);
- if (store.isError()) {
- return Error("Failed to create image store: " + store.error());
- }
-
- hashmap<string, Owned<Backend>> backends = Backend::create(flags);
- if (backends.empty()) {
- return Error("No usable provisioner backend created");
- }
-
- if (!backends.contains(flags.appc_backend)) {
- return Error("The specified provisioner backend '" + flags.appc_backend +
- "'is unsupported");
- }
-
- return Owned<Provisioner>(new AppcProvisioner(
- Owned<AppcProvisionerProcess>(new AppcProvisionerProcess(
- flags,
- root.get(),
- store.get(),
- backends))));
-}
-
-
-AppcProvisioner::AppcProvisioner(Owned<AppcProvisionerProcess> _process)
- : process(_process)
-{
- spawn(CHECK_NOTNULL(process.get()));
-}
-
-
-AppcProvisioner::~AppcProvisioner()
-{
- terminate(process.get());
- wait(process.get());
-}
-
-
-Future<Nothing> AppcProvisioner::recover(
- const list<ContainerState>& states,
- const hashset<ContainerID>& orphans)
-{
- return dispatch(
- process.get(),
- &AppcProvisionerProcess::recover,
- states,
- orphans);
-}
-
-
-Future<string> AppcProvisioner::provision(
- const ContainerID& containerId,
- const Image& image)
-{
- return dispatch(
- process.get(),
- &AppcProvisionerProcess::provision,
- containerId,
- image);
-}
-
-
-Future<bool> AppcProvisioner::destroy(const ContainerID& containerId)
-{
- return dispatch(
- process.get(),
- &AppcProvisionerProcess::destroy,
- containerId);
-}
-
-
-AppcProvisionerProcess::AppcProvisionerProcess(
- const Flags& _flags,
- const string& _root,
- const Owned<Store>& _store,
- const hashmap<string, Owned<Backend>>& _backends)
- : flags(_flags),
- root(_root),
- store(_store),
- backends(_backends) {}
-
-
-Future<Nothing> AppcProvisionerProcess::recover(
- const list<ContainerState>& states,
- const hashset<ContainerID>& orphans)
-{
- // Register living containers, including the ones that do not
- // provision Appc images.
- hashset<ContainerID> alive;
-
- foreach (const ContainerState& state, states) {
- if (state.executor_info().has_container() &&
- state.executor_info().container().type() == ContainerInfo::MESOS) {
- alive.insert(state.container_id());
- }
- }
-
- // List provisioned containers; recover living ones; destroy unknown orphans.
- // Note that known orphan containers are recovered as well and they will
- // be destroyed by the containerizer using the normal cleanup path. See
- // MESOS-2367 for details.
- Try<hashmap<ContainerID, string>> containers =
- provisioners::paths::listContainers(root);
-
- if (containers.isError()) {
- return Failure("Failed to list the containers managed by Appc "
- "provisioner: " + containers.error());
- }
-
- // If no container has been launched the 'containers' directory will be
empty.
- foreachkey (const ContainerID& containerId, containers.get()) {
- if (alive.contains(containerId) || orphans.contains(containerId)) {
- Owned<Info> info = Owned<Info>(new Info());
-
- Try<hashmap<string, hashmap<string, string>>> rootfses =
- provisioners::paths::listContainerRootfses(root, containerId);
-
- if (rootfses.isError()) {
- return Failure("Unable to list rootfses belonged to container '" +
- containerId.value() + "': " + rootfses.error());
- }
-
- foreachkey (const string& backend, rootfses.get()) {
- if (!backends.contains(backend)) {
- return Failure("Found rootfses managed by an unrecognized backend: "
+
- backend);
- }
-
- info->rootfses.put(backend, rootfses.get()[backend]);
- }
-
- VLOG(1) << "Recovered container " << containerId;
- infos.put(containerId, info);
-
- continue;
- }
-
- // Destroy (unknown) orphan container's rootfses.
- Try<hashmap<string, hashmap<string, string>>> rootfses =
- provisioners::paths::listContainerRootfses(root, containerId);
-
- if (rootfses.isError()) {
- return Failure("Unable to find rootfses for container '" +
- containerId.value() + "': " + rootfses.error());
- }
-
- foreachkey (const string& backend, rootfses.get()) {
- if (!backends.contains(backend)) {
- return Failure("Found rootfses managed by an unrecognized backend: " +
- backend);
- }
-
- foreachvalue (const string& rootfs, rootfses.get()[backend]) {
- VLOG(1) << "Destroying orphan rootfs " << rootfs;
-
- // Not waiting for the destruction and we don't care about
- // the return value.
- backends.get(backend).get()->destroy(rootfs)
- .onFailed([rootfs](const std::string& error) {
- LOG(WARNING) << "Failed to destroy orphan rootfs '" << rootfs
- << "': "<< error;
- });
- }
- }
- }
-
- LOG(INFO) << "Recovered Appc provisioner rootfses";
-
- return store->recover()
- .then([]() -> Future<Nothing> {
- LOG(INFO) << "Recovered Appc image store";
- return Nothing();
- });
-}
-
-
-Future<string> AppcProvisionerProcess::provision(
- const ContainerID& containerId,
- const Image& image)
-{
- if (image.type() != Image::APPC) {
- return Failure("Unsupported container image type: " +
- stringify(image.type()));
- }
-
- if (!image.has_appc()) {
- return Failure("Missing Appc image info");
- }
-
- string rootfsId = UUID::random().toString();
- string rootfs = provisioners::paths::getContainerRootfsDir(
- root, containerId, flags.appc_backend, rootfsId);
-
- if (!infos.contains(containerId)) {
- infos.put(containerId, Owned<Info>(new Info()));
- }
-
- infos[containerId]->rootfses[flags.appc_backend].put(rootfsId, rootfs);
-
- // Get and then provision image layers from the store.
- return store->get(image.appc())
- .then(defer(self(), &Self::_provision, lambda::_1, rootfs));
-}
-
-
-Future<string> AppcProvisionerProcess::_provision(
- const vector<string>& layers,
- const string& rootfs)
-{
- LOG(INFO) << "Provisioning image layers to rootfs '" << rootfs << "'";
-
- CHECK(backends.contains(flags.appc_backend));
- return backends.get(flags.appc_backend).get()->provision(layers, rootfs)
- .then([rootfs]() -> Future<string> { return rootfs; });
-}
-
-
-Future<bool> AppcProvisionerProcess::destroy(const ContainerID& containerId)
-{
- if (!infos.contains(containerId)) {
- LOG(INFO) << "Ignoring destroy request for unknown container: "
- << containerId;
-
- return false;
- }
-
- // Unregister the container first. If destroy() fails, we can rely on
- // recover() to retry it later.
- Owned<Info> info = infos[containerId];
- infos.erase(containerId);
-
- list<Future<bool>> futures;
- foreachkey (const string& backend, info->rootfses) {
- foreachvalue (const string& rootfs, info->rootfses[backend]) {
- if (!backends.contains(backend)) {
- return Failure("Cannot destroy rootfs '" + rootfs +
- "' provisioned by an unknown backend '" + backend +
"'");
- }
-
- LOG(INFO) << "Destroying container rootfs for container '"
- << containerId << "' at '" << rootfs << "'";
-
- futures.push_back(
- backends.get(backend).get()->destroy(rootfs));
- }
- }
-
- // TODO(xujyan): Revisit the usefulness of this return value.
- return collect(futures)
- .then([=](const list<bool>& results) -> Future<bool> {
- return true;
- });
-}
-
-} // namespace appc {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/0636f2b3/src/slave/containerizer/provisioners/appc.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/appc.hpp
b/src/slave/containerizer/provisioners/appc.hpp
deleted file mode 100644
index 68e82e3..0000000
--- a/src/slave/containerizer/provisioners/appc.hpp
+++ /dev/null
@@ -1,78 +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 __MESOS_APPC_HPP__
-#define __MESOS_APPC_HPP__
-
-#include <list>
-#include <string>
-#include <vector>
-
-#include <process/future.hpp>
-#include <process/owned.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/json.hpp>
-#include <stout/nothing.hpp>
-#include <stout/try.hpp>
-
-#include "slave/containerizer/provisioner.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace appc {
-
-// Forward declaration.
-class AppcProvisionerProcess;
-
-
-class AppcProvisioner : public Provisioner
-{
-public:
- static Try<process::Owned<Provisioner>> create(
- const Flags& flags,
- Fetcher* fetcher);
-
- ~AppcProvisioner();
-
- virtual process::Future<Nothing> recover(
- const std::list<mesos::slave::ContainerState>& states,
- const hashset<ContainerID>& orphans);
-
- virtual process::Future<std::string> provision(
- const ContainerID& containerId,
- const Image& image);
-
- virtual process::Future<bool> destroy(const ContainerID& containerId);
-
-private:
- explicit AppcProvisioner(process::Owned<AppcProvisionerProcess> process);
-
- AppcProvisioner(const AppcProvisioner&); // Not copyable.
- AppcProvisioner& operator=(const AppcProvisioner&); // Not assignable.
-
- process::Owned<AppcProvisionerProcess> process;
-};
-
-} // namespace appc {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __MESOS_APPC_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/0636f2b3/src/slave/containerizer/provisioners/appc/provisioner.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/appc/provisioner.cpp
b/src/slave/containerizer/provisioners/appc/provisioner.cpp
new file mode 100644
index 0000000..5204cbc
--- /dev/null
+++ b/src/slave/containerizer/provisioners/appc/provisioner.cpp
@@ -0,0 +1,379 @@
+/**
+ * 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 <mesos/type_utils.hpp>
+
+#include <process/collect.hpp>
+#include <process/defer.hpp>
+#include <process/dispatch.hpp>
+#include <process/process.hpp>
+
+#include <stout/foreach.hpp>
+#include <stout/hashset.hpp>
+#include <stout/os.hpp>
+#include <stout/stringify.hpp>
+#include <stout/strings.hpp>
+#include <stout/uuid.hpp>
+
+#include "slave/containerizer/provisioners/backend.hpp"
+#include "slave/containerizer/provisioners/paths.hpp"
+
+#include "slave/containerizer/provisioners/appc/paths.hpp"
+#include "slave/containerizer/provisioners/appc/provisioner.hpp"
+#include "slave/containerizer/provisioners/appc/spec.hpp"
+#include "slave/containerizer/provisioners/appc/store.hpp"
+
+#include "slave/paths.hpp"
+
+using namespace process;
+using namespace mesos::internal::slave;
+
+using std::list;
+using std::string;
+using std::vector;
+
+using mesos::slave::ContainerState;
+
+namespace mesos {
+namespace internal {
+namespace slave {
+namespace appc {
+
+class AppcProvisionerProcess : public Process<AppcProvisionerProcess>
+{
+public:
+ AppcProvisionerProcess(
+ const Flags& flags,
+ const string& root,
+ const Owned<Store>& store,
+ const hashmap<string, Owned<Backend>>& backends);
+
+ Future<Nothing> recover(
+ const list<ContainerState>& states,
+ const hashset<ContainerID>& orphans);
+
+ Future<string> provision(const ContainerID& containerId, const Image& image);
+
+ Future<bool> destroy(const ContainerID& containerId);
+
+private:
+ Future<string> _provision(const vector<string>& layers, const string&
rootfs);
+
+ const Flags flags;
+
+ // Absolute path to the Appc provisioner root directory. It can be derived
+ // from '--work_dir' but we keep a separate copy here because we converted
+ // it into an absolute path so managed rootfs paths match the ones in
+ // 'mountinfo' (important if mount-based backends are used).
+ const string root;
+
+ const Owned<Store> store;
+ const hashmap<string, Owned<Backend>> backends;
+
+ struct Info
+ {
+ // Mappings: backend -> rootfsId -> rootfsPath.
+ hashmap<string, hashmap<string, string>> rootfses;
+ };
+
+ hashmap<ContainerID, Owned<Info>> infos;
+};
+
+
+// NOTE: Successful creation of the provisioner means its managed
+// directory under --work_dir is also created.
+Try<Owned<Provisioner>> AppcProvisioner::create(
+ const Flags& flags,
+ Fetcher* fetcher)
+{
+ string _root =
+ slave::paths::getProvisionerDir(flags.work_dir, Image::APPC);
+
+ Try<Nothing> mkdir = os::mkdir(_root);
+ if (mkdir.isError()) {
+ return Error("Failed to create provisioner root directory '" +
+ _root + "': " + mkdir.error());
+ }
+
+ Result<string> root = os::realpath(_root);
+ if (root.isError()) {
+ return Error(
+ "Failed to resolve the realpath of provisioner root directory '" +
+ _root + "': " + root.error());
+ }
+
+ CHECK_SOME(root); // Can't be None since we just created it.
+
+ Try<Owned<Store>> store = Store::create(flags);
+ if (store.isError()) {
+ return Error("Failed to create image store: " + store.error());
+ }
+
+ hashmap<string, Owned<Backend>> backends = Backend::create(flags);
+ if (backends.empty()) {
+ return Error("No usable provisioner backend created");
+ }
+
+ if (!backends.contains(flags.appc_backend)) {
+ return Error("The specified provisioner backend '" + flags.appc_backend +
+ "'is unsupported");
+ }
+
+ return Owned<Provisioner>(new AppcProvisioner(
+ Owned<AppcProvisionerProcess>(new AppcProvisionerProcess(
+ flags,
+ root.get(),
+ store.get(),
+ backends))));
+}
+
+
+AppcProvisioner::AppcProvisioner(Owned<AppcProvisionerProcess> _process)
+ : process(_process)
+{
+ spawn(CHECK_NOTNULL(process.get()));
+}
+
+
+AppcProvisioner::~AppcProvisioner()
+{
+ terminate(process.get());
+ wait(process.get());
+}
+
+
+Future<Nothing> AppcProvisioner::recover(
+ const list<ContainerState>& states,
+ const hashset<ContainerID>& orphans)
+{
+ return dispatch(
+ process.get(),
+ &AppcProvisionerProcess::recover,
+ states,
+ orphans);
+}
+
+
+Future<string> AppcProvisioner::provision(
+ const ContainerID& containerId,
+ const Image& image)
+{
+ return dispatch(
+ process.get(),
+ &AppcProvisionerProcess::provision,
+ containerId,
+ image);
+}
+
+
+Future<bool> AppcProvisioner::destroy(const ContainerID& containerId)
+{
+ return dispatch(
+ process.get(),
+ &AppcProvisionerProcess::destroy,
+ containerId);
+}
+
+
+AppcProvisionerProcess::AppcProvisionerProcess(
+ const Flags& _flags,
+ const string& _root,
+ const Owned<Store>& _store,
+ const hashmap<string, Owned<Backend>>& _backends)
+ : flags(_flags),
+ root(_root),
+ store(_store),
+ backends(_backends) {}
+
+
+Future<Nothing> AppcProvisionerProcess::recover(
+ const list<ContainerState>& states,
+ const hashset<ContainerID>& orphans)
+{
+ // Register living containers, including the ones that do not
+ // provision Appc images.
+ hashset<ContainerID> alive;
+
+ foreach (const ContainerState& state, states) {
+ if (state.executor_info().has_container() &&
+ state.executor_info().container().type() == ContainerInfo::MESOS) {
+ alive.insert(state.container_id());
+ }
+ }
+
+ // List provisioned containers; recover living ones; destroy unknown orphans.
+ // Note that known orphan containers are recovered as well and they will
+ // be destroyed by the containerizer using the normal cleanup path. See
+ // MESOS-2367 for details.
+ Try<hashmap<ContainerID, string>> containers =
+ provisioners::paths::listContainers(root);
+
+ if (containers.isError()) {
+ return Failure("Failed to list the containers managed by Appc "
+ "provisioner: " + containers.error());
+ }
+
+ // If no container has been launched the 'containers' directory will be
empty.
+ foreachkey (const ContainerID& containerId, containers.get()) {
+ if (alive.contains(containerId) || orphans.contains(containerId)) {
+ Owned<Info> info = Owned<Info>(new Info());
+
+ Try<hashmap<string, hashmap<string, string>>> rootfses =
+ provisioners::paths::listContainerRootfses(root, containerId);
+
+ if (rootfses.isError()) {
+ return Failure("Unable to list rootfses belonged to container '" +
+ containerId.value() + "': " + rootfses.error());
+ }
+
+ foreachkey (const string& backend, rootfses.get()) {
+ if (!backends.contains(backend)) {
+ return Failure("Found rootfses managed by an unrecognized backend: "
+
+ backend);
+ }
+
+ info->rootfses.put(backend, rootfses.get()[backend]);
+ }
+
+ VLOG(1) << "Recovered container " << containerId;
+ infos.put(containerId, info);
+
+ continue;
+ }
+
+ // Destroy (unknown) orphan container's rootfses.
+ Try<hashmap<string, hashmap<string, string>>> rootfses =
+ provisioners::paths::listContainerRootfses(root, containerId);
+
+ if (rootfses.isError()) {
+ return Failure("Unable to find rootfses for container '" +
+ containerId.value() + "': " + rootfses.error());
+ }
+
+ foreachkey (const string& backend, rootfses.get()) {
+ if (!backends.contains(backend)) {
+ return Failure("Found rootfses managed by an unrecognized backend: " +
+ backend);
+ }
+
+ foreachvalue (const string& rootfs, rootfses.get()[backend]) {
+ VLOG(1) << "Destroying orphan rootfs " << rootfs;
+
+ // Not waiting for the destruction and we don't care about
+ // the return value.
+ backends.get(backend).get()->destroy(rootfs)
+ .onFailed([rootfs](const std::string& error) {
+ LOG(WARNING) << "Failed to destroy orphan rootfs '" << rootfs
+ << "': "<< error;
+ });
+ }
+ }
+ }
+
+ LOG(INFO) << "Recovered Appc provisioner rootfses";
+
+ return store->recover()
+ .then([]() -> Future<Nothing> {
+ LOG(INFO) << "Recovered Appc image store";
+ return Nothing();
+ });
+}
+
+
+Future<string> AppcProvisionerProcess::provision(
+ const ContainerID& containerId,
+ const Image& image)
+{
+ if (image.type() != Image::APPC) {
+ return Failure("Unsupported container image type: " +
+ stringify(image.type()));
+ }
+
+ if (!image.has_appc()) {
+ return Failure("Missing Appc image info");
+ }
+
+ string rootfsId = UUID::random().toString();
+ string rootfs = provisioners::paths::getContainerRootfsDir(
+ root, containerId, flags.appc_backend, rootfsId);
+
+ if (!infos.contains(containerId)) {
+ infos.put(containerId, Owned<Info>(new Info()));
+ }
+
+ infos[containerId]->rootfses[flags.appc_backend].put(rootfsId, rootfs);
+
+ // Get and then provision image layers from the store.
+ return store->get(image.appc())
+ .then(defer(self(), &Self::_provision, lambda::_1, rootfs));
+}
+
+
+Future<string> AppcProvisionerProcess::_provision(
+ const vector<string>& layers,
+ const string& rootfs)
+{
+ LOG(INFO) << "Provisioning image layers to rootfs '" << rootfs << "'";
+
+ CHECK(backends.contains(flags.appc_backend));
+ return backends.get(flags.appc_backend).get()->provision(layers, rootfs)
+ .then([rootfs]() -> Future<string> { return rootfs; });
+}
+
+
+Future<bool> AppcProvisionerProcess::destroy(const ContainerID& containerId)
+{
+ if (!infos.contains(containerId)) {
+ LOG(INFO) << "Ignoring destroy request for unknown container: "
+ << containerId;
+
+ return false;
+ }
+
+ // Unregister the container first. If destroy() fails, we can rely on
+ // recover() to retry it later.
+ Owned<Info> info = infos[containerId];
+ infos.erase(containerId);
+
+ list<Future<bool>> futures;
+ foreachkey (const string& backend, info->rootfses) {
+ foreachvalue (const string& rootfs, info->rootfses[backend]) {
+ if (!backends.contains(backend)) {
+ return Failure("Cannot destroy rootfs '" + rootfs +
+ "' provisioned by an unknown backend '" + backend +
"'");
+ }
+
+ LOG(INFO) << "Destroying container rootfs for container '"
+ << containerId << "' at '" << rootfs << "'";
+
+ futures.push_back(
+ backends.get(backend).get()->destroy(rootfs));
+ }
+ }
+
+ // TODO(xujyan): Revisit the usefulness of this return value.
+ return collect(futures)
+ .then([=](const list<bool>& results) -> Future<bool> {
+ return true;
+ });
+}
+
+} // namespace appc {
+} // namespace slave {
+} // namespace internal {
+} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/0636f2b3/src/slave/containerizer/provisioners/appc/provisioner.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/appc/provisioner.hpp
b/src/slave/containerizer/provisioners/appc/provisioner.hpp
new file mode 100644
index 0000000..764b119
--- /dev/null
+++ b/src/slave/containerizer/provisioners/appc/provisioner.hpp
@@ -0,0 +1,78 @@
+/**
+ * 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 __APPC_PROVISIONER_HPP__
+#define __APPC_PROVISIONER_HPP__
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include <process/future.hpp>
+#include <process/owned.hpp>
+
+#include <stout/hashmap.hpp>
+#include <stout/json.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+#include "slave/containerizer/provisioner.hpp"
+
+namespace mesos {
+namespace internal {
+namespace slave {
+namespace appc {
+
+// Forward declaration.
+class AppcProvisionerProcess;
+
+
+class AppcProvisioner : public Provisioner
+{
+public:
+ static Try<process::Owned<Provisioner>> create(
+ const Flags& flags,
+ Fetcher* fetcher);
+
+ ~AppcProvisioner();
+
+ virtual process::Future<Nothing> recover(
+ const std::list<mesos::slave::ContainerState>& states,
+ const hashset<ContainerID>& orphans);
+
+ virtual process::Future<std::string> provision(
+ const ContainerID& containerId,
+ const Image& image);
+
+ virtual process::Future<bool> destroy(const ContainerID& containerId);
+
+private:
+ explicit AppcProvisioner(process::Owned<AppcProvisionerProcess> process);
+
+ AppcProvisioner(const AppcProvisioner&); // Not copyable.
+ AppcProvisioner& operator=(const AppcProvisioner&); // Not assignable.
+
+ process::Owned<AppcProvisionerProcess> process;
+};
+
+} // namespace appc {
+} // namespace slave {
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __APPC_PROVISIONER_HPP__