From 8b1c6bfe3d779c05917b08d3c0de03b78ce68672 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Fri, 27 Jan 2017 16:09:02 +0100 Subject: [PATCH] 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 --- cli/compose/convert/service.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/cli/compose/convert/service.go b/cli/compose/convert/service.go index f23df26127..a8613c0878 100644 --- a/cli/compose/convert/service.go +++ b/cli/compose/convert/service.go @@ -14,6 +14,7 @@ import ( "github.com/docker/docker/opts" runconfigopts "github.com/docker/docker/runconfig/opts" "github.com/docker/go-connections/nat" + "sort" ) // Services from compose-file types to engine API types @@ -110,9 +111,9 @@ func convertService( Command: service.Entrypoint, Args: service.Command, Hostname: service.Hostname, - Hosts: convertExtraHosts(service.ExtraHosts), + Hosts: sortStrings(convertExtraHosts(service.ExtraHosts)), Healthcheck: healthcheck, - Env: convertEnvironment(service.Environment), + Env: sortStrings(convertEnvironment(service.Environment)), Labels: AddStackLabel(namespace, service.Labels), Dir: service.WorkingDir, User: service.User, @@ -138,6 +139,17 @@ func convertService( return serviceSpec, nil } +func sortStrings(strs []string) []string { + sort.Strings(strs) + return strs +} + +type byNetworkTarget []swarm.NetworkAttachmentConfig + +func (a byNetworkTarget) Len() int { return len(a) } +func (a byNetworkTarget) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byNetworkTarget) Less(i, j int) bool { return a[i].Target < a[j].Target } + func convertServiceNetworks( networks map[string]*composetypes.ServiceNetworkConfig, networkConfigs networkMap, @@ -173,6 +185,8 @@ func convertServiceNetworks( Aliases: append(aliases, name), }) } + + sort.Sort(byNetworkTarget(nets)) return nets, nil } @@ -347,6 +361,12 @@ func convertResources(source composetypes.Resources) (*swarm.ResourceRequirement return resources, nil } +type byPublishedPort []swarm.PortConfig + +func (a byPublishedPort) Len() int { return len(a) } +func (a byPublishedPort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byPublishedPort) Less(i, j int) bool { return a[i].PublishedPort < a[j].PublishedPort } + func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) { portConfigs := []swarm.PortConfig{} ports, portBindings, err := nat.ParsePortSpecs(source) @@ -362,6 +382,7 @@ func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) { portConfigs = append(portConfigs, portConfig...) } + sort.Sort(byPublishedPort(portConfigs)) return &swarm.EndpointSpec{Ports: portConfigs}, nil }