blob: 9bfb5d578912a0aeb2b2abb2f3e91f191b540da9 [file] [log] [blame]
// 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 __PROVISIONER_HPP__
#define __PROVISIONER_HPP__
#include <vector>
#include <mesos/resources.hpp>
#include <mesos/appc/spec.hpp>
#include <mesos/docker/v1.hpp>
#include <mesos/secret/resolver.hpp>
#include <mesos/slave/isolator.hpp> // For ContainerState.
#include <stout/nothing.hpp>
#include <stout/path.hpp>
#include <stout/try.hpp>
#include <process/future.hpp>
#include <process/owned.hpp>
#include <process/rwlock.hpp>
#include <process/metrics/counter.hpp>
#include <process/metrics/metrics.hpp>
#include "slave/flags.hpp"
#include "slave/containerizer/fetcher.hpp"
#include "slave/containerizer/mesos/provisioner/store.hpp"
namespace mesos {
namespace internal {
namespace slave {
// Forward declaration.
class Backend;
class ProvisionerProcess;
class Store;
// Provision info struct includes root filesystem for the container
// with specified image, all image manifests that include runtime
// configurations from the image will be passed to Mesos Containerizer.
struct ProvisionInfo
{
std::string rootfs;
// Ephemeral volumes are any additional paths the Provisioner backend
// may have created that should be counted towards the sandbox disk quota.
Option<std::vector<Path>> ephemeralVolumes;
// Docker v1 image manifest.
Option<::docker::spec::v1::ImageManifest> dockerManifest;
// Appc image manifest.
Option<::appc::spec::ImageManifest> appcManifest;
};
class Provisioner
{
public:
// Create the provisioner based on the specified flags.
static Try<process::Owned<Provisioner>> create(
const Flags& flags,
SecretResolver* secretResolver = nullptr);
// This allows the backend to be mocked for testing.
static Try<process::Owned<Provisioner>> create(
const Flags& flags,
const std::string& rootDir,
const std::string& defaultBackend,
const hashmap<std::string, process::Owned<Backend>>& backends,
SecretResolver* secretResolver = nullptr);
// Available only for testing.
explicit Provisioner(process::Owned<ProvisionerProcess> process);
// NOTE: Made 'virtual' for mocking and testing.
virtual ~Provisioner();
// Recover root filesystems for containers from the known
// containers (forked by the launcher) detected by the
// launcher. This function is also responsible for cleaning
// up any intermediate artifacts (e.g. directories) to not
// leak anything.
virtual process::Future<Nothing> recover(
const hashset<ContainerID>& knownContainerIds) const;
// Provision a root filesystem for the container using the specified
// image and return the absolute path to the root filesystem.
virtual process::Future<ProvisionInfo> provision(
const ContainerID& containerId,
const Image& image) const;
// Destroy a previously provisioned root filesystem. Assumes that
// all references (e.g., mounts, open files) to the provisioned
// filesystem have been removed. Return false if there is no
// provisioned root filesystem for the given container.
virtual process::Future<bool> destroy(const ContainerID& containerId) const;
// Prune images in different stores. Image references in excludedImages
// will be passed to stores and retained in a best effort fashion.
// All layer paths used by active containers will not be pruned.
virtual process::Future<Nothing> pruneImages(
const std::vector<Image>& excludedImages) const;
protected:
Provisioner() {} // For creating mock object.
private:
Provisioner(const Provisioner&) = delete; // Not copyable.
Provisioner& operator=(const Provisioner&) = delete; // Not assignable.
process::Owned<ProvisionerProcess> process;
};
// Expose this class for testing only.
class ProvisionerProcess : public process::Process<ProvisionerProcess>
{
public:
ProvisionerProcess(
const std::string& rootDir,
const std::string& defaultBackend,
const hashmap<Image::Type, process::Owned<Store>>& stores,
const hashmap<std::string, process::Owned<Backend>>& backends);
process::Future<Nothing> recover(
const hashset<ContainerID>& knownContainerIds);
process::Future<ProvisionInfo> provision(
const ContainerID& containerId,
const Image& image);
process::Future<bool> destroy(const ContainerID& containerId);
process::Future<Nothing> pruneImages(
const std::vector<Image>& excludedImages);
private:
process::Future<ProvisionInfo> _provision(
const ContainerID& containerId,
const Image& image,
const std::string& backend,
const ImageInfo& imageInfo);
process::Future<bool> _destroy(
const ContainerID& containerId,
const std::vector<process::Future<bool>>& destroys);
void __destroy(
const ContainerID& containerId,
const process::Future<std::vector<process::Future<bool>>>& futures);
// Absolute path to the 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 std::string rootDir;
// The default provisioner backend, using the following logic:
// 1. Use `--image_provisioner_backend` if it is set.
// 2. Use overlayfs backend if it exists.
// 3. Use aufs backend if the overlayfs does not exist.
// 4. Use copy backend of both overlayfs and aufs do not exist.
const std::string defaultBackend;
const hashmap<Image::Type, process::Owned<Store>> stores;
const hashmap<std::string, process::Owned<Backend>> backends;
struct Info
{
// Mappings: backend -> {rootfsId, ...}
hashmap<std::string, hashset<std::string>> rootfses;
// TODO(zhitao): Remove Option after the deprecation cycle
// started in 1.5.
Option<std::vector<std::string>> layers;
// We keep track of the future for 'backend->provision' so
// that destroy will only start calling 'backend->destroy'
// after 'backend->provision' has finished.
process::Future<ProvisionInfo> provisioning;
process::Promise<bool> termination;
// The container status in provisioner.
bool destroying = false;
};
hashmap<ContainerID, process::Owned<Info>> infos;
struct Metrics
{
Metrics();
~Metrics();
process::metrics::Counter remove_container_errors;
} metrics;
// This `ReadWriteLock` instance is used to protect the critical section which
// is the layers in the store directory (i.e. `--docker_store_dir`/layers/).
// Any `provision` and `destroy` can happen concurrently since they are not
// expected to touch the critical section simultaneously.
//
// On the other hand, `pruneImages` needs to know all active layers from all
// containers, therefore it must be exclusive to other `provision`, `destroy`
// and `pruneImages` so that we do not prune image layers which are used by an
// active `provision` or `destroy`.
process::ReadWriteLock rwLock;
};
} // namespace slave {
} // namespace internal {
} // namespace mesos {
#endif // __PROVISIONER_HPP__