Re vendor swarmkit for 17.05.x
| ... | ... |
@@ -145,6 +145,25 @@ func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *check.C) {
|
| 145 | 145 |
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive) |
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 |
+func (s *DockerSwarmSuite) TestUpdateSwarmAddExternalCA(c *check.C) {
|
|
| 149 |
+ // TODO: when root rotation is in, convert to a series of root rotation tests instead. |
|
| 150 |
+ // currently just makes sure that we don't have to provide a CA certificate when |
|
| 151 |
+ // providing an external CA |
|
| 152 |
+ d1 := s.AddDaemon(c, false, false) |
|
| 153 |
+ c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
|
|
| 154 |
+ d1.UpdateSwarm(c, func(s *swarm.Spec) {
|
|
| 155 |
+ s.CAConfig.ExternalCAs = []*swarm.ExternalCA{
|
|
| 156 |
+ {
|
|
| 157 |
+ Protocol: swarm.ExternalCAProtocolCFSSL, |
|
| 158 |
+ URL: "https://thishasnoca.org", |
|
| 159 |
+ }, |
|
| 160 |
+ } |
|
| 161 |
+ }) |
|
| 162 |
+ info, err := d1.SwarmInfo() |
|
| 163 |
+ c.Assert(err, checker.IsNil) |
|
| 164 |
+ c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs, checker.HasLen, 1) |
|
| 165 |
+} |
|
| 166 |
+ |
|
| 148 | 167 |
func (s *DockerSwarmSuite) TestAPISwarmCAHash(c *check.C) {
|
| 149 | 168 |
d1 := s.AddDaemon(c, true, true) |
| 150 | 169 |
d2 := s.AddDaemon(c, false, false) |
| ... | ... |
@@ -50,6 +50,13 @@ func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
|
| 50 | 50 |
c.Assert(out, checker.Contains, "minimum certificate expiry time") |
| 51 | 51 |
spec = getSpec() |
| 52 | 52 |
c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) |
| 53 |
+ |
|
| 54 |
+ // passing an external CA (this is without starting a root rotation) does not fail |
|
| 55 |
+ out, err = d.Cmd("swarm", "update", "--external-ca", "protocol=cfssl,url=https://something.org")
|
|
| 56 |
+ c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
|
|
| 57 |
+ |
|
| 58 |
+ spec = getSpec() |
|
| 59 |
+ c.Assert(spec.CAConfig.ExternalCAs, checker.HasLen, 1) |
|
| 53 | 60 |
} |
| 54 | 61 |
|
| 55 | 62 |
func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
|
| ... | ... |
@@ -60,12 +67,14 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
|
| 60 | 60 |
return sw.Spec |
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 |
- cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s"),
|
|
| 63 |
+ cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s",
|
|
| 64 |
+ "--external-ca", "protocol=cfssl,url=https://something.org"), |
|
| 64 | 65 |
cli.Daemon(d.Daemon)).Assert(c, icmd.Success) |
| 65 | 66 |
|
| 66 | 67 |
spec := getSpec() |
| 67 | 68 |
c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour) |
| 68 | 69 |
c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second) |
| 70 |
+ c.Assert(spec.CAConfig.ExternalCAs, checker.HasLen, 1) |
|
| 69 | 71 |
|
| 70 | 72 |
c.Assert(d.Leave(true), checker.IsNil) |
| 71 | 73 |
time.Sleep(500 * time.Millisecond) // https://github.com/docker/swarmkit/issues/1421 |
| ... | ... |
@@ -105,7 +105,7 @@ github.com/docker/containerd 9048e5e50717ea4497b757314bad98ea3763c145 |
| 105 | 105 |
github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4 |
| 106 | 106 |
|
| 107 | 107 |
# cluster |
| 108 |
-github.com/docker/swarmkit d5232280c510d70755ab11305d46a5704735371a |
|
| 108 |
+github.com/docker/swarmkit 6a6f38c02f1c96b1d3c548e45927349656ae37a1 |
|
| 109 | 109 |
github.com/gogo/protobuf 8d70fb3182befc465c4a1eac8ad4d38ff49778e2 |
| 110 | 110 |
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a |
| 111 | 111 |
github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e |
| ... | ... |
@@ -148,14 +148,16 @@ func validateHasAtLeastOneExternalCA(ctx context.Context, externalCAs map[string |
| 148 | 148 |
|
| 149 | 149 |
// validates that the list of external CAs have valid certs associated with them, and produce a mapping of subject/pubkey:external |
| 150 | 150 |
// for later validation of required external CAs |
| 151 |
-func getNormalizedExtCAs(caConfig *api.CAConfig) (map[string][]*api.ExternalCA, error) {
|
|
| 151 |
+func getNormalizedExtCAs(caConfig *api.CAConfig, normalizedCurrentRootCACert []byte) (map[string][]*api.ExternalCA, error) {
|
|
| 152 | 152 |
extCAs := make(map[string][]*api.ExternalCA) |
| 153 | 153 |
|
| 154 | 154 |
for _, extCA := range caConfig.ExternalCAs {
|
| 155 |
- if len(extCA.CACert) == 0 {
|
|
| 156 |
- return nil, grpc.Errorf(codes.InvalidArgument, "must specify CA certificate for each external CA") |
|
| 155 |
+ associatedCert := normalizedCurrentRootCACert |
|
| 156 |
+ // if no associated cert is provided, assume it's the current root cert |
|
| 157 |
+ if len(extCA.CACert) > 0 {
|
|
| 158 |
+ associatedCert = ca.NormalizePEMs(extCA.CACert) |
|
| 157 | 159 |
} |
| 158 |
- certKey := string(ca.NormalizePEMs(extCA.CACert)) |
|
| 160 |
+ certKey := string(associatedCert) |
|
| 159 | 161 |
extCAs[certKey] = append(extCAs[certKey], extCA) |
| 160 | 162 |
} |
| 161 | 163 |
|
| ... | ... |
@@ -191,12 +193,12 @@ func validateCAConfig(ctx context.Context, securityConfig *ca.SecurityConfig, cl |
| 191 | 191 |
return nil, grpc.Errorf(codes.InvalidArgument, "if a signing CA key is provided, the signing CA cert must also be provided") |
| 192 | 192 |
} |
| 193 | 193 |
|
| 194 |
- extCAs, err := getNormalizedExtCAs(newConfig) // validate that the list of external CAs is not malformed |
|
| 194 |
+ normalizedRootCA := ca.NormalizePEMs(cluster.RootCA.CACert) |
|
| 195 |
+ extCAs, err := getNormalizedExtCAs(newConfig, normalizedRootCA) // validate that the list of external CAs is not malformed |
|
| 195 | 196 |
if err != nil {
|
| 196 | 197 |
return nil, err |
| 197 | 198 |
} |
| 198 | 199 |
|
| 199 |
- normalizedRootCA := ca.NormalizePEMs(cluster.RootCA.CACert) |
|
| 200 | 200 |
var oldCertExtCAs []*api.ExternalCA |
| 201 | 201 |
if !hasSigningKey(&cluster.RootCA) {
|
| 202 | 202 |
oldCertExtCAs, err = validateHasAtLeastOneExternalCA(ctx, extCAs, securityConfig, normalizedRootCA, "current") |
| ... | ... |
@@ -297,8 +297,9 @@ func (g *Orchestrator) reconcileServices(ctx context.Context, serviceIDs []strin |
| 297 | 297 |
updates := make(map[*api.Service][]orchestrator.Slot) |
| 298 | 298 |
|
| 299 | 299 |
_, err := g.store.Batch(func(batch *store.Batch) error {
|
| 300 |
- var updateTasks []orchestrator.Slot |
|
| 301 | 300 |
for _, serviceID := range serviceIDs {
|
| 301 |
+ var updateTasks []orchestrator.Slot |
|
| 302 |
+ |
|
| 302 | 303 |
if _, exists := nodeTasks[serviceID]; !exists {
|
| 303 | 304 |
continue |
| 304 | 305 |
} |
| ... | ... |
@@ -352,7 +353,6 @@ func (g *Orchestrator) reconcileServices(ctx context.Context, serviceIDs []strin |
| 352 | 352 |
for service, updateTasks := range updates {
|
| 353 | 353 |
g.updater.Update(ctx, g.cluster, service, updateTasks) |
| 354 | 354 |
} |
| 355 |
- |
|
| 356 | 355 |
} |
| 357 | 356 |
|
| 358 | 357 |
// updateNode updates g.nodes based on the current node value |