@@ -13,6 +13,7 @@ import (
13
13
"net"
14
14
"net/http"
15
15
"net/url"
16
+ "strconv"
16
17
"strings"
17
18
"sync"
18
19
"time"
@@ -468,7 +469,7 @@ func (e *Engine) EngineToContainerNode() *types.ContainerNode {
468
469
func (e * Engine ) updateClientVersionFromServer (serverVersion string ) {
469
470
// v will be >= 1.8, since this is checked earlier
470
471
// for server/API version reference, check https://docs.docker.com/engine/api/
471
- // new versions of Docker look like 17.06-ce etc.
472
+ // new versions of Docker look like 17.06.x -ce etc.
472
473
s := strings .Split (serverVersion , "-" )
473
474
serverVersion = s [0 ]
474
475
@@ -485,7 +486,7 @@ func (e *Engine) updateClientVersionFromServer(serverVersion string) {
485
486
e .apiClient .UpdateClientVersion ("1.24" )
486
487
case versions .LessThan (serverVersion , "1.13.1" ):
487
488
e .apiClient .UpdateClientVersion ("1.25" )
488
- case versions .LessThan (serverVersion , "17.03.1" ) || serverVersion == "1.13.1" :
489
+ case versions .LessThan (serverVersion , "17.03.1" ) || versions . Equal ( serverVersion , "1.13.1" ) :
489
490
e .apiClient .UpdateClientVersion ("1.26" )
490
491
case versions .LessThan (serverVersion , "17.04" ):
491
492
e .apiClient .UpdateClientVersion ("1.27" )
@@ -945,13 +946,93 @@ func (e *Engine) refreshLoop() {
945
946
e .RefreshVolumes ()
946
947
e .RefreshNetworks ()
947
948
e .RefreshImages ()
948
- log .WithFields (log.Fields {"id" : e .ID , "name" : e .Name }).Debugf ("Engine update succeeded" )
949
+ err := e .UpdateNetworkContainers ("" , false )
950
+ if err != nil {
951
+ log .WithFields (log.Fields {"id" : e .ID , "name" : e .Name }).Debugf ("Engine refresh succeeded, but network containers update failed: %s" , err .Error ())
952
+ } else {
953
+ log .WithFields (log.Fields {"id" : e .ID , "name" : e .Name }).Debugf ("Engine update succeeded" )
954
+ }
949
955
} else {
950
956
log .WithFields (log.Fields {"id" : e .ID , "name" : e .Name }).Debugf ("Engine refresh failed" )
951
957
}
952
958
}
953
959
}
954
960
961
+ // UpdateNetworkContainers updates the list of containers attached to each network.
962
+ // This is required because the RefreshNetworks uses NetworkList which has stopped
963
+ // returning this information for recent API versions. Note that the container cache
964
+ // is used to obtain this information, which means that if the container cache isn't
965
+ // up to date for whatever reason, then the network information might be out of date
966
+ // as well. This needs to be considered while designing networking related functionality.
967
+ // Ideally, this function should only be used in the refresh loop, and called AFTER
968
+ // RefreshNetworks() because RefreshNetworks() will not populate network information
969
+ // correctly if container refresh hasn't taken place
970
+
971
+ // The containerID argument can be provided along with a full argument can be used to
972
+ // limit the update as it concerns only one container instead of doing it for all
973
+ // containers. The idea is that sometimes only things about one container may have
974
+ // changed, and we don't need to run the loop over all containers.
975
+ func (e * Engine ) UpdateNetworkContainers (containerID string , full bool ) error {
976
+ containerMap := make (map [string ]* Container )
977
+ if containerID != "" {
978
+ ctr , err := e .refreshContainer (containerID , full )
979
+ if err != nil {
980
+ return err
981
+ }
982
+ containerMap [containerID ] = ctr
983
+ }
984
+
985
+ e .Lock ()
986
+ defer e .Unlock ()
987
+
988
+ // if a specific container is not being targeted, then an update for all containers
989
+ // will take place
990
+ if containerID == "" {
991
+ containerMap = e .containers
992
+ }
993
+
994
+ for _ , c := range containerMap {
995
+ if c .NetworkSettings == nil {
996
+ continue
997
+ }
998
+ for _ , n := range c .NetworkSettings .Networks {
999
+ if engineNetwork , ok := e .networks [n .NetworkID ]; ok {
1000
+ // extract container name
1001
+ ctrName := ""
1002
+ if len (c .Names ) != 0 {
1003
+ if s := strings .Split (c .Names [0 ], "/" ); len (s ) > 1 {
1004
+ ctrName = s [1 ]
1005
+ } else {
1006
+ ctrName = s [0 ]
1007
+ }
1008
+ }
1009
+ // extract ip addresses
1010
+ ipv4address := ""
1011
+ ipv6address := ""
1012
+ if n .IPAddress != "" {
1013
+ ipv4address = n .IPAddress + "/" + strconv .Itoa (n .IPPrefixLen )
1014
+ }
1015
+ if n .GlobalIPv6Address != "" {
1016
+ ipv6address = n .GlobalIPv6Address + "/" + strconv .Itoa (n .GlobalIPv6PrefixLen )
1017
+ }
1018
+ // udpate network information
1019
+ engineNetwork .Containers [c .ID ] = types.EndpointResource {
1020
+ Name : ctrName ,
1021
+ EndpointID : n .EndpointID ,
1022
+ MacAddress : n .MacAddress ,
1023
+ IPv4Address : ipv4address ,
1024
+ IPv6Address : ipv6address ,
1025
+ }
1026
+ } else {
1027
+ // it shouldn't be the case that a network which a container is connected to wasn't
1028
+ // even listed. Return an error when that happens.
1029
+ return fmt .Errorf ("container %s connected to network %s but the network wasn't listed in the refresh loop" , c .ID , n .NetworkID )
1030
+ }
1031
+ }
1032
+ }
1033
+ return nil
1034
+ }
1035
+
955
1036
func (e * Engine ) emitEvent (event string ) {
956
1037
// If there is no event handler registered, abort right now.
957
1038
if e .eventHandler == nil {
@@ -1306,6 +1387,7 @@ func (e *Engine) String() string {
1306
1387
1307
1388
func (e * Engine ) handler (msg events.Message ) error {
1308
1389
// Something changed - refresh our internal state.
1390
+ // TODO(nishanttotla): Possibly container events should trigger a container refresh
1309
1391
1310
1392
switch msg .Type {
1311
1393
case "network" :
@@ -1531,8 +1613,11 @@ func (e *Engine) NetworkDisconnect(container *Container, network string, force b
1531
1613
if err != nil {
1532
1614
return err
1533
1615
}
1534
-
1535
- return e .RefreshNetworks ()
1616
+ err = e .RefreshNetworks ()
1617
+ if err != nil {
1618
+ return err
1619
+ }
1620
+ return e .UpdateNetworkContainers (container .ID , true )
1536
1621
}
1537
1622
1538
1623
//IsConnectionError returns true when err is connection problem
0 commit comments