api/dispatcher.proto
syntax = "proto3";
package docker.swarmkit.v1;
import "github.com/docker/swarmkit/api/types.proto";
import "github.com/docker/swarmkit/api/objects.proto";
import "gogoproto/gogo.proto";
import "github.com/docker/swarmkit/protobuf/plugin/plugin.proto";
import "google/protobuf/duration.proto";
// Dispatcher is the API provided by a manager group for agents to connect to. Agents
// connect to this service to receive task assignments and report status.
//
// API methods on this service are used only by agent nodes.
service Dispatcher { // maybe dispatch, al likes this
// Session starts an agent session with the dispatcher. The session is
// started after the first SessionMessage is received.
//
// Once started, the agent is controlled with a stream of SessionMessage.
// Agents should list on the stream at all times for instructions.
rpc Session(SessionRequest) returns (stream SessionMessage) {
option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
};
// Heartbeat is heartbeat method for nodes. It returns new TTL in response.
// Node should send new heartbeat earlier than now + TTL, otherwise it will
// be deregistered from dispatcher and its status will be updated to NodeStatus_DOWN
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {
option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
};
// UpdateTaskStatus updates status of task. Node should send such updates
// on every status change of its tasks.
//
// Whether receiving batch updates or single status updates, this method
// should be accepting. Errors should only be returned if the entire update
// should be retried, due to data loss or other problems.
//
// If a task is unknown the dispatcher, the status update should be
// accepted regardless.
rpc UpdateTaskStatus(UpdateTaskStatusRequest) returns (UpdateTaskStatusResponse) {
option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
};
// UpdateVolumeStatus updates the status of a Volume. Like
// UpdateTaskStatus, the node should send such updates on every status
// change of its volumes.
rpc UpdateVolumeStatus(UpdateVolumeStatusRequest) returns (UpdateVolumeStatusResponse) {
option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
};
// Tasks is a stream of tasks state for node. Each message contains full list
// of tasks which should be run on node, if task is not present in that list,
// it should be terminated.
rpc Tasks(TasksRequest) returns (stream TasksMessage) {
option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
option deprecated = true;
};
// Assignments is a stream of assignments such as tasks and secrets for node.
// The first message in the stream contains all of the tasks and secrets
// that are relevant to the node. Future messages in the stream are updates to
// the set of assignments.
rpc Assignments(AssignmentsRequest) returns (stream AssignmentsMessage) {
option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
};
}
// SessionRequest starts a session.
message SessionRequest {
NodeDescription description = 1;
// SessionID can be provided to attempt resuming an existing session. If the
// SessionID is empty or invalid, a new SessionID will be assigned.
//
// See SessionMessage.SessionID for details.
string session_id = 2;
}
// SessionMessage instructs an agent on various actions as part of the current
// session. An agent should act immediately on the contents.
message SessionMessage {
// SessionID is allocated after a successful registration. It should be
// used on all RPC calls after registration. A dispatcher may choose to
// change the SessionID, at which time an agent must re-register and obtain
// a new one.
//
// All Dispatcher calls after register should include the SessionID. If the
// Dispatcher so chooses, it may reject the call with an InvalidArgument
// error code, at which time the agent should call Register to start a new
// session.
//
// As a rule, once an agent has a SessionID, it should never save it to
// disk or try to otherwise reuse. If the agent loses its SessionID, it
// must start a new session through a call to Register. A Dispatcher may
// choose to reuse the SessionID, if it sees fit, but it is not advised.
//
// The actual implementation of the SessionID is Dispatcher specific and
// should be treated as opaque by agents.
//
// From a Dispatcher perspective, there are many ways to use the SessionID
// to ensure uniqueness of a set of client RPC calls. One method is to keep
// the SessionID unique to every call to Register in a single Dispatcher
// instance. This ensures that the SessionID represents the unique
// session from a single Agent to Manager. If the Agent restarts, we
// allocate a new session, since the restarted Agent is not aware of the
// new SessionID.
//
// The most compelling use case is to support duplicate node detection. If
// one clones a virtual machine, including certificate material, two nodes
// may end up with the same identity. This can also happen if two identical
// agent processes are coming from the same node. If the SessionID is
// replicated through the cluster, we can immediately detect the condition
// and address it.
//
// Extending from the case above, we can actually detect a compromised
// identity. Coupled with provisions to rebuild node identity, we can ban
// the compromised node identity and have the nodes re-authenticate and
// build a new identity. At this time, an administrator can then
// re-authorize the compromised nodes, if it was a mistake or ensure that a
// misbehaved node can no longer connect to the cluster.
//
// We considered placing this field in a GRPC header. Because this is a
// critical feature of the protocol, we thought it should be represented
// directly in the RPC message set.
string session_id = 1;
// Node identifies the registering node.
Node node = 2;
// Managers provides a weight list of alternative dispatchers
repeated WeightedPeer managers = 3;
// Symmetric encryption key distributed by the lead manager. Used by agents
// for securing network bootstrapping and communication.
repeated EncryptionKey network_bootstrap_keys = 4;
// Which root certificates to trust
bytes RootCA = 5;
}
// HeartbeatRequest provides identifying properties for a single heartbeat.
message HeartbeatRequest {
string session_id = 1;
}
message HeartbeatResponse {
// Period is the duration to wait before sending the next heartbeat.
// Well-behaved agents should update this on every heartbeat round trip.
google.protobuf.Duration period = 1 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];
}
message UpdateTaskStatusRequest {
// Tasks should contain all statuses for running tasks. Only the status
// field must be set. The spec is not required.
string session_id = 1;
message TaskStatusUpdate {
string task_id = 1;
TaskStatus status = 2;
}
repeated TaskStatusUpdate updates = 3;
}
message UpdateTaskStatusResponse{
// void
}
message UpdateVolumeStatusRequest {
string session_id = 1;
message VolumeStatusUpdate {
// ID is the ID of the volume being updated. This is the Swarmkit ID,
// not the CSI VolumeID.
string id = 1;
// Unpublished is set to true when the volume is affirmatively
// unpublished on the Node side. We don't need to report that a Volume
// is published on the the node; as soon as the Volume is assigned to
// the Node, we must assume that it has been published until informed
// otherwise.
//
// Further, the Node must not send unpublished = true unless it will
// definitely no longer attempt to call NodePublishVolume.
bool unpublished = 2;
}
repeated VolumeStatusUpdate updates = 2;
}
message UpdateVolumeStatusResponse {
// empty on purpose
}
message TasksRequest {
string session_id = 1;
}
message TasksMessage {
// Tasks is the set of tasks that should be running on the node.
// Tasks outside of this set running on the node should be terminated.
repeated Task tasks = 1;
}
message AssignmentsRequest {
string session_id = 1;
}
message Assignment {
oneof item {
Task task = 1;
Secret secret = 2;
Config config = 3;
VolumeAssignment volume = 4;
}
}
message AssignmentChange {
enum AssignmentAction {
UPDATE = 0 [(gogoproto.enumvalue_customname) = "AssignmentActionUpdate"];
REMOVE = 1 [(gogoproto.enumvalue_customname) = "AssignmentActionRemove"];
}
Assignment assignment = 1;
AssignmentAction action = 2;
}
message AssignmentsMessage {
// AssignmentType specifies whether this assignment message carries
// the full state, or is an update to an existing state.
enum Type {
COMPLETE = 0;
INCREMENTAL = 1;
}
Type type = 1;
// AppliesTo references the previous ResultsIn value, to chain
// incremental updates together. For the first update in a stream,
// AppliesTo is empty. If AppliesTo does not match the previously
// received ResultsIn, the consumer of the stream should start a new
// Assignments stream to re-sync.
string applies_to = 2;
// ResultsIn identifies the result of this assignments message, to
// match against the next message's AppliesTo value and protect
// against missed messages.
string results_in = 3;
// AssignmentChange is a set of changes to apply on this node.
repeated AssignmentChange changes = 4;
}