//
// 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.

syntax = "proto2";

package mesos.master;

import "github.com/mesos/mesos-go/api/v1/lib/mesos.proto";
import "github.com/mesos/mesos-go/api/v1/lib/allocator/allocator.proto";
import "github.com/mesos/mesos-go/api/v1/lib/maintenance/maintenance.proto";
import "github.com/mesos/mesos-go/api/v1/lib/quota/quota.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";

option go_package = "master";
option (gogoproto.benchgen_all) = true;
option (gogoproto.enum_stringer_all) = true;
option (gogoproto.equal_all) = true;
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_enum_stringer_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.goproto_unrecognized_all) = false;
option (gogoproto.gostring_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.populate_all) = true;
option (gogoproto.protosizer_all) = true;
option (gogoproto.stringer_all) =  true;
option (gogoproto.testgen_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.verbose_equal_all) = true;

/**
 * Calls that can be sent to the v1 master API.
 *
 * A call is described using the standard protocol buffer "union"
 * trick, see
 * https://developers.google.com/protocol-buffers/docs/techniques#union.
 */
message Call {
  enum Type {
   // If a call of type `Call::FOO` requires additional parameters they can be
   // included in the corresponding `Call::Foo` message. Similarly, if a call
   // receives a synchronous response it will be returned as a `Response`
   // message of type `Response::FOO`. Currently all calls except
   // `Call::SUBSCRIBE` receive synchronous responses; `Call::SUBSCRIBE` returns
   // a streaming response of `Event`.
    UNKNOWN = 0;

    GET_HEALTH = 1;         // Retrieves the master's health status.
    GET_FLAGS = 2;          // Retrieves the master's flag configuration.
    GET_VERSION = 3;        // Retrieves the master's version information.
    GET_METRICS = 4;        // See 'GetMetrics' below.

    GET_LOGGING_LEVEL = 5;  // Retrieves the master's logging level.
    SET_LOGGING_LEVEL = 6;  // See 'SetLoggingLevel' below.

    LIST_FILES = 7;
    READ_FILE = 8;          // See 'ReadFile' below.

    GET_STATE = 9;

    GET_AGENTS = 10;
    GET_FRAMEWORKS = 11;
    GET_EXECUTORS = 12;     // Retrieves the information about all executors.
    GET_TASKS = 13;         // Retrieves the information about all known tasks.
    GET_ROLES = 14;         // Retrieves the information about roles.

    GET_WEIGHTS = 15;       // Retrieves the information about role weights.
    UPDATE_WEIGHTS = 16;

    GET_MASTER = 17;        // Retrieves the master's information.

    SUBSCRIBE = 18;         // Subscribes the master to receive events.

    RESERVE_RESOURCES = 19;
    UNRESERVE_RESOURCES = 20;

    CREATE_VOLUMES = 21;     // See 'CreateVolumes' below.
    DESTROY_VOLUMES = 22;    // See 'DestroyVolumes' below.

    // Retrieves the cluster's maintenance status.
    GET_MAINTENANCE_STATUS = 23;
    // Retrieves the cluster's maintenance schedule.
    GET_MAINTENANCE_SCHEDULE = 24;
    UPDATE_MAINTENANCE_SCHEDULE = 25; // See 'UpdateMaintenanceSchedule' below.
    START_MAINTENANCE = 26;           // See 'StartMaintenance' below.
    STOP_MAINTENANCE = 27;            // See 'StopMaintenance' below.

    GET_QUOTA = 28;
    SET_QUOTA = 29;          // See 'SetQuota' below.
    REMOVE_QUOTA = 30;       // See 'RemoveQuota' below.

    option (gogoproto.goproto_enum_prefix) = true;
  }

  // Provides a snapshot of the current metrics tracked by the master.
  message GetMetrics {
    // If set, `timeout` would be used to determines the maximum amount of time
    // the API will take to respond. If the timeout is exceeded, some metrics
    // may not be included in the response.
    optional DurationInfo timeout = 1;
  }

  // Sets the logging verbosity level for a specified duration. Mesos uses
  // [glog](https://github.com/google/glog) for logging. The library only uses
  // verbose logging which means nothing will be output unless the verbosity
  // level is set (by default it's 0, libprocess uses levels 1, 2, and 3).
  message SetLoggingLevel {
    // The verbosity level.
    required uint32 level = 1 [(gogoproto.nullable) = false];
    // The duration to keep verbosity level toggled. After this duration, the
    // verbosity level of log would revert to the original level.
    required DurationInfo duration = 2 [(gogoproto.nullable) = false];
  }

  // Provides the file listing for a directory.
  message ListFiles {
    required string path = 1 [(gogoproto.nullable) = false];
  }

  // Reads data from a file.
  message ReadFile {
    // The path of file.
    required string path = 1 [(gogoproto.nullable) = false];

    // Initial offset in file to start reading from.
    required uint64 offset = 2 [(gogoproto.nullable) = false];

    // The maximum number of bytes to read. The read length is capped at 16
    // memory pages.
    optional uint64 length = 3;
  }

  message UpdateWeights {
    repeated WeightInfo weight_infos = 1 [(gogoproto.nullable) = false];
  }

  // Reserve resources dynamically on a specific agent.
  message ReserveResources {
    required AgentID agent_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "AgentID"];
    repeated Resource resources = 2 [(gogoproto.nullable) = false];
  }

  // Unreserve resources dynamically on a specific agent.
  message UnreserveResources {
    required AgentID agent_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "AgentID"];
    repeated Resource resources = 2 [(gogoproto.nullable) = false];
  }

  // Create persistent volumes on reserved resources. The request is forwarded
  // asynchronously to the Mesos agent where the reserved resources are located.
  // That asynchronous message may not be delivered or creating the volumes at
  // the agent might fail. Volume creation can be verified by sending a
  // `GET_VOLUMES` call.
  message CreateVolumes {
    required AgentID agent_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "AgentID"];
    repeated Resource volumes = 2 [(gogoproto.nullable) = false];
  }

  // Destroy persistent volumes. The request is forwarded asynchronously to the
  // Mesos agent where the reserved resources are located. That asynchronous
  // message may not be delivered or destroying the volumes at the agent might
  // fail. Volume deletion can be verified by sending a `GET_VOLUMES` call.
  message DestroyVolumes {
    required AgentID agent_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "AgentID"];
    repeated Resource volumes = 2 [(gogoproto.nullable) = false];
  }

  // Updates the cluster's maintenance schedule.
  message UpdateMaintenanceSchedule {
    required maintenance.Schedule schedule = 1 [(gogoproto.nullable) = false];
  }

  // Starts the maintenance of the cluster, this would bring a set of machines
  // down.
  message StartMaintenance {
    repeated MachineID machines = 1 [(gogoproto.nullable) = false];
  }

  // Stops the maintenance of the cluster, this would bring a set of machines
  // back up.
  message StopMaintenance {
    repeated MachineID machines = 1 [(gogoproto.nullable) = false];
  }

  // Sets the quota for resources to be used by a particular role.
  message SetQuota {
    required quota.QuotaRequest quota_request = 1 [(gogoproto.nullable) = false];
  }

  message RemoveQuota {
    required string role = 1 [(gogoproto.nullable) = false];
  }

  optional Type type = 1 [(gogoproto.nullable) = false];

  optional GetMetrics get_metrics = 2;
  optional SetLoggingLevel set_logging_level = 3;
  optional ListFiles list_files = 4;
  optional ReadFile read_file = 5;
  optional UpdateWeights update_weights = 6;
  optional ReserveResources reserve_resources = 7;
  optional UnreserveResources unreserve_resources = 8;
  optional CreateVolumes create_volumes = 9;
  optional DestroyVolumes destroy_volumes = 10;
  optional UpdateMaintenanceSchedule update_maintenance_schedule = 11;
  optional StartMaintenance start_maintenance = 12;
  optional StopMaintenance stop_maintenance = 13;
  optional SetQuota set_quota = 14;
  optional RemoveQuota remove_quota = 15;
}


