Browse code

Make docker stack deploy a little bit more indempotent

Sort some slice fields before sending them to the swarm api so that it
won't trigger an update.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>

Vincent Demeester authored on 2016/12/28 01:39:24
Showing 1 changed files
... ...
@@ -2,6 +2,7 @@ package convert
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"sort"
5 6
 	"time"
6 7
 
7 8
 	"github.com/docker/docker/api/types/container"
... ...
@@ -98,9 +99,9 @@ func convertService(
98 98
 				Command:         service.Entrypoint,
99 99
 				Args:            service.Command,
100 100
 				Hostname:        service.Hostname,
101
-				Hosts:           convertExtraHosts(service.ExtraHosts),
101
+				Hosts:           sortStrings(convertExtraHosts(service.ExtraHosts)),
102 102
 				Healthcheck:     healthcheck,
103
-				Env:             convertEnvironment(service.Environment),
103
+				Env:             sortStrings(convertEnvironment(service.Environment)),
104 104
 				Labels:          AddStackLabel(namespace, service.Labels),
105 105
 				Dir:             service.WorkingDir,
106 106
 				User:            service.User,
... ...
@@ -125,6 +126,17 @@ func convertService(
125 125
 	return serviceSpec, nil
126 126
 }
127 127
 
128
+func sortStrings(strs []string) []string {
129
+	sort.Strings(strs)
130
+	return strs
131
+}
132
+
133
+type byNetworkTarget []swarm.NetworkAttachmentConfig
134
+
135
+func (a byNetworkTarget) Len() int           { return len(a) }
136
+func (a byNetworkTarget) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
137
+func (a byNetworkTarget) Less(i, j int) bool { return a[i].Target < a[j].Target }
138
+
128 139
 func convertServiceNetworks(
129 140
 	networks map[string]*composetypes.ServiceNetworkConfig,
130 141
 	networkConfigs networkMap,
... ...
@@ -160,6 +172,9 @@ func convertServiceNetworks(
160 160
 			Aliases: append(aliases, name),
161 161
 		})
162 162
 	}
163
+
164
+	sort.Sort(byNetworkTarget(nets))
165
+
163 166
 	return nets, nil
164 167
 }
165 168
 
... ...
@@ -294,6 +309,12 @@ func convertResources(source composetypes.Resources) (*swarm.ResourceRequirement
294 294
 
295 295
 }
296 296
 
297
+type byPublishedPort []swarm.PortConfig
298
+
299
+func (a byPublishedPort) Len() int           { return len(a) }
300
+func (a byPublishedPort) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
301
+func (a byPublishedPort) Less(i, j int) bool { return a[i].PublishedPort < a[j].PublishedPort }
302
+
297 303
 func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) {
298 304
 	portConfigs := []swarm.PortConfig{}
299 305
 	ports, portBindings, err := nat.ParsePortSpecs(source)
... ...
@@ -307,6 +328,9 @@ func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) {
307 307
 			opts.ConvertPortToPortConfig(port, portBindings)...)
308 308
 	}
309 309
 
310
+	// Sorting to make sure these are always in the same order
311
+	sort.Sort(byPublishedPort(portConfigs))
312
+
310 313
 	return &swarm.EndpointSpec{Ports: portConfigs}, nil
311 314
 }
312 315