Esempio n. 1
0
TEST(DurationTest, Comparison)
{
  EXPECT_EQ(Duration::zero(), Seconds(0));
  EXPECT_EQ(Minutes(180), Hours(3));
  EXPECT_EQ(Seconds(10800), Hours(3));
  EXPECT_EQ(Milliseconds(10800000), Hours(3));

  EXPECT_EQ(Milliseconds(1), Microseconds(1000));
  EXPECT_EQ(Milliseconds(1000), Seconds(1));

  EXPECT_GT(Weeks(1), Days(6));

  EXPECT_LT(Hours(23), Days(1));

  EXPECT_LE(Hours(24), Days(1));
  EXPECT_GE(Hours(24), Days(1));

  EXPECT_NE(Minutes(59), Hours(1));

  // Maintains precision for a 100 year duration.
  EXPECT_GT(Weeks(5217) + Nanoseconds(1), Weeks(5217));
  EXPECT_LT(Weeks(5217) - Nanoseconds(1), Weeks(5217));
}
// Ensures that the driver can handle the SUBSCRIBED event.
TEST_F(SchedulerDriverEventTest, Subscribed)
{
    Try<Owned<cluster::Master>> master = StartMaster();
    ASSERT_SOME(master);

    FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
    frameworkInfo.set_failover_timeout(Weeks(2).secs());

    // Make sure the initial registration calls 'registered'.
    MockScheduler sched;
    MesosSchedulerDriver driver(
        &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);

    // Intercept the registration message, send a SUBSCRIBED instead.
    Future<Message> frameworkRegisteredMessage =
        DROP_MESSAGE(Eq(FrameworkRegisteredMessage().GetTypeName()), _, _);

    // Ensure that there will be no (re-)registration retries
    // from the scheduler driver.
    Clock::pause();

    driver.start();

    AWAIT_READY(frameworkRegisteredMessage);
    UPID frameworkPid = frameworkRegisteredMessage.get().to;

    FrameworkRegisteredMessage message;
    ASSERT_TRUE(message.ParseFromString(frameworkRegisteredMessage.get().body));

    FrameworkID frameworkId = message.framework_id();
    frameworkInfo.mutable_id()->CopyFrom(frameworkId);

    Event event;
    event.set_type(Event::SUBSCRIBED);
    event.mutable_subscribed()->mutable_framework_id()->CopyFrom(frameworkId);

    Future<Nothing> registered;
    EXPECT_CALL(sched, registered(&driver, frameworkId, _))
    .WillOnce(FutureSatisfy(&registered));

    process::post(master.get()->pid, frameworkPid, event);

    AWAIT_READY(registered);

    driver.stop();
    driver.join();
}
Esempio n. 3
0
namespace slave {

const Duration EXECUTOR_REGISTRATION_TIMEOUT = Minutes(1);
const Duration EXECUTOR_SHUTDOWN_GRACE_PERIOD = Seconds(5);
const Duration EXECUTOR_REREGISTER_TIMEOUT = Seconds(2);
const Duration EXECUTOR_SIGNAL_ESCALATION_TIMEOUT = Seconds(3);
const Duration STATUS_UPDATE_RETRY_INTERVAL_MIN = Seconds(10);
const Duration STATUS_UPDATE_RETRY_INTERVAL_MAX = Minutes(10);
const Duration REGISTRATION_BACKOFF_FACTOR = Seconds(1);
const Duration REGISTER_RETRY_INTERVAL_MAX = Minutes(1);
const Duration GC_DELAY = Weeks(1);
const double GC_DISK_HEADROOM = 0.1;
const Duration DISK_WATCH_INTERVAL = Minutes(1);
const Duration RECOVERY_TIMEOUT = Minutes(15);
const Duration RESOURCE_MONITORING_INTERVAL = Seconds(1);
const uint32_t MAX_COMPLETED_FRAMEWORKS = 50;
const uint32_t MAX_COMPLETED_EXECUTORS_PER_FRAMEWORK = 150;
const uint32_t MAX_COMPLETED_TASKS_PER_EXECUTOR = 200;
const double DEFAULT_CPUS = 1;
const Bytes DEFAULT_MEM = Gigabytes(1);
const Bytes DEFAULT_DISK = Gigabytes(10);
const std::string DEFAULT_PORTS = "[31000-32000]";
#ifdef WITH_NETWORK_ISOLATOR
const uint16_t DEFAULT_EPHEMERAL_PORTS_PER_CONTAINER = 1024;
#endif
const Duration DOCKER_REMOVE_DELAY = Hours(6);
const Duration DOCKER_INSPECT_DELAY = Seconds(1);
// TODO(tnachen): Make this a flag.
const Duration DOCKER_VERSION_WAIT_TIMEOUT = Seconds(5);
const std::string DEFAULT_AUTHENTICATEE = "crammd5";

Duration DEFAULT_MASTER_PING_TIMEOUT()
{
  return master::DEFAULT_SLAVE_PING_TIMEOUT *
    master::DEFAULT_MAX_SLAVE_PING_TIMEOUTS;
}

} // namespace slave {
Esempio n. 4
0
// This test verifies that if master --> framework socket closes and the
// framework is not aware of it (i.e., one way network partition), all
// subsequent calls from the framework after the master has marked it as
// disconnected would result in an error message causing the framework to abort.
TEST_F(PartitionTest, OneWayPartitionMasterToScheduler)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
  frameworkInfo.set_failover_timeout(Weeks(2).secs());

  MockScheduler sched;
  StandaloneMasterDetector detector(master.get()->pid);
  TestingMesosSchedulerDriver driver(&sched, &detector, frameworkInfo);

  Future<process::Message> frameworkRegisteredMessage =
    FUTURE_MESSAGE(Eq(FrameworkRegisteredMessage().GetTypeName()), _, _);

  Future<Nothing> registered;
  EXPECT_CALL(sched, registered(&driver, _, _))
    .WillOnce(FutureSatisfy(&registered));

  driver.start();

  AWAIT_READY(frameworkRegisteredMessage);

  AWAIT_READY(registered);

  Future<Nothing> error;
  EXPECT_CALL(sched, error(&driver, _))
    .WillOnce(FutureSatisfy(&error));

  // Simulate framework disconnection. This should result in an error message.
  ASSERT_TRUE(process::inject::exited(
      frameworkRegisteredMessage.get().to, master.get()->pid));

  AWAIT_READY(error);

  driver.stop();
  driver.join();
}
Esempio n. 5
0
inline std::ostream& operator<<(std::ostream& stream, const Duration& duration_)
{
  // Output the duration in full double precision and save the old precision.
  std::streamsize precision =
    stream.precision(std::numeric_limits<double>::digits10);

  // Parse the duration as the sign and the absolute value.
  Duration duration = duration_;
  if (duration_ < Duration::zero()) {
    stream << "-";

    // Duration::min() may not be representable as a positive Duration.
    if (duration_ == Duration::min()) {
      duration = Duration::max();
    } else {
      duration = duration_ * -1;
    }
  }

  // First determine which bucket of time unit the duration falls into
  // then check whether the duration can be represented as a whole
  // number with this time unit or a smaller one.
  // e.g. 1.42857142857143weeks falls into the 'Weeks' bucket but
  // reads better with a smaller unit: '10days'. So we use 'days'
  // instead of 'weeks' to output the duration.
  int64_t nanoseconds = duration.ns();
  if (duration < Microseconds(1)) {
    stream << duration.ns() << Nanoseconds::units();
  } else if (duration < Milliseconds(1)) {
    if (nanoseconds % Duration::MICROSECONDS != 0) {
      // We can't get a whole number using this unit but we can at
      // one level down.
      stream << duration.ns() << Nanoseconds::units();
    } else {
      stream << duration.us() << Microseconds::units();
    }
  } else if (duration < Seconds(1)) {
    if (nanoseconds % Duration::MILLISECONDS != 0 &&
        nanoseconds % Duration::MICROSECONDS == 0) {
      stream << duration.us() << Microseconds::units();
    } else {
      stream << duration.ms() << Milliseconds::units();
    }
  } else if (duration < Minutes(1)) {
    if (nanoseconds % Duration::SECONDS != 0 &&
        nanoseconds % Duration::MILLISECONDS == 0) {
      stream << duration.ms() << Milliseconds::units();
    } else {
      stream << duration.secs() << Seconds::units();
    }
  } else if (duration < Hours(1)) {
    if (nanoseconds % Duration::MINUTES != 0 &&
        nanoseconds % Duration::SECONDS == 0) {
      stream << duration.secs() << Seconds::units();
    } else {
      stream << duration.mins() << Minutes::units();
    }
  } else if (duration < Days(1)) {
    if (nanoseconds % Duration::HOURS != 0 &&
        nanoseconds % Duration::MINUTES == 0) {
      stream << duration.mins() << Minutes::units();
    } else {
      stream << duration.hrs() << Hours::units();
    }
  } else if (duration < Weeks(1)) {
    if (nanoseconds % Duration::DAYS != 0 &&
        nanoseconds % Duration::HOURS == 0) {
      stream << duration.hrs() << Hours::units();
    } else {
      stream << duration.days() << Days::units();
    }
  } else {
    if (nanoseconds % Duration::WEEKS != 0 &&
        nanoseconds % Duration::DAYS == 0) {
      stream << duration.days() << Days::units();
    } else {
      stream << duration.weeks() << Weeks::units();
    }
  }

  // Return the stream to original formatting state.
  stream.precision(precision);

  return stream;
}
// Ensures that the driver can handle the SUBSCRIBED event
// after a master failover.
TEST_F(SchedulerDriverEventTest, SubscribedMasterFailover)
{
  Try<PID<Master>> master = StartMaster();
  ASSERT_SOME(master);

  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
  frameworkInfo.set_failover_timeout(Weeks(2).secs());

  // Make sure the initial registration calls 'registered'.
  MockScheduler sched;
  StandaloneMasterDetector detector(master.get());
  TestingMesosSchedulerDriver driver(&sched, &detector, frameworkInfo);

  // Intercept the registration message, send a SUBSCRIBED instead.
  Future<Message> frameworkRegisteredMessage =
    DROP_MESSAGE(Eq(FrameworkRegisteredMessage().GetTypeName()), _, _);

  // Ensure that there will be no (re-)registration retries
  // from the scheduler driver.
  Clock::pause();

  driver.start();

  AWAIT_READY(frameworkRegisteredMessage);
  UPID frameworkPid = frameworkRegisteredMessage.get().to;

  FrameworkRegisteredMessage message;
  ASSERT_TRUE(message.ParseFromString(frameworkRegisteredMessage.get().body));

  FrameworkID frameworkId = message.framework_id();
  frameworkInfo.mutable_id()->CopyFrom(frameworkId);

  Event event;
  event.set_type(Event::SUBSCRIBED);
  event.mutable_subscribed()->mutable_framework_id()->CopyFrom(frameworkId);

  Future<Nothing> registered;
  EXPECT_CALL(sched, registered(&driver, frameworkId, _))
    .WillOnce(FutureSatisfy(&registered));

  process::post(master.get(), frameworkPid, event);

  AWAIT_READY(registered);

  // Fail over the master and expect a 'reregistered' call.
  // Note that the master sends a registered message for
  // this case (see MESOS-786).
  Stop(master.get());
  master = StartMaster();
  ASSERT_SOME(master);

  EXPECT_CALL(sched, disconnected(&driver));

  frameworkRegisteredMessage =
    DROP_MESSAGE(Eq(FrameworkRegisteredMessage().GetTypeName()), _, _);

  detector.appoint(master.get());

  AWAIT_READY(frameworkRegisteredMessage);

  Future<Nothing> reregistered;
  EXPECT_CALL(sched, reregistered(&driver, _))
    .WillOnce(FutureSatisfy(&reregistered));

  process::post(master.get(), frameworkPid, event);

  AWAIT_READY(reregistered);
}
// This test verifies that a framework attempting to subscribe
// after its failover timeout has elapsed is disallowed.
TEST_F(HttpFaultToleranceTest, SchedulerSubscribeAfterFailoverTimeout)
{
  master::Flags flags = CreateMasterFlags();
  flags.authenticate_frameworks = false;

  v1::FrameworkInfo frameworkInfo = v1::DEFAULT_FRAMEWORK_INFO;
  frameworkInfo.set_failover_timeout(Weeks(2).secs());

  Try<Owned<cluster::Master>> master = StartMaster(flags);
  ASSERT_SOME(master);

  Future<Nothing> deactivateFramework = FUTURE_DISPATCH(
      _, &master::allocator::MesosAllocatorProcess::deactivateFramework);

  v1::FrameworkID frameworkId;

  ContentType contentType = ContentType::PROTOBUF;

  // Launch the first (i.e., failing) scheduler and wait until it receives
  // a `SUBSCRIBED` event to launch the second (i.e., failover) scheduler.
  {
    auto scheduler = std::make_shared<v1::MockHTTPScheduler>();

    Future<Nothing> connected;
    EXPECT_CALL(*scheduler, connected(_))
      .WillOnce(FutureSatisfy(&connected));

    v1::scheduler::TestMesos schedulerLibrary(
        master.get()->pid,
        contentType,
        scheduler);

    AWAIT_READY(connected);

    Future<Event::Subscribed> subscribed;
    EXPECT_CALL(*scheduler, subscribed(_, _))
      .WillOnce(FutureArg<1>(&subscribed));

    EXPECT_CALL(*scheduler, heartbeat(_))
      .WillRepeatedly(Return()); // Ignore heartbeats.

    {
      Call call;
      call.set_type(Call::SUBSCRIBE);
      Call::Subscribe* subscribe = call.mutable_subscribe();
      subscribe->mutable_framework_info()->CopyFrom(frameworkInfo);

      schedulerLibrary.send(call);
    }

    AWAIT_READY(subscribed);

    frameworkId = subscribed->framework_id();
  }

  // Wait until master schedules the framework for removal.
  AWAIT_READY(deactivateFramework);

  // Simulate framework failover timeout.
  Clock::pause();
  Clock::settle();

  Try<Duration> failoverTimeout =
    Duration::create(frameworkInfo.failover_timeout());

  ASSERT_SOME(failoverTimeout);

  Future<Nothing> frameworkFailoverTimeout =
    FUTURE_DISPATCH(_, &Master::frameworkFailoverTimeout);

  Clock::advance(failoverTimeout.get());
  Clock::resume();

  // Wait until master actually marks the framework as completed.
  AWAIT_READY(frameworkFailoverTimeout);

  // Now launch the second (i.e., failover) scheduler using the
  // framework id recorded from the first scheduler.
  {
    auto scheduler = std::make_shared<v1::MockHTTPScheduler>();

    Future<Nothing> connected;
    EXPECT_CALL(*scheduler, connected(_))
      .WillOnce(FutureSatisfy(&connected))
      .WillRepeatedly(Return()); // Ignore future invocations.

    v1::scheduler::TestMesos schedulerLibrary(
        master.get()->pid,
        contentType,
        scheduler);

    AWAIT_READY(connected);

    // Framework should get `Error` event because the framework with this id
    // is marked as completed.
    Future<Nothing> error;
    EXPECT_CALL(*scheduler, error(_, _))
      .WillOnce(FutureSatisfy(&error));

    EXPECT_CALL(*scheduler, disconnected(_))
      .Times(AtMost(1));

    {
      Call call;
      call.mutable_framework_id()->CopyFrom(frameworkId);
      call.set_type(Call::SUBSCRIBE);

      Call::Subscribe* subscribe = call.mutable_subscribe();
      subscribe->mutable_framework_info()->CopyFrom(v1::DEFAULT_FRAMEWORK_INFO);
      subscribe->mutable_framework_info()->mutable_id()->CopyFrom(frameworkId);

      schedulerLibrary.send(call);
    }

    AWAIT_READY(error);
  }
}
// This test verifies if we are able to upgrade from a PID based
// scheduler to HTTP scheduler.
TEST_P(SchedulerHttpApiTest, UpdatePidToHttpScheduler)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  v1::FrameworkInfo frameworkInfo = v1::DEFAULT_FRAMEWORK_INFO;
  frameworkInfo.set_failover_timeout(Weeks(2).secs());

  MockScheduler sched;
  StandaloneMasterDetector detector(master.get()->pid);
  TestingMesosSchedulerDriver driver(&sched, &detector, devolve(frameworkInfo));

  Future<FrameworkID> frameworkId;
  EXPECT_CALL(sched, registered(&driver, _, _))
    .WillOnce(FutureArg<1>(&frameworkId));

  // Check that driver is notified with an error when the http
  // framework is connected.
  Future<FrameworkErrorMessage> errorMessage =
    FUTURE_PROTOBUF(FrameworkErrorMessage(), _, _);

  EXPECT_CALL(sched, error(_, _));

  driver.start();

  AWAIT_READY(frameworkId);
  EXPECT_NE("", frameworkId.get().value());

  // Now try to subscribe as an HTTP framework.
  Call call;
  call.set_type(Call::SUBSCRIBE);
  call.mutable_framework_id()->CopyFrom(evolve(frameworkId.get()));

  Call::Subscribe* subscribe = call.mutable_subscribe();

  subscribe->mutable_framework_info()->CopyFrom(frameworkInfo);
  subscribe->mutable_framework_info()->mutable_id()->
    CopyFrom(evolve(frameworkId.get()));

  // Retrieve the parameter passed as content type to this test.
  const string contentType = GetParam();

  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
  headers["Accept"] = contentType;

  Future<Response> response = process::http::streaming::post(
      master.get()->pid,
      "api/v1/scheduler",
      headers,
      serialize(call, contentType),
      contentType);

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
  AWAIT_EXPECT_RESPONSE_HEADER_EQ("chunked", "Transfer-Encoding", response);
  ASSERT_EQ(Response::PIPE, response.get().type);

  Option<Pipe::Reader> reader = response.get().reader;
  ASSERT_SOME(reader);

  auto deserializer = lambda::bind(
      &SchedulerHttpApiTest::deserialize, this, contentType, lambda::_1);

  Reader<Event> responseDecoder(Decoder<Event>(deserializer), reader.get());

  Future<Result<Event>> event = responseDecoder.read();
  AWAIT_READY(event);
  ASSERT_SOME(event.get());

  // Check event type is subscribed and the framework id is set.
  ASSERT_EQ(Event::SUBSCRIBED, event.get().get().type());
  EXPECT_EQ(evolve(frameworkId.get()),
            event.get().get().subscribed().framework_id());

  // Make sure it receives a heartbeat.
  event = responseDecoder.read();
  AWAIT_READY(event);
  ASSERT_SOME(event.get());

  ASSERT_EQ(Event::HEARTBEAT, event.get().get().type());

  driver.stop();
  driver.join();
}
Esempio n. 9
0
namespace master {

// TODO(benh): Add units after constants.
// TODO(benh): Also make configuration options be constants.

// TODO(vinod): Move constants that are only used in flags to
// 'master/flags.hpp'.

// TODO(jieyu): Use static functions for all the constants. See more
// details in MESOS-1023.

// Maximum number of slot offers to have outstanding for each framework.
constexpr int MAX_OFFERS_PER_FRAMEWORK = 50;

// Minimum number of cpus per offer.
constexpr double MIN_CPUS = 0.01;

// Minimum amount of memory per offer.
constexpr Bytes MIN_MEM = Megabytes(32);

// Default interval the master uses to send heartbeats to an HTTP
// scheduler.
constexpr Duration DEFAULT_HEARTBEAT_INTERVAL = Seconds(15);

// Amount of time within which a slave PING should be received.
// NOTE: The slave uses these PING constants to determine when
// the master has stopped sending pings. If these are made
// configurable, then we'll need to rely on upper/lower bounds
// to ensure that the slave is not unnecessarily triggering
// re-registrations.
constexpr Duration DEFAULT_AGENT_PING_TIMEOUT = Seconds(15);

// Maximum number of ping timeouts until slave is considered failed.
constexpr size_t DEFAULT_MAX_AGENT_PING_TIMEOUTS = 5;

// The minimum timeout that can be used by a newly elected leader to
// allow re-registration of slaves. Any slaves that do not re-register
// within this timeout will be marked unreachable; if/when the agent
// re-registers, non-partition-aware tasks running on the agent will
// be terminated.
constexpr Duration MIN_AGENT_REREGISTER_TIMEOUT = Minutes(10);

// Default limit on the percentage of slaves that will be removed
// after recovering if no re-registration attempts were made.
// TODO(bmahler): There's no value here that works for all setups.
// Currently the default is 100% which is favorable to those running
// small clusters or experimenting with Mesos. However, it's important
// that we also prevent the catastrophic 100% removal case for
// production clusters. This TODO is to provide a --production flag
// which would allow flag defaults that are more appropriate for
// production use-cases.
constexpr double RECOVERY_AGENT_REMOVAL_PERCENT_LIMIT = 1.0; // 100%.

// Maximum number of removed slaves to store in the cache.
constexpr size_t MAX_REMOVED_SLAVES = 100000;

// Default maximum number of completed frameworks to store in the cache.
constexpr size_t DEFAULT_MAX_COMPLETED_FRAMEWORKS = 50;

// Default maximum number of completed tasks per framework
// to store in the cache.
constexpr size_t DEFAULT_MAX_COMPLETED_TASKS_PER_FRAMEWORK = 1000;

// Default maximum number of unreachable tasks per framework
// to store in the cache.
constexpr size_t DEFAULT_MAX_UNREACHABLE_TASKS_PER_FRAMEWORK = 1000;

// Time interval to check for updated watchers list.
constexpr Duration WHITELIST_WATCH_INTERVAL = Seconds(5);

// Default number of tasks (limit) for /master/tasks endpoint.
constexpr size_t TASK_LIMIT = 100;

constexpr Duration DEFAULT_REGISTRY_GC_INTERVAL = Minutes(15);

constexpr Duration DEFAULT_REGISTRY_MAX_AGENT_AGE = Weeks(2);

constexpr size_t DEFAULT_REGISTRY_MAX_AGENT_COUNT = 100 * 1024;

/**
 * Label used by the Leader Contender and Detector.
 *
 * \deprecated Will be deprecated as of Mesos 0.24: see MESOS-2340.
 */
constexpr char MASTER_INFO_LABEL[] = "info";

/**
 * Label used by the Leader Contender and Detector, for JSON content.
 *
 * \since Mesos 0.23 (see MESOS-2340).
 */
constexpr char MASTER_INFO_JSON_LABEL[] = "json.info";

// Timeout used for ZooKeeper related operations.
// TODO(vinod): Master detector/contender should use this timeout.
constexpr Duration ZOOKEEPER_SESSION_TIMEOUT = Seconds(10);

// Name of the default, CRAM-MD5 authenticator.
constexpr char DEFAULT_AUTHENTICATOR[] = "crammd5";

// Name of the default, HierarchicalDRF authenticator.
constexpr char DEFAULT_ALLOCATOR[] = "HierarchicalDRF";

// The default interval between allocations.
constexpr Duration DEFAULT_ALLOCATION_INTERVAL = Seconds(1);

// Name of the default, local authorizer.
constexpr char DEFAULT_AUTHORIZER[] = "local";

// Name of the master HTTP authentication realm for read-only endpoints.
constexpr char READONLY_HTTP_AUTHENTICATION_REALM[] =
  "mesos-master-readonly";

// Name of the master HTTP authentication realm for read-write endpoints.
constexpr char READWRITE_HTTP_AUTHENTICATION_REALM[] =
  "mesos-master-readwrite";

// Name of the default authentication realm for HTTP frameworks.
constexpr char DEFAULT_HTTP_FRAMEWORK_AUTHENTICATION_REALM[] =
  "mesos-master-scheduler";

// Agents older than this version are not allowed to register.
const Version MINIMUM_AGENT_VERSION = Version(1, 0, 0);

std::vector<MasterInfo::Capability> MASTER_CAPABILITIES();

} // namespace master {
Esempio n. 10
0
namespace slave {

// TODO(jieyu): Use static functions for all the constants. See more
// details in MESOS-1023.

constexpr Duration EXECUTOR_REGISTRATION_TIMEOUT = Minutes(1);
constexpr Duration EXECUTOR_REREGISTRATION_TIMEOUT = Seconds(2);

// The maximum timeout within which an executor can re-register.
// Note that this value has to be << 'MIN_AGENT_REREGISTER_TIMEOUT'
// declared in 'master/constants.hpp'; since agent recovery will only
// complete after this timeout has elapsed, this ensures that the
// agent can re-register with the master before it is marked
// unreachable and its tasks are transitioned to TASK_UNREACHABLE or
// TASK_LOST.
constexpr Duration MAX_EXECUTOR_REREGISTRATION_TIMEOUT = Seconds(15);

// The default amount of time to wait for the executor to
// shut down before destroying the container.
constexpr Duration DEFAULT_EXECUTOR_SHUTDOWN_GRACE_PERIOD = Seconds(5);

constexpr Duration RECOVERY_TIMEOUT = Minutes(15);

// TODO(gkleiman): Move this to a different file once `TaskStatusUpdateManager`
// uses `StatusUpdateManagerProcess`. See MESOS-8296.
constexpr Duration STATUS_UPDATE_RETRY_INTERVAL_MIN = Seconds(10);
constexpr Duration STATUS_UPDATE_RETRY_INTERVAL_MAX = Minutes(10);

// Default backoff interval used by the slave to wait before registration.
constexpr Duration DEFAULT_REGISTRATION_BACKOFF_FACTOR = Seconds(1);

// The maximum interval the slave waits before retrying registration.
// Note that this value has to be << 'MIN_SLAVE_REREGISTER_TIMEOUT'
// declared in 'master/constants.hpp'. This helps the slave to retry
// (re-)registration multiple times between when the master finishes
// recovery and when it times out slave re-registration.
constexpr Duration REGISTER_RETRY_INTERVAL_MAX = Minutes(1);

// The maximum interval the slave waits before retrying authentication.
constexpr Duration AUTHENTICATION_RETRY_INTERVAL_MAX = Minutes(1);

// Default backoff interval used by the slave to wait after failed
// authentication.
constexpr Duration DEFAULT_AUTHENTICATION_BACKOFF_FACTOR = Seconds(1);

constexpr Duration GC_DELAY = Weeks(1);
constexpr Duration DISK_WATCH_INTERVAL = Minutes(1);

// Minimum free disk capacity enforced by the garbage collector.
constexpr double GC_DISK_HEADROOM = 0.1;

// Maximum number of completed frameworks to store in memory.
constexpr size_t MAX_COMPLETED_FRAMEWORKS = 50;

// Default maximum number of completed executors per framework
// to store in memory.
constexpr size_t DEFAULT_MAX_COMPLETED_EXECUTORS_PER_FRAMEWORK = 150;

// Maximum number of completed tasks per executor to store in memory.
//
// NOTE: This should be greater than zero because the agent looks
// for completed tasks to determine (with false positives) whether
// an executor ever received tasks. See MESOS-8411.
//
// TODO(mzhu): Remove this note once we can determine whether an
// executor ever received tasks without looking through the
// completed tasks.
constexpr size_t MAX_COMPLETED_TASKS_PER_EXECUTOR = 200;

// Default cpus offered by the slave.
constexpr double DEFAULT_CPUS = 1;

// Default memory offered by the slave.
constexpr Bytes DEFAULT_MEM = Gigabytes(1);

// Default disk space offered by the slave.
constexpr Bytes DEFAULT_DISK = Gigabytes(10);

// Default ports range offered by the slave.
constexpr char DEFAULT_PORTS[] = "[31000-32000]";

// Default cpu resource given to a command executor.
constexpr double DEFAULT_EXECUTOR_CPUS = 0.1;

// Default memory resource given to a command executor.
constexpr Bytes DEFAULT_EXECUTOR_MEM = Megabytes(32);

#ifdef ENABLE_PORT_MAPPING_ISOLATOR
// Default number of ephemeral ports allocated to a container by the
// network isolator.
constexpr uint16_t DEFAULT_EPHEMERAL_PORTS_PER_CONTAINER = 1024;
#endif

// Default UNIX socket (Linux) or Named Pipe (Windows) resource that provides
// CLI access to the Docker daemon.
#ifdef __WINDOWS__
constexpr char DEFAULT_DOCKER_HOST_RESOURCE[] = "//./pipe/docker_engine";
#else
constexpr char DEFAULT_DOCKER_HOST_RESOURCE[] = "/var/run/docker.sock";
#endif // __WINDOWS__

// Default duration that docker containers will be removed after exit.
constexpr Duration DOCKER_REMOVE_DELAY = Hours(6);

// Default duration to wait before retry inspecting a docker
// container.
constexpr Duration DOCKER_INSPECT_DELAY = Seconds(1);

// Default maximum number of docker inspect calls docker ps will invoke
// in parallel to prevent hitting system's open file descriptor limit.
constexpr size_t DOCKER_PS_MAX_INSPECT_CALLS = 100;

// Default duration that docker containerizer will wait to check
// docker version.
// TODO(tnachen): Make this a flag.
constexpr Duration DOCKER_VERSION_WAIT_TIMEOUT = Seconds(5);

// Additional duration that docker containerizer will wait beyond the
// configured `docker_stop_timeout` for docker stop to succeed, before
// trying to kill the process by itself.
constexpr Duration DOCKER_FORCE_KILL_TIMEOUT = Seconds(1);

// Name of the default, CRAM-MD5 authenticatee.
constexpr char DEFAULT_AUTHENTICATEE[] = "crammd5";

// Name of the default, local authorizer.
constexpr char DEFAULT_AUTHORIZER[] = "local";

// Name of the agent HTTP authentication realm for read-only endpoints.
constexpr char READONLY_HTTP_AUTHENTICATION_REALM[] = "mesos-agent-readonly";

// Name of the agent HTTP authentication realm for read-write endpoints.
constexpr char READWRITE_HTTP_AUTHENTICATION_REALM[] = "mesos-agent-readwrite";

// Name of the agent HTTP authentication realm for HTTP executors.
constexpr char EXECUTOR_HTTP_AUTHENTICATION_REALM[] = "mesos-agent-executor";

// Default maximum storage space to be used by the fetcher cache.
constexpr Bytes DEFAULT_FETCHER_CACHE_SIZE = Gigabytes(2);

// If no pings received within this timeout, then the slave will
// trigger a re-detection of the master to cause a re-registration.
Duration DEFAULT_MASTER_PING_TIMEOUT();

// Name of the executable for default executor.
#ifdef __WINDOWS__
constexpr char MESOS_DEFAULT_EXECUTOR[] = "mesos-default-executor.exe";
#else
constexpr char MESOS_DEFAULT_EXECUTOR[] = "mesos-default-executor";
#endif // __WINDOWS__

// Virtual path on which agent logs are mounted in `/files/` endpoint.
constexpr char AGENT_LOG_VIRTUAL_PATH[] = "/slave/log";

std::vector<SlaveInfo::Capability> AGENT_CAPABILITIES();

} // namespace slave {