/**
 * Synchronous responses for all calls (except Call::SUBSCRIBE) made to
 * the v1 master API.
 */
message Response {
  // Each of the responses of type `FOO` corresponds to `Foo` message below.
  enum Type {
    UNKNOWN = 0;

    GET_HEALTH = 1;                // See 'GetHealth' below.
    GET_FLAGS = 2;                 // See 'GetFlags' below.
    GET_VERSION = 3;               // See 'GetVersion' below.
    GET_METRICS = 4;               // See 'GetMetrics' below.

    GET_LOGGING_LEVEL = 5;         // See 'GetLoggingLevel' below.

    LIST_FILES = 6;
    READ_FILE = 7;                 // See 'ReadFile' below.

    GET_STATE = 8;

    GET_AGENTS = 9;
    GET_FRAMEWORKS = 10;
    GET_EXECUTORS = 11;            // See 'GetExecutors' below.
    GET_TASKS = 12;                // See 'GetTasks' below.
    GET_ROLES = 13;                // See 'GetRoles' below.

    GET_WEIGHTS = 14;              // See 'GetWeights' below.

    GET_MASTER = 15;               // See 'GetMaster' below.

    GET_MAINTENANCE_STATUS = 16;   // See 'GetMaintenanceStatus' below.
    GET_MAINTENANCE_SCHEDULE = 17; // See 'GetMaintenanceSchedule' below.

    GET_QUOTA = 18;

    option (gogoproto.goproto_enum_prefix) = true;
  }

  // `healthy` would be true if the master is healthy. Delayed responses are
  // also indicative of the poor health of the master.
  message GetHealth {
    required bool healthy = 1 [(gogoproto.nullable) = false];
  }

  // Contains the flag configuration of the master.
  message GetFlags {
    repeated Flag flags = 1 [(gogoproto.nullable) = false];
  }

  // Contains the version information of the master.
  message GetVersion {
    required VersionInfo version_info = 1 [(gogoproto.nullable) = false];
  }

  // Contains a snapshot of the current metrics.
  message GetMetrics {
    repeated Metric metrics = 1 [(gogoproto.nullable) = false];
  }

  // Contains the logging level of the master.
  message GetLoggingLevel {
    required uint32 level = 1 [(gogoproto.nullable) = false];
  }

  // Contains the file listing(similar to `ls -l`) for a directory.
  message ListFiles {
    repeated FileInfo file_infos = 1 [(gogoproto.nullable) = false];
  }

  // Contains the file data.
  message ReadFile {
    // The size of file (in bytes).
    required uint64 size = 1 [(gogoproto.nullable) = false];

    required bytes data = 2;
  }

  // Contains full state of the master i.e. information about the tasks,
  // agents, frameworks and executors running in the cluster.
  message GetState {
    optional GetTasks get_tasks = 1;
    optional GetExecutors get_executors = 2;
    optional GetFrameworks get_frameworks = 3;
    optional GetAgents get_agents = 4;
  }

  message GetAgents {
    message Agent {
      required AgentInfo agent_info = 1 [(gogoproto.nullable) = false];
      required bool active = 2 [(gogoproto.nullable) = false];
      required string version = 3 [(gogoproto.nullable) = false];

      optional string pid = 4 [(gogoproto.customname) = "PID"];
      optional TimeInfo registered_time = 5;
      optional TimeInfo reregistered_time = 6;

      // Total resources (including oversubscribed resources) the agent
      // provides.
      repeated Resource total_resources = 7 [(gogoproto.nullable) = false];

      repeated Resource allocated_resources = 8 [(gogoproto.nullable) = false];
      repeated Resource offered_resources = 9 [(gogoproto.nullable) = false];

      repeated AgentInfo.Capability capabilities = 10 [(gogoproto.nullable) = false];
    }

    // Registered agents.
    repeated Agent agents = 1 [(gogoproto.nullable) = false];

    // Agents which are recovered from registry but not reregistered yet.
    repeated AgentInfo recovered_agents = 2 [(gogoproto.nullable) = false];
  }

  // Information about all the frameworks known to the master at the current
  // time. Note that there might be frameworks unknown to the master running
  // on partitioned or unsubscribed agents.
  message GetFrameworks {
    message Framework {
      required FrameworkInfo framework_info = 1 [(gogoproto.nullable) = false];
      required bool active = 2 [(gogoproto.nullable) = false];
      required bool connected = 3 [(gogoproto.nullable) = false];

      // If true, this framework was previously subscribed but hasn't
      // yet re-subscribed after a master failover. Recovered frameworks
      // are only reported if one or more agents running a task or
      // executor for the framework have re-registered after master
      // failover.
      required bool recovered = 11 [(gogoproto.nullable) = false];

      optional TimeInfo registered_time = 4;
      optional TimeInfo reregistered_time = 5;
      optional TimeInfo unregistered_time = 6;

      repeated Offer offers = 7 [(gogoproto.nullable) = false];
      repeated InverseOffer inverse_offers = 8 [(gogoproto.nullable) = false];

      repeated Resource allocated_resources = 9 [(gogoproto.nullable) = false];
      repeated Resource offered_resources = 10 [(gogoproto.nullable) = false];
    }

    // Frameworks that have subscribed with the master. Note that this includes
    // frameworks that are disconnected and in the process of re-subscribing.
    repeated Framework frameworks = 1 [(gogoproto.nullable) = false];

    // Frameworks that have been teared down.
    repeated Framework completed_frameworks = 2 [(gogoproto.nullable) = false];

    // This field previously contained frameworks that previously
    // subscribed but haven't yet re-subscribed after a master failover.
    // As of Mesos 1.2, this field will always be empty; recovered
    // frameworks are now reported in the `frameworks` list with the
    // `recovered` field set to true.
    //
    // TODO(neilc): Remove this field in Mesos 2.0.
    repeated FrameworkInfo recovered_frameworks = 3 [(gogoproto.nullable) = false];
  }

  // Lists information about all the executors known to the master at the
  // current time. Note that there might be executors unknown to the master
  // running on partitioned or unsubscribed agents.
  message GetExecutors {
    message Executor {
      required ExecutorInfo executor_info = 1 [(gogoproto.nullable) = false];
      required AgentID agent_id = 2 [(gogoproto.nullable) = false, (gogoproto.customname) = "AgentID"];
    }

    repeated Executor executors = 1 [(gogoproto.nullable) = false];

    // As of Mesos 1.3.0, this field is deprecated and will always be empty.
    //
    // TODO(neilc): Remove this field in Mesos 2.0.
    repeated Executor orphan_executors = 2 [(gogoproto.nullable) = false];
  }

  // Lists information about all the tasks known to the master at the current
  // time. Note that there might be tasks unknown to the master running on
  // partitioned or unsubscribed agents.
  message GetTasks {
    // Tasks that are enqueued on the master waiting (e.g., authorizing)
    // to be launched.
    repeated Task pending_tasks = 1 [(gogoproto.nullable) = false];

    // Tasks that have been forwarded to the agent for launch. This
    // includes tasks that are staging or running; it also includes
    // tasks that have reached a terminal state but the terminal status
    // update has not yet been acknowledged by the scheduler.
    repeated Task tasks = 2 [(gogoproto.nullable) = false];

    // Tasks that were running on agents that have become partitioned
    // from the master. If/when the agent is no longer partitioned,
    // tasks running on that agent will no longer be unreachable (they
    // will either be running or completed). Note that the master only
    // stores a limited number of unreachable tasks; information about
    // unreachable tasks is also not preserved across master failover.
    repeated Task unreachable_tasks = 5 [(gogoproto.nullable) = false];

    // Tasks that have reached terminal state and have all their updates
    // acknowledged by the scheduler.
    repeated Task completed_tasks = 3 [(gogoproto.nullable) = false];

    // As of Mesos 1.3.0, this field is deprecated and will always be empty.
    //
    // TODO(neilc): Remove this field in Mesos 2.0.
    repeated Task orphan_tasks = 4 [(gogoproto.nullable) = false];
  }

  // Provides information about every role that is on the role whitelist (if
  // enabled), has one or more registered frameworks or has a non-default weight
  // or quota.
  message GetRoles {
    repeated Role roles = 1 [(gogoproto.nullable) = false];
  }

  // Provides the weight information about every role.
  message GetWeights {
    repeated WeightInfo weight_infos = 1 [(gogoproto.nullable) = false];
  }

  // Contains the master's information.
  message GetMaster {
    optional MasterInfo master_info = 1;
  }

  // Contains the cluster's maintenance status.
  message GetMaintenanceStatus {
    required maintenance.ClusterStatus status = 1 [(gogoproto.nullable) = false];
  }

  // Contains the cluster's maintenance schedule.
  message GetMaintenanceSchedule {
    required maintenance.Schedule schedule = 1 [(gogoproto.nullable) = false];
  }

  // Contains the cluster's configured quotas.
  message GetQuota {
    required quota.QuotaStatus status = 1 [(gogoproto.nullable) = false];
  }

  optional Type type = 1 [(gogoproto.nullable) = false];

  optional GetHealth get_health = 2;
  optional GetFlags get_flags = 3;
  optional GetVersion get_version = 4;
  optional GetMetrics get_metrics = 5;
  optional GetLoggingLevel get_logging_level = 6;
  optional ListFiles list_files = 7;
  optional ReadFile read_file = 8;
  optional GetState get_state = 9;
  optional GetAgents get_agents = 10;
  optional GetFrameworks get_frameworks = 11;
  optional GetExecutors get_executors = 12;
  optional GetTasks get_tasks = 13;
  optional GetRoles get_roles = 14;
  optional GetWeights get_weights = 15;
  optional GetMaster get_master = 16;
  optional GetMaintenanceStatus get_maintenance_status = 17;
  optional GetMaintenanceSchedule get_maintenance_schedule = 18;
  optional GetQuota get_quota = 19;
}


