blob: c34f1296586ea5d26619605f8f6a5ae9444f1a96 [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 __MESOS_SLAVE_CONTAINERIZER_HPP__
#define __MESOS_SLAVE_CONTAINERIZER_HPP__
#include <string>
#include <process/shared.hpp>
#include <process/subprocess.hpp>
#include <stout/option.hpp>
// ONLY USEFUL AFTER RUNNING PROTOC.
#include <mesos/slave/containerizer.pb.h>
namespace mesos {
namespace slave {
/**
* An abstraction around the IO classes used to redirect
* stdin/stdout/stderr to/from a container by the containerizer.
*/
struct ContainerIO
{
/**
* Describes how the containerizer redirects I/O for
* stdin/stdout/stderr of a container.
* See `process::Subprocess::IO`.
*
* NOTE: This wrapper prevents the containerizer from redirecting I/O
* via a `Subprocess::PIPE`. This is restricted because the IO of a
* container must not be affected by the status of the agent process:
* * A `Subprocess::PIPE` will require the agent process to regularly
* read and empty the pipe. The agent does not do this. If the pipe
* fills up, the write-end of the pipe may become blocked on IO.
* * Redirection must continue even if the agent dies.
*/
class IO
{
public:
enum class Type
{
FD,
PATH
};
static IO PATH(const std::string& path)
{
return IO(Type::PATH, path);
}
static IO FD(int_fd fd, bool closeOnDestruction = true)
{
return IO(Type::FD, fd, closeOnDestruction);
}
operator process::Subprocess::IO () const
{
switch (type_) {
case Type::FD:
return process::Subprocess::FD(*fd_);
case Type::PATH:
return process::Subprocess::PATH(path_.get());
default:
UNREACHABLE();
}
}
private:
// A simple abstraction to wrap an FD and (optionally) close it
// on destruction. We know that we never copy instances of this
// class once they are instantiated, so it's OK to call
// `close()` in the destructor since only one reference will
// ever exist to it.
class FDWrapper
{
public:
FDWrapper(int_fd _fd, bool _closeOnDestruction)
: fd(_fd), closeOnDestruction(_closeOnDestruction) {}
~FDWrapper() {
CHECK(fd >= 0);
if (closeOnDestruction) {
close(fd);
}
}
operator int_fd() const { return fd; }
private:
FDWrapper(const FDWrapper& fd) = delete;
int_fd fd;
bool closeOnDestruction;
};
IO(Type _type, int_fd _fd, bool closeOnDestruction)
: type_(_type),
fd_(new FDWrapper(_fd, closeOnDestruction)),
path_(None()) {}
IO(Type _type, const std::string& _path)
: type_(_type),
fd_(),
path_(_path) {}
Type type_;
process::Shared<FDWrapper> fd_;
Option<std::string> path_;
};
/**
* How to redirect the stdin of the executable.
* See `process::Subprocess::IO`.
*/
IO in = IO::FD(STDIN_FILENO, false);
/**
* How to redirect the stdout of the executable.
* See `process::Subprocess::IO`.
*/
IO out = IO::FD(STDOUT_FILENO, false);
/**
* Similar to `out`, except this describes how to redirect stderr.
*/
IO err = IO::FD(STDERR_FILENO, false);
};
} // namespace slave {
} // namespace mesos {
#endif // __MESOS_SLAVE_CONTAINERIZER_HPP__