text: syntax = "proto3";
  
  package docker.swarmkit.v1;
  
  import "timestamp/timestamp.proto"; // TODO(stevvooe): use our own until we fix gogoproto/deepcopy
  import "duration/duration.proto"; // TODO(stevvooe): use our own until we fix gogoproto/deepcopy
  import "gogoproto/gogo.proto";
  
  // This file contains types that are common to objects and spec or that are not
  // considered first-class within the cluster object-model.
  
  // Version tracks the last time an object in the store was updated.
  message Version {
  	uint64 index = 1;
  }
  
  // Annotations provide useful information to identify API objects. They are
  // common to all API specs.
  message Annotations {
  	string name = 1;
  	map<string, string> labels = 2;
  }
  
  message Resources {
  	// Amount of CPUs (e.g. 2000000000 = 2 CPU cores)
  	int64 nano_cpus = 1 [(gogoproto.customname) = "NanoCPUs"];
  
  	// Amount of memory in bytes.
  	int64 memory_bytes = 2;
  }
  
  message ResourceRequirements {
  	Resources limits = 1;
  	Resources reservations = 2;
  }
  
  message Platform {
  	// Architecture (e.g. x86_64)
  	string architecture = 1;
  
  	// Operating System (e.g. linux)
  	string os = 2 [(gogoproto.customname) = "OS"];
  }
  
  // PluginDescription describes an engine plugin.
  message PluginDescription {
  	// Type of plugin. Canonical values for existing types are
  	// Volume, Network, and Authorization. More types could be
  	// supported in the future.
  	string type = 1;
  
  	// Name of the plugin
  	string name = 2;
  }
  
  message EngineDescription {
  	// Docker daemon version running on the node.
  	string engine_version = 1;
  
  	// Labels attached to the engine.
  	map<string, string> labels = 2;
  
  	// Volume, Network, and Auth plugins
  	repeated PluginDescription plugins = 3 [(gogoproto.nullable) = false];
  }
  
  message NodeDescription {
  	// Hostname of the node as reported by the agent.
  	// This is different from spec.meta.name which is user-defined.
  	string hostname = 1;
  
  	// Platform of the node.
  	Platform platform = 2;
  
  	// Total resources on the node.
  	Resources resources = 3;
  
  	// Information about the Docker Engine on the node.
  	EngineDescription engine = 4;
  }
  
  message RaftMemberStatus {
  	bool leader = 1;
  
  	enum Reachability {
  		// Unknown indicates that the manager state cannot be resolved
  		UNKNOWN = 0;
  
  		// Unreachable indicates that the node cannot be contacted by other
  		// raft cluster members.
  		UNREACHABLE = 1;
  
  		// Reachable indicates that the node is healthy and reachable
  		// by other members.
  		REACHABLE = 2;
  	}
  
  	Reachability reachability = 2;
  	string message = 3;
  }
  
  message NodeStatus {
  	// TODO(aluzzardi) These should be using `gogoproto.enumvalue_customname`.
  	enum State {
  		// Unknown indicates the node state cannot be resolved.
  		UNKNOWN = 0;
  
  		// Down indicates the node is down.
  		DOWN = 1;
  
  		// Ready indicates the node is ready to accept tasks.
  		READY = 2;
  
  		// Disconnected indicates the node is currently trying to find new manager.
  		DISCONNECTED = 3;
  	}
  
  	State state = 1;
  	string message = 2;
  	// Addr is the node's IP address as observed by the manager
  	string addr = 3;
  }
  
  message Image {
  	// reference is a docker image reference. This can include a rpository, tag
  	// or be fully qualified witha digest. The format is specified in the
  	// distribution/reference package.
  	string reference = 1;
  }
  
  // Mount describes volume mounts for a container.
  //
  // The Mount type follows the structure of the mount syscall, including a type,
  // source, target. Top-level flags, such as writable, are common to all kinds
  // of mounts, where we also provide options that are specific to a type of
  // mount. This corresponds to flags and data, respectively, in the syscall.
  message Mount {
  	enum Type {
  		option (gogoproto.goproto_enum_prefix) = false;
  		option (gogoproto.enum_customname) = "MountType";
  
  		BIND = 0 [(gogoproto.enumvalue_customname) = "MountTypeBind"]; // Bind mount host dir
  		VOLUME = 1 [(gogoproto.enumvalue_customname) = "MountTypeVolume"];  // Remote storage volumes
  		TMPFS = 2 [(gogoproto.enumvalue_customname) = "MountTypeTmpfs"]; // Mount a tmpfs
  	}
  
  	// Type defines the nature of the mount.
  	Type type = 1;
  
  	// Source specifies the name of the mount. Depending on mount type, this
  	// may be a volume name or a host path, or even ignored.
  	string source = 2;
  
  	// Target path in container
  	string target = 3;
  
  	// ReadOnly should be set to true if the mount should not be writable.
  	bool readonly = 4 [(gogoproto.customname) = "ReadOnly"];
  
  	// BindOptions specifies options that are specific to a bind mount.
  	message BindOptions {
  		enum Propagation {
  			option (gogoproto.goproto_enum_prefix) = false;
  			option (gogoproto.enum_customname) = "MountPropagation";
  
  			RPRIVATE = 0 [(gogoproto.enumvalue_customname) = "MountPropagationRPrivate"];
  			PRIVATE = 1 [(gogoproto.enumvalue_customname) = "MountPropagationPrivate"];
  			RSHARED = 2 [(gogoproto.enumvalue_customname) = "MountPropagationRShared"];
  			SHARED = 3 [(gogoproto.enumvalue_customname) = "MountPropagationShared"];
  			RSLAVE = 4 [(gogoproto.enumvalue_customname) = "MountPropagationRSlave"];
  			SLAVE = 5 [(gogoproto.enumvalue_customname) = "MountPropagationSlave"];
  		}
  
  		// Propagation mode of mount.
  		Propagation propagation = 1;
  	}
  
  	// VolumeOptions contains parameters for mounting the volume.
  	message VolumeOptions {
  		// nocopy prevents automatic copying of data to the volume with data from target
  		bool nocopy = 1 [(gogoproto.customname) = "NoCopy"];
  
  		// labels to apply to the volume if creating
  		map<string, string> labels = 2;
  
  		// DriverConfig specifies the options that may be passed to the driver
  		// if the volume is created.
  		//
  		// If this is empty, no volume will be created if the volume is missing.
  		Driver driver_config = 3;
  	}
  
  	message TmpfsOptions {
  		// Size sets the size of the tmpfs, in bytes.
  		//
  		// This will be converted to an operating system specific value
  		// depending on the host. For example, on linux, it will be convered to
  		// use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with
  		// docker, uses a straight byte value.
  		//
  		// Percentages are not supported.
  		int64 size_bytes = 1;
  
  		// Mode of the tmpfs upon creation
  		uint32 mode = 2 [(gogoproto.customtype) = "os.FileMode", (gogoproto.nullable) = false];
  
  		// TODO(stevvooe): There are several more tmpfs flags, specified in the
  		// daemon, that are accepted. Only the most basic are added for now.
  		//
  		// From docker/docker/pkg/mount/flags.go:
  		//
  		// var validFlags = map[string]bool{
  		// 	"":          true,
  		// 	"size":      true, X
  		// 	"mode":      true, X
  		// 	"uid":       true,
  		// 	"gid":       true,
  		// 	"nr_inodes": true,
  		// 	"nr_blocks": true,
  		// 	"mpol":      true,
  		// }
  		//
  		// Some of these may be straightforward to add, but others, such as
  		// uid/gid have implications in a clustered system.
  	}
  
  	// Depending on type, one of bind_options or volumes_options will be set.
  
  	// BindOptions configures properties of a bind mount type.
  	//
  	// For mounts of type bind, the source must be an absolute host path.
  	BindOptions bind_options = 5;
  
  	// VolumeOptions configures the properties specific to a volume mount type.
  	//
  	// For mounts of type volume, the source will be used as the volume name.
  	VolumeOptions volume_options = 6;
  
  	// TmpfsOptions allows one to set options for mounting a temporary
  	// filesystem.
  	//
  	// The source field will be ignored when using mounts of type tmpfs.
  	TmpfsOptions tmpfs_options = 7;
  
  	// TODO(stevvooe): It be better to use a oneof field above, although the
  	// type is enough to make the decision, while being primary to the
  	// datastructure.
  }
  
  message RestartPolicy {
  	enum RestartCondition {
  		option (gogoproto.goproto_enum_prefix) = false;
  		option (gogoproto.enum_customname) = "RestartCondition";
  		NONE = 0 [(gogoproto.enumvalue_customname) = "RestartOnNone"];
  		ON_FAILURE = 1 [(gogoproto.enumvalue_customname) = "RestartOnFailure"];
  		ANY = 2 [(gogoproto.enumvalue_customname) = "RestartOnAny"];
  	}
  
  	RestartCondition condition = 1;
  
  	// Delay between restart attempts
  	Duration delay = 2;
  
  	// MaxAttempts is the maximum number of restarts to attempt on an
  	// instance before giving up. Ignored if 0.
  	uint64 max_attempts = 3;
  
  	// Window is the time window used to evaluate the restart policy.
  	// The time window is unbounded if this is 0.
  	Duration window = 4;
  }
  
  // UpdateConfig specifies the rate and policy of updates.
  // TODO(aluzzardi): Consider making this a oneof with RollingStrategy and LockstepStrategy.
  message UpdateConfig {
  	// Maximum number of tasks to be updated in one iteration.
  	// 0 means unlimited parallelism.
  	uint64 parallelism = 1;
  
  	// Amount of time between updates.
  	Duration delay = 2 [(gogoproto.nullable) = false];
  
  	enum FailureAction {
  		PAUSE = 0;
  		CONTINUE = 1;
  		// NOTE: Automated rollback triggered as a failure action is an
  		// experimental feature that is not yet exposed to the end
  		// user. Currently, rollbacks must be initiated manually
  		// through the API by setting Spec to PreviousSpec. We may
  		// decide to expose automatic rollback in the future based on
  		// user feedback, or remove this feature otherwise.
  		ROLLBACK = 2;
  	}
  
  	// FailureAction is the action to take when an update failures.
  	FailureAction failure_action = 3;
  
  	// Monitor indicates how long to monitor a task for failure after it is
  	// created. If the task fails by ending up in one of the states
  	// REJECTED, COMPLETED, or FAILED, within Monitor from its creation,
  	// this counts as a failure. If it fails after Monitor, it does not
  	// count as a failure. If Monitor is unspecified, a default value will
  	// be used.
  	Duration monitor = 4;
  
  	// MaxFailureRatio is the fraction of tasks that may fail during
  	// an update before the failure action is invoked. Any task created by
  	// the current update which ends up in one of the states REJECTED,
  	// COMPLETED or FAILED within Monitor from its creation counts as a
  	// failure. The number of failures is divided by the number of tasks
  	// being updated, and if this fraction is greater than
  	// MaxFailureRatio, the failure action is invoked.
  	//
  	// If the failure action is CONTINUE, there is no effect.
  	// If the failure action is PAUSE, no more tasks will be updated until
  	// another update is started.
  	// If the failure action is ROLLBACK, the orchestrator will attempt to
  	// roll back to the previous service spec. If the MaxFailureRatio
  	// threshold is hit during the rollback, the rollback will pause.
  	//
  	// TODO(aaronl): Should there be a separate failure threshold for
  	// rollbacks? Should there be a failure action for rollbacks (to allow
  	// them to do something other than pause when the rollback encounters
  	// errors)?
  	float max_failure_ratio = 5;
  }
  
  // UpdateStatus is the status of an update in progress.
  message UpdateStatus {
  	enum UpdateState {
  		UNKNOWN = 0;
  		UPDATING = 1;
  		PAUSED = 2;
  		COMPLETED = 3;
  		ROLLBACK_STARTED = 4;
  		ROLLBACK_PAUSED = 5; // if a rollback fails
  		ROLLBACK_COMPLETED = 6;
  	}
  
  	// State is the state of this update. It indicates whether the
  	// update is in progress, completed, paused, rolling back, or
  	// finished rolling back.
  	UpdateState state = 1;
  
  	// StartedAt is the time at which the update was started.
  	Timestamp started_at = 2;
  
  	// CompletedAt is the time at which the update completed successfully,
  	// paused, or finished rolling back.
  	Timestamp completed_at = 3;
  
  	// TODO(aaronl): Consider adding a timestamp showing when the most
  	// recent task update took place. Currently, this is nontrivial
  	// because each service update kicks off a replacement update, so
  	// updating the service object with a timestamp at every step along
  	// the rolling update would cause the rolling update to be constantly
  	// restarted.
  
  	// Message explains how the update got into its current state. For
  	// example, if the update is paused, it will explain what is preventing
  	// the update from proceeding (typically the failure of a task to start up
  	// when OnFailure is PAUSE).
  	string message = 4;
  }
  
  // TaskState enumerates the states that a task progresses through within an
  // agent. States are designed to be monotonically increasing, such that if two
  // states are seen by a task, the greater of the new represents the true state.
  enum TaskState {
  	// TODO(aluzzardi): Move it back into `TaskStatus` because of the naming
  	// collisions of enums.
  
  	option (gogoproto.goproto_enum_prefix) = false;
  	option (gogoproto.enum_customname) = "TaskState";
  	NEW = 0 [(gogoproto.enumvalue_customname)="TaskStateNew"];
  	PENDING = 64 [(gogoproto.enumvalue_customname)="TaskStatePending"]; // waiting for scheduling decision
  	ASSIGNED = 192 [(gogoproto.enumvalue_customname)="TaskStateAssigned"];
  	ACCEPTED = 256 [(gogoproto.enumvalue_customname)="TaskStateAccepted"]; // task has been accepted by an agent.
  	PREPARING = 320 [(gogoproto.enumvalue_customname)="TaskStatePreparing"];
  	READY = 384 [(gogoproto.enumvalue_customname)="TaskStateReady"];
  	STARTING = 448 [(gogoproto.enumvalue_customname)="TaskStateStarting"];
  	RUNNING = 512 [(gogoproto.enumvalue_customname)="TaskStateRunning"];
  	COMPLETE = 576 [(gogoproto.enumvalue_customname)="TaskStateCompleted"]; // successful completion of task (not error code, just ran)
  	SHUTDOWN = 640 [(gogoproto.enumvalue_customname)="TaskStateShutdown"]; // orchestrator requested shutdown
  	FAILED = 704 [(gogoproto.enumvalue_customname)="TaskStateFailed"]; // task execution failed with error
  	REJECTED = 768 [(gogoproto.enumvalue_customname)="TaskStateRejected"]; // task could not be executed here.
  
  	// NOTE(stevvooe): The state of a task is actually a lamport clock, in that
  	// given two observations, the greater of the two can be considered
  	// correct. To enforce this, we only allow tasks to proceed to a greater
  	// state.
  	//
  	// A byproduct of this design decision is that we must also maintain this
  	// invariant in the protobuf enum values, such that when comparing two
  	// values, the one with the greater value is also the greater state.
  	//
  	// Because we may want to add intervening states a later date, we've left
  	// 64 spaces between each one. This should allow us to make 5 or 6
  	// insertions between each state if we find that we made a mistake and need
  	// another state.
  	//
  	// Remove this message when the states are deemed perfect.
  }
  
  // Container specific status.
  message ContainerStatus {
  	string container_id = 1 [(gogoproto.customname) = "ContainerID"];
  
  	int32 pid = 2 [(gogoproto.customname) = "PID"];
  	int32 exit_code = 3;
  }
  
  // PortStatus specifies the actual allocated runtime state of a list
  // of port configs.
  message PortStatus {
  	repeated PortConfig ports = 1;
  }
  
  message TaskStatus {
  	Timestamp timestamp = 1;
  
  	// State expresses the current state of the task.
  	TaskState state = 2;
  
  	// Message reports a message for the task status. This should provide a
  	// human readable message that can point to how the task actually arrived
  	// at a current state.
  	//
  	// As a convention, we place the a small message here that led to the
  	// current state. For example, if the task is in ready, because it was
  	// prepared, we'd place "prepared" in this field. If we skipped preparation
  	// because the task is prepared, we would put "already prepared" in this
  	// field.
  	string message = 3;
  
  	// Err is set if the task is in an error state.
  	//
  	// The following states should report a companion error:
  	//
  	//	FAILED, REJECTED
  	//
  	// TODO(stevvooe) Integrate this field with the error interface.
  	string err = 4;
  
  	// Container status contains container specific status information.
  	oneof runtime_status {
  		ContainerStatus container = 5;
  	}
  
  	// HostPorts provides a list of ports allocated at the host
  	// level.
  	PortStatus port_status = 6;
  }
  
  // NetworkAttachmentConfig specifies how a service should be attached to a particular network.
  //
  // For now, this is a simple struct, but this can include future information
  // instructing Swarm on how this service should work on the particular
  // network.
  message NetworkAttachmentConfig {
  	// Target specifies the target network for attachment. This value must be a
  	// network ID.
  	string target = 1;
  	// Aliases specifies a list of discoverable alternate names for the service on this Target.
  	repeated string aliases = 2;
  	// Addresses specifies a list of ipv4 and ipv6 addresses
  	// preferred. If these addresses are not available then the
  	// attachment might fail.
  	repeated string addresses = 3;
  }
  
  // IPAMConfig specifies parameters for IP Address Management.
  message IPAMConfig {
  	// TODO(stevvooe): It may make more sense to manage IPAM and network
  	// definitions separately. This will allow multiple networks to share IPAM
  	// instances. For now, we will follow the conventions of libnetwork and
  	// specify this as part of the network specification.
  
  	// AddressFamily specifies the network address family that
  	// this IPAMConfig belongs to.
  	enum AddressFamily {
  		UNKNOWN = 0; // satisfy proto3
  		IPV4 = 4;
  		IPV6 = 6;
  	}
  
  	AddressFamily family = 1;
  
  	// Subnet defines a network as a CIDR address (ie network and mask
  	// 192.168.0.1/24).
  	string subnet = 2;
  
  	// Range defines the portion of the subnet to allocate to tasks. This is
  	// defined as a subnet within the primary subnet.
  	string range = 3;
  
  	// Gateway address within the subnet.
  	string gateway = 4;
  
  	// Reserved is a list of address from the master pool that should *not* be
  	// allocated. These addresses may have already been allocated or may be
  	// reserved for another allocation manager.
  	map<string, string> reserved = 5;
  }
  
  // PortConfig specifies an exposed port which can be
  // addressed using the given name. This can be later queried
  // using a service discovery api or a DNS SRV query. The node
  // port specifies a port that can be used to address this
  // service external to the cluster by sending a connection
  // request to this port to any node on the cluster.
  message PortConfig {
  	enum Protocol {
  		option (gogoproto.goproto_enum_prefix) = false;
  
  		TCP = 0 [(gogoproto.enumvalue_customname) = "ProtocolTCP"];
  		UDP = 1 [(gogoproto.enumvalue_customname) = "ProtocolUDP"];
  	}
  
  	// PublishMode controls how ports are published on the swarm.
  	enum PublishMode {
  		option (gogoproto.enum_customname) = "PublishMode";
  		option (gogoproto.goproto_enum_prefix) = false;
  
  		// PublishModeIngress exposes the port across the cluster on all nodes.
  		INGRESS = 0 [(gogoproto.enumvalue_customname) = "PublishModeIngress"];
  
  		// PublishModeHost exposes the port on just the target host.  If the
  		// published port is undefined, an ephemeral port will be allocated. If
  		// the published port is defined, the node will attempt to allocate it,
  		// erroring the task if it fails.
  		HOST = 1 [(gogoproto.enumvalue_customname) = "PublishModeHost"];
  	}
  
  	// Name for the port. If provided the port information can
  	// be queried using the name as in a DNS SRV query.
  	string name = 1;
  
  	// Protocol for the port which is exposed.
  	Protocol protocol = 2;
  
  	// The port which the application is exposing and is bound to.
  	uint32 target_port = 3;
  
  	// PublishedPort specifies the port on which the service is exposed. If
  	// specified, the port must be within the available range. If not specified
  	// (value is zero), an available port is automatically assigned.
  	uint32 published_port = 4;
  
  	// PublishMode controls how the port is published.
  	PublishMode publish_mode = 5;
  }
  
  // Driver is a generic driver type to be used throughout the API. For now, a
  // driver is simply a name and set of options. The field contents depend on the
  // target use case and driver application. For example, a network driver may
  // have different rules than a volume driver.
  message Driver {
  	string name = 1;
  	map <string, string> options = 2;
  }
  
  message IPAMOptions {
  	Driver driver = 1;
  	repeated IPAMConfig configs = 3;
  }
  
  // Peer should be used anywhere where we are describing a remote peer.
  message Peer {
  	string node_id = 1 [(gogoproto.customname) = "NodeID"];
  	string addr = 2;
  }
  
  // WeightedPeer should be used anywhere where we are describing a remote peer
  // with a weight.
  message WeightedPeer {
  	Peer peer = 1;
  	int64 weight = 2;
  }
  
  
  message IssuanceStatus {
  	enum State {
  		option (gogoproto.goproto_enum_prefix) = false;
  
  		UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "IssuanceStateUnknown"];
  		// A new certificate should be issued
  		RENEW = 1 [(gogoproto.enumvalue_customname)="IssuanceStateRenew"];
  		// Certificate is pending acceptance
  		PENDING = 2 [(gogoproto.enumvalue_customname)="IssuanceStatePending"];
  		// successful completion certificate issuance
  		ISSUED = 3 [(gogoproto.enumvalue_customname)="IssuanceStateIssued"];
  		// Certificate issuance failed
  		FAILED = 4 [(gogoproto.enumvalue_customname)="IssuanceStateFailed"];
  		// Signals workers to renew their certificate. From the CA's perspective
  		// this is equivalent to IssuanceStateIssued: a noop.
  		ROTATE = 5 [(gogoproto.enumvalue_customname)="IssuanceStateRotate"];
  	}
  	State state = 1;
  
  	// Err is set if the Certificate Issuance is in an error state.
  	// The following states should report a companion error:
  	//	FAILED
  	string err = 2;
  }
  
  message AcceptancePolicy {
  	message RoleAdmissionPolicy {
  		message Secret {
  			// The actual content (possibly hashed)
  			bytes data = 1;
  			// The type of hash we are using, or "plaintext"
  			string alg = 2;
  		}
  
  		NodeRole role = 1;
  		// Autoaccept controls which roles' certificates are automatically
  		// issued without administrator intervention.
  		bool autoaccept = 2;
  		// Secret represents a user-provided string that is necessary for new
  		// nodes to join the cluster
  		Secret secret = 3;
  	}
  
  	repeated RoleAdmissionPolicy policies = 1;
  }
  
  message ExternalCA {
  	enum CAProtocol {
  		CFSSL = 0 [(gogoproto.enumvalue_customname) = "CAProtocolCFSSL"];
  	}
  
  	// Protocol is the protocol used by this external CA.
  	CAProtocol protocol = 1;
  
  	// URL is the URL where the external CA can be reached.
  	string url = 2 [(gogoproto.customname) = "URL"];
  
  	// Options is a set of additional key/value pairs whose interpretation
  	// depends on the specified CA type.
  	map<string, string> options = 3;
  }
  
  message CAConfig {
  	// NodeCertExpiry is the duration certificates should be issued for
  	Duration node_cert_expiry = 1;
  
  	// ExternalCAs is a list of CAs to which a manager node will make
  	// certificate signing requests for node certificates.
  	repeated ExternalCA external_cas = 2 [(gogoproto.customname) = "ExternalCAs"];
  }
  
  // OrchestrationConfig defines cluster-level orchestration settings.
  message OrchestrationConfig {
  	// TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or
  	// node. If negative, never remove completed or failed tasks.
  	int64 task_history_retention_limit = 1;
  
  }
  
  // TaskDefaults specifies default values for task creation.
  message TaskDefaults {
  	// LogDriver specifies the log driver to use for the cluster if not
  	// specified for each task.
  	//
  	// If this is changed, only new tasks will pick up the new log driver.
  	// Existing tasks will continue to use the previous default until rescheduled.
  	Driver log_driver = 1;
  }
  
  // DispatcherConfig defines cluster-level dispatcher settings.
  message DispatcherConfig {
  	// HeartbeatPeriod defines how often agent should send heartbeats to
  	// dispatcher.
  	Duration heartbeat_period = 1;
  }
  
  // RaftConfig defines raft settings for the cluster.
  message RaftConfig {
  	// SnapshotInterval is the number of log entries between snapshots.
  	uint64 snapshot_interval = 1;
  	// KeepOldSnapshots is the number of snapshots to keep beyond the
  	// current snapshot.
  	uint64 keep_old_snapshots = 2;
  	// LogEntriesForSlowFollowers is the number of log entries to keep
  	// around to sync up slow followers after a snapshot is created.
  	uint64 log_entries_for_slow_followers = 3;
  	// HeartbeatTick defines the amount of ticks (in seconds) between
  	// each heartbeat message sent to other members for health-check.
  	uint32 heartbeat_tick = 4;
  	// ElectionTick defines the amount of ticks (in seconds) needed
  	// without a leader to trigger a new election.
  	uint32 election_tick = 5;
  }
  
  // Placement specifies task distribution constraints.
  message Placement {
  	// constraints specifies a set of requirements a node should meet for a task.
  	repeated string constraints = 1;
  }
  
  // JoinToken contains the join tokens for workers and managers.
  message JoinTokens {
  	// Worker is the join token workers may use to join the swarm.
  	string worker = 1;
  
  	// Manager is the join token workers may use to join the swarm.
  	string manager = 2;
  }
  
  message RootCA {
  	// CAKey is the root CA private key.
  	bytes ca_key = 1 [(gogoproto.customname) = "CAKey"];
  
  	// CACert is the root CA certificate.
  	bytes ca_cert = 2 [(gogoproto.customname) = "CACert"];
  
  	// CACertHash is the digest of the CA Certificate.
  	string ca_cert_hash = 3 [(gogoproto.customname) = "CACertHash"];
  
  	// JoinTokens contains the join tokens for workers and managers.
  	JoinTokens join_tokens = 4 [(gogoproto.nullable) = false];
  }
  
  
  enum NodeRole {
  	option (gogoproto.enum_customname) = "NodeRole";
  	option (gogoproto.goproto_enum_prefix) = false;
  
  	WORKER = 0 [(gogoproto.enumvalue_customname) = "NodeRoleWorker"];
  	MANAGER = 1 [(gogoproto.enumvalue_customname) = "NodeRoleManager"];
  }
  
  message Certificate {
  	NodeRole role = 1;
  
  	bytes csr = 2 [(gogoproto.customname) = "CSR"];
  
  	IssuanceStatus status = 3 [(gogoproto.nullable) = false];
  
  	bytes certificate = 4;
  
  	// CN represents the node ID.
  	string cn = 5 [(gogoproto.customname) = "CN"];
  }
  
  
  // Symmetric keys to encrypt inter-agent communication.
  message EncryptionKey {
  	// Agent subsystem the key is intended for. Example:
  	// networking:gossip
  	string subsystem = 1;
  
  	// Encryption algorithm that can implemented using this key
  	enum Algorithm {
  		option (gogoproto.goproto_enum_prefix) = false;
  
  		AES_128_GCM = 0;
  	}
  
  	Algorithm algorithm = 2;
  
  	bytes key = 3;
  
  	// Time stamp from the lamport clock of the key allocator to
  	// identify the relative age of the key.
  	uint64 lamport_time = 4;
  }
  
  // ManagerStatus provides informations about the state of a manager in the cluster.
  message ManagerStatus {
  	// RaftID specifies the internal ID used by the manager in a raft context, it can never be modified
  	// and is used only for information purposes
  	uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
  
  	// Addr is the address advertised to raft.
  	string addr = 2;
  
  	// Leader is set to true if this node is the raft leader.
  	bool leader = 3;
  
  	// Reachability specifies whether this node is reachable.
  	RaftMemberStatus.Reachability reachability = 4;
  }
  
  
  // SecretReference is the linkage between a service and a secret that it uses.
  message SecretReference {
  	// SecretID represents the ID of the specific Secret that we're
  	// referencing. This identifier exists so that SecretReferences don't leak
  	// any information about the secret contents.
  	string secret_id = 1 [(gogoproto.customname) = "SecretID"];
  
  	// SecretName is the name of the secret that this references, but this is just provided for
  	// lookup/display purposes.  The secret in the reference will be identified by its ID.
  	string secret_name = 2;
  
  	// FileTarget represents a specific target that is backed by a file
  	message FileTarget {
  		// Name represents the final filename in the filesystem
  		string name = 1;
  
  		// UID represents the file UID
  		string uid = 2 [(gogoproto.customname) = "UID"];
  
  		// GID represents the file GID
  		string gid = 3 [(gogoproto.customname) = "GID"];
  
  		// Mode represents the FileMode of the file
  		uint32 mode = 4 [(gogoproto.customtype) = "os.FileMode", (gogoproto.nullable) = false];
  	}
  
  	// Target specifies how this secret should be exposed to the task.
  	oneof target {
  		FileTarget file = 3;
  	}
  }
  
  // BlacklistedCertificate is a record for a blacklisted certificate. It does not
  // contain the certificate's CN, because these records are indexed by CN.
  message BlacklistedCertificate {
  	// Expiry is the latest known expiration time of a certificate that
  	// was issued for the given CN.
  	Timestamp expiry = 1;
  }
  
  // HealthConfig holds configuration settings for the HEALTHCHECK feature.
  message HealthConfig {
  	// Test is the test to perform to check that the container is healthy.
  	// An empty slice means to inherit the default.
  	// The options are:
  	// {} : inherit healthcheck
  	// {"NONE"} : disable healthcheck
  	// {"CMD", args...} : exec arguments directly
  	// {"CMD-SHELL", command} : run command with system's default shell
  	repeated string test = 1;
  
  	// Interval is the time to wait between checks. Zero means inherit.
  	Duration interval = 2;
  
  	// Timeout is the time to wait before considering the check to have hung.
  	// Zero means inherit.
  	Duration timeout = 3;
  
  	// Retries is the number of consecutive failures needed to consider a
  	// container as unhealthy. Zero means inherit.
  	int32 retries = 4;
  }
  
  message MaybeEncryptedRecord {
  	enum Algorithm {
  		NONE = 0 [(gogoproto.enumvalue_customname) = "NotEncrypted"];
  		SECRETBOX_SALSA20_POLY1305 = 1 [(gogoproto.enumvalue_customname) = "NACLSecretboxSalsa20Poly1305"];
  	}
  
  	Algorithm algorithm = 1;
  	bytes data = 2;
  	bytes nonce = 3;
  }
  