@@ -4,8 +4,11 @@ import (
44 "encoding/json"
55 "fmt"
66 "io"
7+ "net"
78 "os"
89 "path/filepath"
10+ "strconv"
11+ "strings"
912 "sync"
1013 "syscall"
1114 "time"
@@ -23,14 +26,25 @@ import (
2326 "github.com/docker/docker/pkg/signal"
2427 "github.com/docker/docker/pkg/symlink"
2528 "github.com/docker/docker/runconfig"
29+ runconfigopts "github.com/docker/docker/runconfig/opts"
2630 "github.com/docker/docker/volume"
2731 containertypes "github.com/docker/engine-api/types/container"
32+ networktypes "github.com/docker/engine-api/types/network"
2833 "github.com/docker/go-connections/nat"
34+ "github.com/docker/libnetwork"
35+ "github.com/docker/libnetwork/netlabel"
36+ "github.com/docker/libnetwork/options"
37+ "github.com/docker/libnetwork/types"
2938 "github.com/opencontainers/runc/libcontainer/label"
3039)
3140
3241const configFileName = "config.v2.json"
3342
43+ var (
44+ errInvalidEndpoint = fmt .Errorf ("invalid endpoint while building port map info" )
45+ errInvalidNetwork = fmt .Errorf ("invalid network settings while building port map info" )
46+ )
47+
3448// CommonContainer holds the fields for a container which are
3549// applicable across all platforms supported by the daemon.
3650type CommonContainer struct {
@@ -581,6 +595,293 @@ func (container *Container) InitDNSHostConfig() {
581595 }
582596}
583597
598+ // GetEndpointInNetwork returns the container's endpoint to the provided network.
599+ func (container * Container ) GetEndpointInNetwork (n libnetwork.Network ) (libnetwork.Endpoint , error ) {
600+ endpointName := strings .TrimPrefix (container .Name , "/" )
601+ return n .EndpointByName (endpointName )
602+ }
603+
604+ func (container * Container ) buildPortMapInfo (ep libnetwork.Endpoint ) error {
605+ if ep == nil {
606+ return errInvalidEndpoint
607+ }
608+
609+ networkSettings := container .NetworkSettings
610+ if networkSettings == nil {
611+ return errInvalidNetwork
612+ }
613+
614+ if len (networkSettings .Ports ) == 0 {
615+ pm , err := getEndpointPortMapInfo (ep )
616+ if err != nil {
617+ return err
618+ }
619+ networkSettings .Ports = pm
620+ }
621+ return nil
622+ }
623+
624+ func getEndpointPortMapInfo (ep libnetwork.Endpoint ) (nat.PortMap , error ) {
625+ pm := nat.PortMap {}
626+ driverInfo , err := ep .DriverInfo ()
627+ if err != nil {
628+ return pm , err
629+ }
630+
631+ if driverInfo == nil {
632+ // It is not an error for epInfo to be nil
633+ return pm , nil
634+ }
635+
636+ if expData , ok := driverInfo [netlabel .ExposedPorts ]; ok {
637+ if exposedPorts , ok := expData .([]types.TransportPort ); ok {
638+ for _ , tp := range exposedPorts {
639+ natPort , err := nat .NewPort (tp .Proto .String (), strconv .Itoa (int (tp .Port )))
640+ if err != nil {
641+ return pm , fmt .Errorf ("Error parsing Port value(%v):%v" , tp .Port , err )
642+ }
643+ pm [natPort ] = nil
644+ }
645+ }
646+ }
647+
648+ mapData , ok := driverInfo [netlabel .PortMap ]
649+ if ! ok {
650+ return pm , nil
651+ }
652+
653+ if portMapping , ok := mapData .([]types.PortBinding ); ok {
654+ for _ , pp := range portMapping {
655+ natPort , err := nat .NewPort (pp .Proto .String (), strconv .Itoa (int (pp .Port )))
656+ if err != nil {
657+ return pm , err
658+ }
659+ natBndg := nat.PortBinding {HostIP : pp .HostIP .String (), HostPort : strconv .Itoa (int (pp .HostPort ))}
660+ pm [natPort ] = append (pm [natPort ], natBndg )
661+ }
662+ }
663+
664+ return pm , nil
665+ }
666+
667+ func getSandboxPortMapInfo (sb libnetwork.Sandbox ) nat.PortMap {
668+ pm := nat.PortMap {}
669+ if sb == nil {
670+ return pm
671+ }
672+
673+ for _ , ep := range sb .Endpoints () {
674+ pm , _ = getEndpointPortMapInfo (ep )
675+ if len (pm ) > 0 {
676+ break
677+ }
678+ }
679+ return pm
680+ }
681+
682+ // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
683+ func (container * Container ) BuildEndpointInfo (n libnetwork.Network , ep libnetwork.Endpoint ) error {
684+ if ep == nil {
685+ return errInvalidEndpoint
686+ }
687+
688+ networkSettings := container .NetworkSettings
689+ if networkSettings == nil {
690+ return errInvalidNetwork
691+ }
692+
693+ epInfo := ep .Info ()
694+ if epInfo == nil {
695+ // It is not an error to get an empty endpoint info
696+ return nil
697+ }
698+
699+ if _ , ok := networkSettings .Networks [n .Name ()]; ! ok {
700+ networkSettings .Networks [n .Name ()] = new (networktypes.EndpointSettings )
701+ }
702+ networkSettings .Networks [n .Name ()].NetworkID = n .ID ()
703+ networkSettings .Networks [n .Name ()].EndpointID = ep .ID ()
704+
705+ iface := epInfo .Iface ()
706+ if iface == nil {
707+ return nil
708+ }
709+
710+ if iface .MacAddress () != nil {
711+ networkSettings .Networks [n .Name ()].MacAddress = iface .MacAddress ().String ()
712+ }
713+
714+ if iface .Address () != nil {
715+ ones , _ := iface .Address ().Mask .Size ()
716+ networkSettings .Networks [n .Name ()].IPAddress = iface .Address ().IP .String ()
717+ networkSettings .Networks [n .Name ()].IPPrefixLen = ones
718+ }
719+
720+ if iface .AddressIPv6 () != nil && iface .AddressIPv6 ().IP .To16 () != nil {
721+ onesv6 , _ := iface .AddressIPv6 ().Mask .Size ()
722+ networkSettings .Networks [n .Name ()].GlobalIPv6Address = iface .AddressIPv6 ().IP .String ()
723+ networkSettings .Networks [n .Name ()].GlobalIPv6PrefixLen = onesv6
724+ }
725+
726+ return nil
727+ }
728+
729+ // UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
730+ func (container * Container ) UpdateJoinInfo (n libnetwork.Network , ep libnetwork.Endpoint ) error {
731+ if err := container .buildPortMapInfo (ep ); err != nil {
732+ return err
733+ }
734+
735+ epInfo := ep .Info ()
736+ if epInfo == nil {
737+ // It is not an error to get an empty endpoint info
738+ return nil
739+ }
740+ if epInfo .Gateway () != nil {
741+ container .NetworkSettings .Networks [n .Name ()].Gateway = epInfo .Gateway ().String ()
742+ }
743+ if epInfo .GatewayIPv6 ().To16 () != nil {
744+ container .NetworkSettings .Networks [n .Name ()].IPv6Gateway = epInfo .GatewayIPv6 ().String ()
745+ }
746+
747+ return nil
748+ }
749+
750+ // UpdateSandboxNetworkSettings updates the sandbox ID and Key.
751+ func (container * Container ) UpdateSandboxNetworkSettings (sb libnetwork.Sandbox ) error {
752+ container .NetworkSettings .SandboxID = sb .ID ()
753+ container .NetworkSettings .SandboxKey = sb .Key ()
754+ return nil
755+ }
756+
757+ // BuildJoinOptions builds endpoint Join options from a given network.
758+ func (container * Container ) BuildJoinOptions (n libnetwork.Network ) ([]libnetwork.EndpointOption , error ) {
759+ var joinOptions []libnetwork.EndpointOption
760+ if epConfig , ok := container .NetworkSettings .Networks [n .Name ()]; ok {
761+ for _ , str := range epConfig .Links {
762+ name , alias , err := runconfigopts .ParseLink (str )
763+ if err != nil {
764+ return nil , err
765+ }
766+ joinOptions = append (joinOptions , libnetwork .CreateOptionAlias (name , alias ))
767+ }
768+ }
769+ return joinOptions , nil
770+ }
771+
772+ // BuildCreateEndpointOptions builds endpoint options from a given network.
773+ func (container * Container ) BuildCreateEndpointOptions (n libnetwork.Network , epConfig * networktypes.EndpointSettings , sb libnetwork.Sandbox ) ([]libnetwork.EndpointOption , error ) {
774+ var (
775+ bindings = make (nat.PortMap )
776+ pbList []types.PortBinding
777+ exposeList []types.TransportPort
778+ createOptions []libnetwork.EndpointOption
779+ )
780+
781+ defaultNetName := runconfig .DefaultDaemonNetworkMode ().NetworkName ()
782+
783+ if n .Name () == defaultNetName || container .NetworkSettings .IsAnonymousEndpoint {
784+ createOptions = append (createOptions , libnetwork .CreateOptionAnonymous ())
785+ }
786+
787+ if epConfig != nil {
788+ ipam := epConfig .IPAMConfig
789+ if ipam != nil && (ipam .IPv4Address != "" || ipam .IPv6Address != "" ) {
790+ createOptions = append (createOptions ,
791+ libnetwork .CreateOptionIpam (net .ParseIP (ipam .IPv4Address ), net .ParseIP (ipam .IPv6Address ), nil ))
792+ }
793+
794+ for _ , alias := range epConfig .Aliases {
795+ createOptions = append (createOptions , libnetwork .CreateOptionMyAlias (alias ))
796+ }
797+ }
798+
799+ if ! containertypes .NetworkMode (n .Name ()).IsUserDefined () {
800+ createOptions = append (createOptions , libnetwork .CreateOptionDisableResolution ())
801+ }
802+
803+ // configs that are applicable only for the endpoint in the network
804+ // to which container was connected to on docker run.
805+ // Ideally all these network-specific endpoint configurations must be moved under
806+ // container.NetworkSettings.Networks[n.Name()]
807+ if n .Name () == container .HostConfig .NetworkMode .NetworkName () ||
808+ (n .Name () == defaultNetName && container .HostConfig .NetworkMode .IsDefault ()) {
809+ if container .Config .MacAddress != "" {
810+ mac , err := net .ParseMAC (container .Config .MacAddress )
811+ if err != nil {
812+ return nil , err
813+ }
814+
815+ genericOption := options.Generic {
816+ netlabel .MacAddress : mac ,
817+ }
818+
819+ createOptions = append (createOptions , libnetwork .EndpointOptionGeneric (genericOption ))
820+ }
821+ }
822+
823+ // Port-mapping rules belong to the container & applicable only to non-internal networks
824+ portmaps := getSandboxPortMapInfo (sb )
825+ if n .Info ().Internal () || len (portmaps ) > 0 {
826+ return createOptions , nil
827+ }
828+
829+ if container .HostConfig .PortBindings != nil {
830+ for p , b := range container .HostConfig .PortBindings {
831+ bindings [p ] = []nat.PortBinding {}
832+ for _ , bb := range b {
833+ bindings [p ] = append (bindings [p ], nat.PortBinding {
834+ HostIP : bb .HostIP ,
835+ HostPort : bb .HostPort ,
836+ })
837+ }
838+ }
839+ }
840+
841+ portSpecs := container .Config .ExposedPorts
842+ ports := make ([]nat.Port , len (portSpecs ))
843+ var i int
844+ for p := range portSpecs {
845+ ports [i ] = p
846+ i ++
847+ }
848+ nat .SortPortMap (ports , bindings )
849+ for _ , port := range ports {
850+ expose := types.TransportPort {}
851+ expose .Proto = types .ParseProtocol (port .Proto ())
852+ expose .Port = uint16 (port .Int ())
853+ exposeList = append (exposeList , expose )
854+
855+ pb := types.PortBinding {Port : expose .Port , Proto : expose .Proto }
856+ binding := bindings [port ]
857+ for i := 0 ; i < len (binding ); i ++ {
858+ pbCopy := pb .GetCopy ()
859+ newP , err := nat .NewPort (nat .SplitProtoPort (binding [i ].HostPort ))
860+ var portStart , portEnd int
861+ if err == nil {
862+ portStart , portEnd , err = newP .Range ()
863+ }
864+ if err != nil {
865+ return nil , fmt .Errorf ("Error parsing HostPort value(%s):%v" , binding [i ].HostPort , err )
866+ }
867+ pbCopy .HostPort = uint16 (portStart )
868+ pbCopy .HostPortEnd = uint16 (portEnd )
869+ pbCopy .HostIP = net .ParseIP (binding [i ].HostIP )
870+ pbList = append (pbList , pbCopy )
871+ }
872+
873+ if container .HostConfig .PublishAllPorts && len (binding ) == 0 {
874+ pbList = append (pbList , pb )
875+ }
876+ }
877+
878+ createOptions = append (createOptions ,
879+ libnetwork .CreateOptionPortMapping (pbList ),
880+ libnetwork .CreateOptionExposedPorts (exposeList ))
881+
882+ return createOptions , nil
883+ }
884+
584885// UpdateMonitor updates monitor configure for running container
585886func (container * Container ) UpdateMonitor (restartPolicy containertypes.RestartPolicy ) {
586887 monitor := container .monitor
0 commit comments