/**
 * Streaming response to `Call::SUBSCRIBE` made to the master.
 */
message Event {
  enum Type {
    UNKNOWN = 0;
    SUBSCRIBED = 1; // See `Subscribed` below.
    TASK_ADDED = 2; // See `TaskAdded` below.
    TASK_UPDATED = 3; // See `TaskUpdated` below.
    AGENT_ADDED = 4; // See `AgentAdded` below.
    AGENT_REMOVED = 5; // See `AgentRemoved` below.
    FRAMEWORK_ADDED = 6; // See `FrameworkAdded` below.
    FRAMEWORK_UPDATED = 7; // See `FrameworkUpdated` below.
    FRAMEWORK_REMOVED = 8; // See `FrameworkRemoved` below.

    // TODO(vinod): Fill in more events.

    option (gogoproto.goproto_enum_prefix) = true;
  }

  // First event received when a client subscribes.
  message Subscribed {
    // Snapshot of the entire cluster state. Further updates to the
    // cluster state are sent as separate events on the stream.
    optional Response.GetState get_state = 1;
  }

  // Forwarded by the master when a task becomes known to it. This can happen
  // when a new task is launched by the scheduler or when the task becomes
  // known to the master upon an agent (re-)registration after a failover.
  message TaskAdded {
    required Task task = 1 [(gogoproto.nullable) = false];
  }

  // Forwarded by the master when an existing task transitions to a new state.
  message TaskUpdated {
    required FrameworkID framework_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "FrameworkID"];

    // This is the status of the task corresponding to the last
    // status update acknowledged by the scheduler.
    required TaskStatus status = 2 [(gogoproto.nullable) = false];

    // This is the latest state of the task according to the agent.
    required TaskState state = 3;
  }


  // Forwarded by the master when a framework becomes known to it.
  // This can happen when a new framework registers with the master.
  message FrameworkAdded {
    required Response.GetFrameworks.Framework framework = 1 [(gogoproto.nullable) = false];
  }

  // Forwarded by the master when a framework re-registers with the master
  // upon a disconnection (network error) or upon a master failover.
  message FrameworkUpdated {
    required Response.GetFrameworks.Framework framework = 1 [(gogoproto.nullable) = false];
  }

  // Forwarded by the master when a framework is removed. This can happen when
  // a framework is explicitly teardown by the operator or if it fails to
  // re-register with the master within the failover timeout.
  message FrameworkRemoved {
    required FrameworkInfo framework_info = 1 [(gogoproto.nullable) = false];
  }

  // Forwarded by the master when an agent becomes known to it.
  // This can happen when an agent registered for the first
  // time, or reregistered after a master failover.
  message AgentAdded {
    required Response.GetAgents.Agent agent = 1 [(gogoproto.nullable) = false];
  }

  // Forwarded by the master when an agent is removed. This
  // can happen when the agent is scheduled for maintenance.
  //
  // NOTE: It's possible that an agent might become
  // active once it has been removed, i.e. if the master
  // has gc'ed its list of known "dead" agents.
  // See MESOS-5965 for context.
  message AgentRemoved {
    required AgentID agent_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "AgentID"];
  }

  optional Type type = 1 [(gogoproto.nullable) = false];

  optional Subscribed subscribed = 2;
  optional TaskAdded task_added = 3;
  optional TaskUpdated task_updated = 4;
  optional AgentAdded agent_added = 5;
  optional AgentRemoved agent_removed = 6;
  optional FrameworkAdded framework_added = 7;
  optional FrameworkUpdated framework_updated = 8;
  optional FrameworkRemoved framework_removed = 9;
}
