Update swarmkit vendor

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
Derek McGowan 2017-02-06 16:23:19 -08:00
parent 24698a07cb
commit 2bea87393b
No known key found for this signature in database
GPG key ID: F58C5D0A4405ACDB
20 changed files with 168 additions and 103 deletions

View file

@ -102,7 +102,7 @@ github.com/docker/containerd 78fb8f45890a601e0fd9051cf9f9f74923e950fd
github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
# cluster
github.com/docker/swarmkit 78ae345f449ac69aa741c762df7e5f0020f70275
github.com/docker/swarmkit 3ca4775ba4a5519e2225c3337c7db8901ec39d26
github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
github.com/gogo/protobuf 8d70fb3182befc465c4a1eac8ad4d38ff49778e2
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a

View file

@ -39,6 +39,7 @@ type Agent struct {
ready chan struct{}
leaving chan struct{}
leaveOnce sync.Once
left chan struct{} // closed after "run" processes "leaving" and will no longer accept new assignments
stopped chan struct{} // requests shutdown
stopOnce sync.Once // only allow stop to be called once
closed chan struct{} // only closed in run
@ -56,6 +57,7 @@ func New(config *Config) (*Agent, error) {
sessionq: make(chan sessionOperation),
started: make(chan struct{}),
leaving: make(chan struct{}),
left: make(chan struct{}),
stopped: make(chan struct{}),
closed: make(chan struct{}),
ready: make(chan struct{}),
@ -96,6 +98,16 @@ func (a *Agent) Leave(ctx context.Context) error {
close(a.leaving)
})
// Do not call Wait until we have confirmed that the agent is no longer
// accepting assignments. Starting a worker might race with Wait.
select {
case <-a.left:
case <-a.closed:
return ErrClosed
case <-ctx.Done():
return ctx.Err()
}
// agent could be closed while Leave is in progress
var err error
ch := make(chan struct{})
@ -215,6 +227,8 @@ func (a *Agent) run(ctx context.Context) {
if err := a.worker.Assign(ctx, nil); err != nil {
log.G(ctx).WithError(err).Error("failed removing all assignments")
}
close(a.left)
case msg := <-session.assignments:
// if we have left, accept no more assignments
if leaving == nil {

View file

@ -104,17 +104,21 @@ func Resolve(ctx context.Context, task *api.Task, executor Executor) (Controller
// depending on the tasks state, a failed controller resolution has varying
// impact. The following expresses that impact.
if task.Status.State < api.TaskStateStarting {
if err != nil {
// before the task has been started, we consider it a rejection.
status.Message = "resolving controller failed"
status.Err = err.Error()
if err != nil {
status.Message = "resolving controller failed"
status.Err = err.Error()
// before the task has been started, we consider it a rejection.
// if task is running, consider the task has failed
// otherwise keep the existing state
if task.Status.State < api.TaskStateStarting {
status.State = api.TaskStateRejected
} else if task.Status.State < api.TaskStateAccepted {
// we always want to proceed to accepted when we resolve the contoller
status.Message = "accepted"
status.State = api.TaskStateAccepted
} else if task.Status.State <= api.TaskStateRunning {
status.State = api.TaskStateFailed
}
} else if task.Status.State < api.TaskStateAccepted {
// we always want to proceed to accepted when we resolve the controller
status.Message = "accepted"
status.State = api.TaskStateAccepted
}
return ctlr, status, err

View file

@ -30,7 +30,7 @@ service NodeCA {
}
message NodeCertificateStatusRequest {
string node_id = 1 [(gogoproto.customname) = "NodeID"];
string node_id = 1;
}
message NodeCertificateStatusResponse {
@ -54,7 +54,7 @@ message IssueNodeCertificateRequest {
}
message IssueNodeCertificateResponse {
string node_id = 1 [(gogoproto.customname) = "NodeID"];
string node_id = 1;
NodeSpec.Membership node_membership = 2;
}

View file

@ -119,7 +119,7 @@ service Control {
}
message GetNodeRequest {
string node_id = 1 [(gogoproto.customname) = "NodeID"];
string node_id = 1;
}
message GetNodeResponse {
@ -129,7 +129,7 @@ message GetNodeResponse {
message ListNodesRequest {
message Filters {
repeated string names = 1;
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
repeated string id_prefixes = 2;
map<string, string> labels = 3;
repeated NodeSpec.Membership memberships = 4;
repeated NodeRole roles = 5;
@ -148,7 +148,7 @@ message ListNodesResponse {
// to request a new availability for a node, such as PAUSE. Invalid updates
// will be denied and cause an error.
message UpdateNodeRequest {
string node_id = 1 [(gogoproto.customname) = "NodeID"];
string node_id = 1;
Version node_version = 2;
NodeSpec spec = 3;
}
@ -159,7 +159,7 @@ message UpdateNodeResponse {
// RemoveNodeRequest requests to delete the specified node from store.
message RemoveNodeRequest {
string node_id = 1 [(gogoproto.customname) = "NodeID"];
string node_id = 1;
bool force = 2;
}
@ -167,7 +167,7 @@ message RemoveNodeResponse {
}
message GetTaskRequest {
string task_id = 1 [(gogoproto.customname) = "TaskID"];
string task_id = 1;
}
message GetTaskResponse {
@ -175,7 +175,7 @@ message GetTaskResponse {
}
message RemoveTaskRequest {
string task_id = 1 [(gogoproto.customname) = "TaskID"];
string task_id = 1;
}
message RemoveTaskResponse {
@ -184,10 +184,10 @@ message RemoveTaskResponse {
message ListTasksRequest {
message Filters {
repeated string names = 1;
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
repeated string id_prefixes = 2;
map<string, string> labels = 3;
repeated string service_ids = 4 [(gogoproto.customname) = "ServiceIDs"];
repeated string node_ids = 5 [(gogoproto.customname) = "NodeIDs"];
repeated string service_ids = 4;
repeated string node_ids = 5;
repeated docker.swarmkit.v1.TaskState desired_states = 6;
// NamePrefixes matches all objects with the given prefixes
repeated string name_prefixes = 7;
@ -209,7 +209,7 @@ message CreateServiceResponse {
}
message GetServiceRequest {
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
string service_id = 1;
}
message GetServiceResponse {
@ -217,7 +217,7 @@ message GetServiceResponse {
}
message UpdateServiceRequest {
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
string service_id = 1;
Version service_version = 2;
ServiceSpec spec = 3;
}
@ -227,7 +227,7 @@ message UpdateServiceResponse {
}
message RemoveServiceRequest {
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
string service_id = 1;
}
message RemoveServiceResponse {
@ -236,7 +236,7 @@ message RemoveServiceResponse {
message ListServicesRequest {
message Filters {
repeated string names = 1;
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
repeated string id_prefixes = 2;
map<string, string> labels = 3;
// NamePrefixes matches all objects with the given prefixes
repeated string name_prefixes = 4;
@ -259,7 +259,7 @@ message CreateNetworkResponse {
message GetNetworkRequest {
string name = 1;
string network_id = 2 [(gogoproto.customname) = "NetworkID"];
string network_id = 2;
}
message GetNetworkResponse {
@ -268,7 +268,7 @@ message GetNetworkResponse {
message RemoveNetworkRequest {
string name = 1;
string network_id = 2 [(gogoproto.customname) = "NetworkID"];
string network_id = 2;
}
message RemoveNetworkResponse {}
@ -276,7 +276,7 @@ message RemoveNetworkResponse {}
message ListNetworksRequest {
message Filters {
repeated string names = 1;
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
repeated string id_prefixes = 2;
map<string, string> labels = 3;
// NamePrefixes matches all objects with the given prefixes
repeated string name_prefixes = 4;
@ -290,7 +290,7 @@ message ListNetworksResponse {
}
message GetClusterRequest {
string cluster_id = 1 [(gogoproto.customname) = "ClusterID"];
string cluster_id = 1;
}
message GetClusterResponse {
@ -300,7 +300,7 @@ message GetClusterResponse {
message ListClustersRequest {
message Filters {
repeated string names = 1;
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
repeated string id_prefixes = 2;
map<string, string> labels = 3;
// NamePrefixes matches all objects with the given prefixes
repeated string name_prefixes = 4;
@ -328,7 +328,7 @@ message KeyRotation {
message UpdateClusterRequest {
// ClusterID is the cluster ID to update.
string cluster_id = 1 [(gogoproto.customname) = "ClusterID"];
string cluster_id = 1;
// ClusterVersion is the version of the cluster being updated.
Version cluster_version = 2;
@ -346,7 +346,7 @@ message UpdateClusterResponse {
// GetSecretRequest is the request to get a `Secret` object given a secret id.
message GetSecretRequest {
string secret_id = 1 [(gogoproto.customname) = "SecretID"];
string secret_id = 1;
}
// GetSecretResponse contains the Secret corresponding to the id in
@ -358,7 +358,7 @@ message GetSecretResponse {
message UpdateSecretRequest {
// SecretID is the secret ID to update.
string secret_id = 1 [(gogoproto.customname) = "SecretID"];
string secret_id = 1;
// SecretVersion is the version of the secret being updated.
Version secret_version = 2;
@ -378,7 +378,7 @@ message UpdateSecretResponse {
message ListSecretsRequest {
message Filters {
repeated string names = 1;
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
repeated string id_prefixes = 2;
map<string, string> labels = 3;
repeated string name_prefixes = 4;
}
@ -410,7 +410,7 @@ message CreateSecretResponse {
// RemoveSecretRequest contains the ID of the secret that should be removed. This
// removes all versions of the secret.
message RemoveSecretRequest {
string secret_id = 1 [(gogoproto.customname) = "SecretID"];
string secret_id = 1;
}
// RemoveSecretResponse is an empty object indicating the successful removal of

View file

@ -66,7 +66,7 @@ message SessionRequest {
// SessionID is empty or invalid, a new SessionID will be assigned.
//
// See SessionMessage.SessionID for details.
string session_id = 2 [(gogoproto.customname) = "SessionID"];
string session_id = 2;
}
// SessionMessage instructs an agent on various actions as part of the current
@ -115,7 +115,7 @@ message SessionMessage {
// 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 [(gogoproto.customname) = "SessionID"];
string session_id = 1;
// Node identifies the registering node.
Node node = 2;
@ -130,7 +130,7 @@ message SessionMessage {
// HeartbeatRequest provides identifying properties for a single heartbeat.
message HeartbeatRequest {
string session_id = 1 [(gogoproto.customname) = "SessionID"];
string session_id = 1;
}
message HeartbeatResponse {
@ -142,10 +142,10 @@ message HeartbeatResponse {
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 [(gogoproto.customname) = "SessionID"];
string session_id = 1;
message TaskStatusUpdate {
string task_id = 1 [(gogoproto.customname) = "TaskID"];
string task_id = 1;
TaskStatus status = 2;
}
@ -157,7 +157,7 @@ message UpdateTaskStatusResponse{
}
message TasksRequest {
string session_id = 1 [(gogoproto.customname) = "SessionID"];
string session_id = 1;
}
message TasksMessage {
@ -167,7 +167,7 @@ message TasksMessage {
}
message AssignmentsRequest {
string session_id = 1 [(gogoproto.customname) = "SessionID"];
string session_id = 1;
}
message Assignment {

View file

@ -54,16 +54,16 @@ message LogSubscriptionOptions {
// possible. For example, if they want to listen to all the tasks of a service,
// they should use the service id, rather than specifying the individual tasks.
message LogSelector {
repeated string service_ids = 1 [(gogoproto.customname) = "ServiceIDs"];
repeated string node_ids = 2 [(gogoproto.customname) = "NodeIDs"];
repeated string task_ids = 3 [(gogoproto.customname) = "TaskIDs"];
repeated string service_ids = 1;
repeated string node_ids = 2;
repeated string task_ids = 3;
}
// LogContext marks the context from which a log message was generated.
message LogContext {
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
string node_id = 2 [(gogoproto.customname) = "NodeID"];
string task_id = 3 [(gogoproto.customname) = "TaskID"];
string service_id = 1;
string node_id = 2;
string task_id = 3;
}
// LogMessage
@ -147,7 +147,7 @@ message ListenSubscriptionsRequest { }
// If Options.Follow == false, the worker should end the subscription on its own.
message SubscriptionMessage {
// ID identifies the subscription.
string id = 1 [(gogoproto.customname) = "ID"];
string id = 1;
// Selector defines which sources should be sent for the subscription.
LogSelector selector = 2;
@ -163,7 +163,7 @@ message SubscriptionMessage {
message PublishLogsMessage {
// SubscriptionID identifies which subscription the set of messages should
// be sent to. We can think of this as a "mail box" for the subscription.
string subscription_id = 1 [(gogoproto.customname) = "SubscriptionID"];
string subscription_id = 1;
// Messages is the log message for publishing.
repeated LogMessage messages = 2 [(gogoproto.nullable) = false];

View file

@ -25,7 +25,7 @@ message Meta {
// Node provides the internal node state as seen by the cluster.
message Node {
// ID specifies the identity of the node.
string id = 1 [(gogoproto.customname) = "ID"];
string id = 1;
Meta meta = 2 [(gogoproto.nullable) = false];
@ -63,7 +63,7 @@ message Node {
}
message Service {
string id = 1 [(gogoproto.customname) = "ID"];
string id = 1;
Meta meta = 2 [(gogoproto.nullable) = false];
@ -101,7 +101,7 @@ message Endpoint {
// and the IP addresses the target service will be made available under.
message VirtualIP {
// NetworkID for which this endpoint attachment was created.
string network_id = 1 [(gogoproto.customname) = "NetworkID"];
string network_id = 1;
// A virtual IP is used to address this service in IP
// layer that the client can use to send requests to
@ -123,7 +123,7 @@ message Endpoint {
// immutable and idempotent. Once it is dispatched to a node, it will not be
// dispatched to another node.
message Task {
string id = 1 [(gogoproto.customname) = "ID"];
string id = 1;
Meta meta = 2 [(gogoproto.nullable) = false];
@ -133,7 +133,7 @@ message Task {
// ServiceID indicates the service under which this task is orchestrated. This
// should almost always be set.
string service_id = 4 [(gogoproto.customname) = "ServiceID"];
string service_id = 4;
// Slot is the service slot number for a task.
// For example, if a replicated service has replicas = 2, there will be a
@ -142,7 +142,7 @@ message Task {
// NodeID indicates the node to which the task is assigned. If this field
// is empty or not set, the task is unassigned.
string node_id = 6 [(gogoproto.customname) = "NodeID"];
string node_id = 6;
// Annotations defines the names and labels for the runtime, as set by
// the cluster manager.
@ -204,7 +204,7 @@ message NetworkAttachment {
}
message Network {
string id = 1 [(gogoproto.customname) = "ID"];
string id = 1;
Meta meta = 2 [(gogoproto.nullable) = false];
@ -220,7 +220,7 @@ message Network {
// Cluster provides global cluster settings.
message Cluster {
string id = 1 [(gogoproto.customname) = "ID"];
string id = 1;
Meta meta = 2 [(gogoproto.nullable) = false];
@ -256,7 +256,7 @@ message Cluster {
// information that is generated from the secret data in the `spec`, such as
// the digest and size of the secret data.
message Secret {
string id = 1 [(gogoproto.customname) = "ID"];
string id = 1;
Meta meta = 2 [(gogoproto.nullable) = false];

View file

@ -40,10 +40,10 @@ service RaftMembership {
message RaftMember {
// 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"];
uint64 raft_id = 1;
// NodeID is the node's ID.
string node_id = 2 [(gogoproto.customname) = "NodeID"];
string node_id = 2;
// Addr specifies the address of the member
string addr = 3;
@ -59,7 +59,7 @@ message JoinRequest {
message JoinResponse {
// RaftID is the ID assigned to the new member.
uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
uint64 raft_id = 1;
// Members is the membership set of the cluster.
repeated RaftMember members = 2;
@ -84,7 +84,7 @@ message ProcessRaftMessageResponse {}
message ResolveAddressRequest {
// raft_id is the ID to resolve to an address.
uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
uint64 raft_id = 1;
}
message ResolveAddressResponse {
@ -96,7 +96,7 @@ message ResolveAddressResponse {
// over the raft backend with a request ID to track when the
// action is effectively applied
message InternalRaftRequest {
uint64 id = 1 [(gogoproto.customname) = "ID"];
uint64 id = 1;
repeated StoreAction action = 2;
}

View file

@ -20,15 +20,15 @@ service ResourceAllocator {
message AttachNetworkRequest {
NetworkAttachmentConfig config = 1;
string container_id = 2 [(gogoproto.customname) = "ContainerID"];
string container_id = 2;
}
message AttachNetworkResponse {
string attachment_id = 1 [(gogoproto.customname) = "AttachmentID"];
string attachment_id = 1;
}
message DetachNetworkRequest {
string attachment_id = 1 [(gogoproto.customname) = "AttachmentID"];
string attachment_id = 1;
}
message DetachNetworkResponse {}

View file

@ -130,7 +130,7 @@ message TaskSpec {
message NetworkAttachmentSpec {
// ContainerID spcifies a unique ID of the container for which
// this attachment is for.
string container_id = 1 [(gogoproto.customname) = "ContainerID"];
string container_id = 1;
}

View file

@ -410,7 +410,7 @@ enum TaskState {
// Container specific status.
message ContainerStatus {
string container_id = 1 [(gogoproto.customname) = "ContainerID"];
string container_id = 1;
int32 pid = 2 [(gogoproto.customname) = "PID"];
int32 exit_code = 3;
@ -574,7 +574,7 @@ message IPAMOptions {
// Peer should be used anywhere where we are describing a remote peer.
message Peer {
string node_id = 1 [(gogoproto.customname) = "NodeID"];
string node_id = 1;
string addr = 2;
}
@ -787,7 +787,7 @@ message EncryptionKey {
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"];
uint64 raft_id = 1;
// Addr is the address advertised to raft.
string addr = 2;
@ -805,7 +805,7 @@ 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"];
string secret_id = 1;
// 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.

View file

@ -151,6 +151,25 @@ func (rca *RootCA) IssueAndSaveNewCertificates(kw KeyWriter, cn, ou, org string)
return &tlsKeyPair, nil
}
// Normally we can just call cert.Verify(opts), but since we actually want more information about
// whether a certificate is not yet valid or expired, we also need to perform the expiry checks ourselves.
func verifyCertificate(cert *x509.Certificate, opts x509.VerifyOptions, allowExpired bool) error {
_, err := cert.Verify(opts)
if invalidErr, ok := err.(x509.CertificateInvalidError); ok && invalidErr.Reason == x509.Expired {
now := time.Now().UTC()
if now.Before(cert.NotBefore) {
return errors.Wrapf(err, "certificate not valid before %s, and it is currently %s",
cert.NotBefore.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
}
if allowExpired {
return nil
}
return errors.Wrapf(err, "certificate expires at %s, and it is currently %s",
cert.NotAfter.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
}
return err
}
// RequestAndSaveNewCertificates gets new certificates issued, either by signing them locally if a signer is
// available, or by requesting them from the remote server at remoteAddr.
func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWriter, config CertificateRequestConfig) (*tls.Certificate, error) {
@ -199,7 +218,7 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWrit
Roots: rca.Pool,
}
// Check to see if this certificate was signed by our CA, and isn't expired
if _, err := X509Cert.Verify(opts); err != nil {
if err := verifyCertificate(X509Cert, opts, false); err != nil {
return nil, err
}

View file

@ -15,6 +15,7 @@ import (
"github.com/Sirupsen/logrus"
cfconfig "github.com/cloudflare/cfssl/config"
events "github.com/docker/go-events"
"github.com/docker/swarmkit/api"
"github.com/docker/swarmkit/connectionbroker"
"github.com/docker/swarmkit/identity"
@ -50,6 +51,13 @@ const (
base36DigestLen = 50
)
// RenewTLSExponentialBackoff sets the exponential backoff when trying to renew TLS certificates that have expired
var RenewTLSExponentialBackoff = events.ExponentialBackoffConfig{
Base: time.Second * 5,
Factor: time.Minute,
Max: 1 * time.Hour,
}
// SecurityConfig is used to represent a node's security configuration. It includes information about
// the RootCA and ServerTLSCreds/ClientTLSCreds transport authenticators to be used for MTLS
type SecurityConfig struct {
@ -189,7 +197,7 @@ func GenerateJoinToken(rootCA *RootCA) string {
func getCAHashFromToken(token string) (digest.Digest, error) {
split := strings.Split(token, "-")
if len(split) != 4 || split[0] != "SWMTKN" || split[1] != "1" {
if len(split) != 4 || split[0] != "SWMTKN" || split[1] != "1" || len(split[2]) != base36DigestLen || len(split[3]) != maxGeneratedSecretLength {
return "", errors.New("invalid join token")
}
@ -242,7 +250,7 @@ func DownloadRootCA(ctx context.Context, paths CertPaths, token string, connBrok
// LoadSecurityConfig loads TLS credentials from disk, or returns an error if
// these credentials do not exist or are unusable.
func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter) (*SecurityConfig, error) {
func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter, allowExpired bool) (*SecurityConfig, error) {
ctx = log.WithModule(ctx, "tls")
// At this point we've successfully loaded the CA details from disk, or
@ -273,7 +281,7 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter)
}
// Check to see if this certificate was signed by our CA, and isn't expired
if _, err := X509Cert.Verify(opts); err != nil {
if err := verifyCertificate(X509Cert, opts, allowExpired); err != nil {
return nil, err
}
@ -447,6 +455,7 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
go func() {
var retry time.Duration
expBackoff := events.NewExponentialBackoff(RenewTLSExponentialBackoff)
defer close(updates)
for {
ctx = log.WithModule(ctx, "tls")
@ -472,18 +481,12 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
return
}
} else {
// If we have an expired certificate, we let's stick with the starting default in
// the hope that this is a temporary clock skew.
// If we have an expired certificate, try to renew immediately: the hope that this is a temporary clock skew, or
// we can issue our own TLS certs.
if validUntil.Before(time.Now()) {
log.WithError(err).Errorf("failed to create a new client TLS config")
select {
case updates <- CertificateUpdate{Err: errors.New("TLS certificate is expired")}:
case <-ctx.Done():
log.Info("shutting down certificate renewal routine")
return
}
log.Warn("the current TLS certificate is expired, so an attempt to renew it will be made immediately")
// retry immediately(ish) with exponential backoff
retry = expBackoff.Proceed(nil)
} else {
// Random retry time between 50% and 80% of the total time to expiration
retry = calculateRandomExpiry(validFrom, validUntil)
@ -492,7 +495,7 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
log.WithFields(logrus.Fields{
"time": time.Now().Add(retry),
}).Debugf("next certificate renewal scheduled")
}).Debugf("next certificate renewal scheduled for %v from now", retry)
select {
case <-time.After(retry):
@ -508,8 +511,10 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
var certUpdate CertificateUpdate
if err := RenewTLSConfigNow(ctx, s, connBroker); err != nil {
certUpdate.Err = err
expBackoff.Failure(nil, nil)
} else {
certUpdate.Role = s.ClientTLSCreds.Role()
expBackoff = events.NewExponentialBackoff(RenewTLSExponentialBackoff)
}
select {

View file

@ -110,7 +110,7 @@ func validateContainerSpec(container *api.ContainerSpec) error {
return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided")
}
if _, err := reference.ParseNamed(container.Image); err != nil {
if _, err := reference.ParseNormalizedNamed(container.Image); err != nil {
return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image)
}
@ -275,6 +275,21 @@ func (s *Server) validateNetworks(networks []*api.NetworkAttachmentConfig) error
return nil
}
func validateMode(s *api.ServiceSpec) error {
m := s.GetMode()
switch m.(type) {
case *api.ServiceSpec_Replicated:
if int64(m.(*api.ServiceSpec_Replicated).Replicated.Replicas) < 0 {
return grpc.Errorf(codes.InvalidArgument, "Number of replicas must be non-negative")
}
case *api.ServiceSpec_Global:
default:
return grpc.Errorf(codes.InvalidArgument, "Unrecognized service mode")
}
return nil
}
func validateServiceSpec(spec *api.ServiceSpec) error {
if spec == nil {
return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
@ -291,6 +306,9 @@ func validateServiceSpec(spec *api.ServiceSpec) error {
if err := validateEndpointSpec(spec.Endpoint); err != nil {
return err
}
if err := validateMode(spec); err != nil {
return err
}
// Check to see if the Secret Reference portion of the spec is valid
if err := validateSecretRefsSpec(spec); err != nil {
return err

View file

@ -1,7 +1,6 @@
package logbroker
import (
"context"
"fmt"
"strings"
"sync"
@ -12,6 +11,7 @@ import (
"github.com/docker/swarmkit/manager/state"
"github.com/docker/swarmkit/manager/state/store"
"github.com/docker/swarmkit/watch"
"golang.org/x/net/context"
)
type subscription struct {

View file

@ -102,15 +102,15 @@ func (r *Orchestrator) reconcile(ctx context.Context, service *api.Service) {
}
deploy := service.Spec.GetMode().(*api.ServiceSpec_Replicated)
specifiedSlots := int(deploy.Replicated.Replicas)
specifiedSlots := deploy.Replicated.Replicas
switch {
case specifiedSlots > numSlots:
case specifiedSlots > uint64(numSlots):
log.G(ctx).Debugf("Service %s was scaled up from %d to %d instances", service.ID, numSlots, specifiedSlots)
// Update all current tasks then add missing tasks
r.updater.Update(ctx, r.cluster, service, slotsSlice)
_, err = r.store.Batch(func(batch *store.Batch) error {
r.addTasks(ctx, batch, service, runningSlots, deadSlots, specifiedSlots-numSlots)
r.addTasks(ctx, batch, service, runningSlots, deadSlots, specifiedSlots-uint64(numSlots))
r.deleteTasksMap(ctx, batch, deadSlots)
return nil
})
@ -118,7 +118,7 @@ func (r *Orchestrator) reconcile(ctx context.Context, service *api.Service) {
log.G(ctx).WithError(err).Errorf("reconcile batch failed")
}
case specifiedSlots < numSlots:
case specifiedSlots < uint64(numSlots):
// Update up to N tasks then remove the extra
log.G(ctx).Debugf("Service %s was scaled down from %d to %d instances", service.ID, numSlots, specifiedSlots)
@ -165,7 +165,7 @@ func (r *Orchestrator) reconcile(ctx context.Context, service *api.Service) {
log.G(ctx).WithError(err).Errorf("reconcile batch failed")
}
case specifiedSlots == numSlots:
case specifiedSlots == uint64(numSlots):
_, err = r.store.Batch(func(batch *store.Batch) error {
r.deleteTasksMap(ctx, batch, deadSlots)
return nil
@ -178,9 +178,9 @@ func (r *Orchestrator) reconcile(ctx context.Context, service *api.Service) {
}
}
func (r *Orchestrator) addTasks(ctx context.Context, batch *store.Batch, service *api.Service, runningSlots map[uint64]orchestrator.Slot, deadSlots map[uint64]orchestrator.Slot, count int) {
func (r *Orchestrator) addTasks(ctx context.Context, batch *store.Batch, service *api.Service, runningSlots map[uint64]orchestrator.Slot, deadSlots map[uint64]orchestrator.Slot, count uint64) {
slot := uint64(0)
for i := 0; i < count; i++ {
for i := uint64(0); i < count; i++ {
// Find a slot number that is missing a running task
for {
slot++

View file

@ -1193,9 +1193,13 @@ func (n *Node) ProcessRaftMessage(ctx context.Context, msg *api.ProcessRaftMessa
ctx, cancel := n.WithContext(ctx)
defer cancel()
if err := n.reportNewAddress(ctx, msg.Message.From); err != nil {
log.G(ctx).WithError(err).Errorf("failed to report new address of %x to transport", msg.Message.From)
}
// TODO(aaronl): Address changes are temporarily disabled.
// See https://github.com/docker/docker/issues/30455.
// This should be reenabled in the future with additional
// safeguards (perhaps storing multiple addresses per node).
//if err := n.reportNewAddress(ctx, msg.Message.From); err != nil {
// log.G(ctx).WithError(err).Errorf("failed to report new address of %x to transport", msg.Message.From)
//}
// Reject vote requests from unreachable peers
if msg.Message.Type == raftpb.MsgVote {

View file

@ -1,7 +1,6 @@
package storage
import (
"context"
"io"
"io/ioutil"
"os"
@ -15,6 +14,7 @@ import (
"github.com/docker/swarmkit/log"
"github.com/docker/swarmkit/manager/encryption"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
// This package wraps the github.com/coreos/etcd/wal package, and encrypts

View file

@ -568,7 +568,8 @@ func (n *Node) loadSecurityConfig(ctx context.Context) (*ca.SecurityConfig, erro
return nil, err
}
if err == nil {
securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw)
// if forcing a new cluster, we allow the certificates to be expired - a new set will be generated
securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
if err != nil {
_, isInvalidKEK := errors.Cause(err).(ca.ErrInvalidKEK)
if isInvalidKEK {
@ -606,7 +607,7 @@ func (n *Node) loadSecurityConfig(ctx context.Context) (*ca.SecurityConfig, erro
// - We wait for CreateSecurityConfig to finish since we need a certificate to operate.
// Attempt to load certificate from disk
securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw)
securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
if err == nil {
log.G(ctx).WithFields(logrus.Fields{
"node.id": securityConfig.ClientTLSCreds.NodeID(),