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

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

option go_package = "executor";
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;

/**
 * Executor event API.
 *
 * An event is described using the standard protocol buffer "union"
 * trick, see https://developers.google.com/protocol-buffers/docs/techniques#union.
 */
message Event {
  // Possible event types, followed by message definitions if
  // applicable.
  enum Type {
    // This must be the first enum value in this list, to
    // ensure that if 'type' is not set, the default value
    // is UNKNOWN. This enables enum values to be added
    // in a backwards-compatible way. See: MESOS-4997.
    UNKNOWN = 0;

    SUBSCRIBED = 1;   // See 'Subscribed' below.
    LAUNCH = 2;       // See 'Launch' below.
    LAUNCH_GROUP = 8; // See 'LaunchGroup' below.
    KILL = 3;         // See 'Kill' below.
    ACKNOWLEDGED = 4; // See 'Acknowledged' below.
    MESSAGE = 5;      // See 'Message' below.
    ERROR = 6;        // See 'Error' below.

    // Received when the agent asks the executor to shutdown/kill itself.
    // The executor is then required to kill all its active tasks, send
    // `TASK_KILLED` status updates and gracefully exit. The executor
    // should terminate within a `MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD`
    // (an environment variable set by the agent upon executor startup);
    // it can be configured via `ExecutorInfo.shutdown_grace_period`. If
    // the executor fails to do so, the agent will forcefully destroy the
    // container where the executor is running. The agent would then send
    // `TASK_LOST` updates for any remaining active tasks of this executor.
    //
    // NOTE: The executor must not assume that it will always be allotted
    // the full grace period, as the agent may decide to allot a shorter
    // period and failures / forcible terminations may occur.
    //
    // TODO(alexr): Consider adding a duration field into the `Shutdown`
    // message so that the agent can communicate when a shorter period
    // has been allotted.
    SHUTDOWN = 7;

    option (gogoproto.goproto_enum_prefix) = true;
  }

  // First event received when the executor subscribes.
  // The 'id' field in the 'framework_info' will be set.
   message Subscribed {
    required ExecutorInfo executor_info = 1 [(gogoproto.nullable) = false];
    required FrameworkInfo framework_info = 2 [(gogoproto.nullable) = false];
    required AgentInfo agent_info = 3 [(gogoproto.nullable) = false];

    // Uniquely identifies the container of an executor run.
    optional ContainerID container_id = 4 [(gogoproto.customname) = "ContainerID"];
  }

  // Received when the framework attempts to launch a task. Once
  // the task is successfully launched, the executor must respond with
  // a TASK_RUNNING update (See TaskState in v1/mesos.proto).
  message Launch {
    required TaskInfo task = 1 [(gogoproto.nullable) = false];
  }

  // Received when the framework attempts to launch a group of tasks atomically.
  // Similar to `Launch` above the executor must send TASK_RUNNING updates for
  // tasks that are successfully launched.
  message LaunchGroup {
    required TaskGroupInfo task_group = 1 [(gogoproto.nullable) = false];
  }

  // Received when the scheduler wants to kill a specific task. Once
  // the task is terminated, the executor should send a TASK_KILLED
  // (or TASK_FAILED) update. The terminal update is necessary so
  // Mesos can release the resources associated with the task.
  message Kill {
    required TaskID task_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "TaskID"];

    // If set, overrides any previously specified kill policy for this task.
    // This includes 'TaskInfo.kill_policy' and 'Executor.kill.kill_policy'.
    // Can be used to forcefully kill a task which is already being killed.
    optional KillPolicy kill_policy = 2;
  }

  // Received when the agent acknowledges the receipt of status
  // update. Schedulers are responsible for explicitly acknowledging
  // the receipt of status updates that have 'update.status().uuid()'
  // field set. Unacknowledged updates can be retried by the executor.
  // They should also be sent by the executor whenever it
  // re-subscribes.
  message Acknowledged {
    required TaskID task_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "TaskID"];
    required bytes uuid = 2 [(gogoproto.customname) = "UUID"];
  }

  // Received when a custom message generated by the scheduler is
  // forwarded by the agent. Note that this message is not
  // interpreted by Mesos and is only forwarded (without reliability
  // guarantees) to the executor. It is up to the scheduler to retry
  // if the message is dropped for any reason.
  message Message {
    required bytes data = 1;
  }

  // Received in case the executor sends invalid calls (e.g.,
  // required values not set).
  // TODO(arojas): Remove this once the old executor driver is no
  // longer supported. With HTTP API all errors will be signaled via
  // HTTP response codes.
  message Error {
    required string message = 1 [(gogoproto.nullable) = false];
  }

  // Type of the event, indicates which optional field below should be
  // present if that type has a nested message definition.
  // Enum fields should be optional, see: MESOS-4997.
  optional Type type = 1 [(gogoproto.nullable) = false];

  optional Subscribed subscribed = 2;
  optional Acknowledged acknowledged = 3;
  optional Launch launch = 4;
  optional LaunchGroup launch_group = 8;
  optional Kill kill = 5;
  optional Message message = 6;
  optional Error error = 7;
}


/**
 * Executor call API.
 *
 * Like Event, a Call is described using the standard protocol buffer
 * "union" trick (see above).
 */
message Call {
  // Possible call types, followed by message definitions if
  // applicable.
  enum Type {
    // See comments above on `Event::Type` for more details on this enum value.
    UNKNOWN = 0;

    SUBSCRIBE = 1;    // See 'Subscribe' below.
    UPDATE = 2;       // See 'Update' below.
    MESSAGE = 3;      // See 'Message' below.

    option (gogoproto.goproto_enum_prefix) = true;
  }

  // Request to subscribe with the agent. If subscribing after a disconnection,
  // it must include a list of all the tasks and updates which haven't been
  // acknowledged by the scheduler.
  message Subscribe {
    repeated TaskInfo unacknowledged_tasks = 1 [(gogoproto.nullable) = false];
    repeated Update unacknowledged_updates = 2 [(gogoproto.nullable) = false];
  }

  // Notifies the scheduler that a task has transitioned from one
  // state to another. Status updates should be used by executors
  // to reliably communicate the status of the tasks that they
  // manage. It is crucial that a terminal update (see TaskState
  // in v1/mesos.proto) is sent to the scheduler as soon as the task
  // terminates, in order for Mesos to release the resources allocated
  // to the task. It is the responsibility of the scheduler to
  // explicitly acknowledge the receipt of a status update. See
  // 'Acknowledged' in the 'Events' section above for the semantics.
  message Update {
    required TaskStatus status = 1 [(gogoproto.nullable) = false];
  }

  // Sends arbitrary binary data to the scheduler. Note that Mesos
  // neither interprets this data nor makes any guarantees about the
  // delivery of this message to the scheduler.
  // See 'Message' in the 'Events' section.
  message Message {
    required bytes data = 2;
  }

  // Identifies the executor which generated this call.
  required ExecutorID executor_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ExecutorID"];
  required FrameworkID framework_id = 2 [(gogoproto.nullable) = false, (gogoproto.customname) = "FrameworkID"];

  // Type of the call, indicates which optional field below should be
  // present if that type has a nested message definition.
  // In case type is SUBSCRIBED, no message needs to be set.
  // See comments on `Event::Type` above on the reasoning behind this
  // field being optional.
  optional Type type = 3 [(gogoproto.nullable) = false];

  optional Subscribe subscribe = 4;
  optional Update update = 5;
  optional Message message = 6;
}
