Signed-off-by: msabansal <sabansal@microsoft.com>
msabansal authored on 2016/03/10 13:33:21... | ... |
@@ -4,8 +4,11 @@ import ( |
4 | 4 |
"encoding/json" |
5 | 5 |
"fmt" |
6 | 6 |
"io" |
7 |
+ "net" |
|
7 | 8 |
"os" |
8 | 9 |
"path/filepath" |
10 |
+ "strconv" |
|
11 |
+ "strings" |
|
9 | 12 |
"sync" |
10 | 13 |
"syscall" |
11 | 14 |
"time" |
... | ... |
@@ -23,14 +26,25 @@ import ( |
23 | 23 |
"github.com/docker/docker/pkg/signal" |
24 | 24 |
"github.com/docker/docker/pkg/symlink" |
25 | 25 |
"github.com/docker/docker/runconfig" |
26 |
+ runconfigopts "github.com/docker/docker/runconfig/opts" |
|
26 | 27 |
"github.com/docker/docker/volume" |
27 | 28 |
containertypes "github.com/docker/engine-api/types/container" |
29 |
+ networktypes "github.com/docker/engine-api/types/network" |
|
28 | 30 |
"github.com/docker/go-connections/nat" |
31 |
+ "github.com/docker/libnetwork" |
|
32 |
+ "github.com/docker/libnetwork/netlabel" |
|
33 |
+ "github.com/docker/libnetwork/options" |
|
34 |
+ "github.com/docker/libnetwork/types" |
|
29 | 35 |
"github.com/opencontainers/runc/libcontainer/label" |
30 | 36 |
) |
31 | 37 |
|
32 | 38 |
const configFileName = "config.v2.json" |
33 | 39 |
|
40 |
+var ( |
|
41 |
+ errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info") |
|
42 |
+ errInvalidNetwork = fmt.Errorf("invalid network settings while building port map info") |
|
43 |
+) |
|
44 |
+ |
|
34 | 45 |
// CommonContainer holds the fields for a container which are |
35 | 46 |
// applicable across all platforms supported by the daemon. |
36 | 47 |
type CommonContainer struct { |
... | ... |
@@ -581,6 +595,293 @@ func (container *Container) InitDNSHostConfig() { |
581 | 581 |
} |
582 | 582 |
} |
583 | 583 |
|
584 |
+// GetEndpointInNetwork returns the container's endpoint to the provided network. |
|
585 |
+func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) { |
|
586 |
+ endpointName := strings.TrimPrefix(container.Name, "/") |
|
587 |
+ return n.EndpointByName(endpointName) |
|
588 |
+} |
|
589 |
+ |
|
590 |
+func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error { |
|
591 |
+ if ep == nil { |
|
592 |
+ return errInvalidEndpoint |
|
593 |
+ } |
|
594 |
+ |
|
595 |
+ networkSettings := container.NetworkSettings |
|
596 |
+ if networkSettings == nil { |
|
597 |
+ return errInvalidNetwork |
|
598 |
+ } |
|
599 |
+ |
|
600 |
+ if len(networkSettings.Ports) == 0 { |
|
601 |
+ pm, err := getEndpointPortMapInfo(ep) |
|
602 |
+ if err != nil { |
|
603 |
+ return err |
|
604 |
+ } |
|
605 |
+ networkSettings.Ports = pm |
|
606 |
+ } |
|
607 |
+ return nil |
|
608 |
+} |
|
609 |
+ |
|
610 |
+func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) { |
|
611 |
+ pm := nat.PortMap{} |
|
612 |
+ driverInfo, err := ep.DriverInfo() |
|
613 |
+ if err != nil { |
|
614 |
+ return pm, err |
|
615 |
+ } |
|
616 |
+ |
|
617 |
+ if driverInfo == nil { |
|
618 |
+ // It is not an error for epInfo to be nil |
|
619 |
+ return pm, nil |
|
620 |
+ } |
|
621 |
+ |
|
622 |
+ if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { |
|
623 |
+ if exposedPorts, ok := expData.([]types.TransportPort); ok { |
|
624 |
+ for _, tp := range exposedPorts { |
|
625 |
+ natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) |
|
626 |
+ if err != nil { |
|
627 |
+ return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err) |
|
628 |
+ } |
|
629 |
+ pm[natPort] = nil |
|
630 |
+ } |
|
631 |
+ } |
|
632 |
+ } |
|
633 |
+ |
|
634 |
+ mapData, ok := driverInfo[netlabel.PortMap] |
|
635 |
+ if !ok { |
|
636 |
+ return pm, nil |
|
637 |
+ } |
|
638 |
+ |
|
639 |
+ if portMapping, ok := mapData.([]types.PortBinding); ok { |
|
640 |
+ for _, pp := range portMapping { |
|
641 |
+ natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) |
|
642 |
+ if err != nil { |
|
643 |
+ return pm, err |
|
644 |
+ } |
|
645 |
+ natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} |
|
646 |
+ pm[natPort] = append(pm[natPort], natBndg) |
|
647 |
+ } |
|
648 |
+ } |
|
649 |
+ |
|
650 |
+ return pm, nil |
|
651 |
+} |
|
652 |
+ |
|
653 |
+func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap { |
|
654 |
+ pm := nat.PortMap{} |
|
655 |
+ if sb == nil { |
|
656 |
+ return pm |
|
657 |
+ } |
|
658 |
+ |
|
659 |
+ for _, ep := range sb.Endpoints() { |
|
660 |
+ pm, _ = getEndpointPortMapInfo(ep) |
|
661 |
+ if len(pm) > 0 { |
|
662 |
+ break |
|
663 |
+ } |
|
664 |
+ } |
|
665 |
+ return pm |
|
666 |
+} |
|
667 |
+ |
|
668 |
+// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint. |
|
669 |
+func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { |
|
670 |
+ if ep == nil { |
|
671 |
+ return errInvalidEndpoint |
|
672 |
+ } |
|
673 |
+ |
|
674 |
+ networkSettings := container.NetworkSettings |
|
675 |
+ if networkSettings == nil { |
|
676 |
+ return errInvalidNetwork |
|
677 |
+ } |
|
678 |
+ |
|
679 |
+ epInfo := ep.Info() |
|
680 |
+ if epInfo == nil { |
|
681 |
+ // It is not an error to get an empty endpoint info |
|
682 |
+ return nil |
|
683 |
+ } |
|
684 |
+ |
|
685 |
+ if _, ok := networkSettings.Networks[n.Name()]; !ok { |
|
686 |
+ networkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings) |
|
687 |
+ } |
|
688 |
+ networkSettings.Networks[n.Name()].NetworkID = n.ID() |
|
689 |
+ networkSettings.Networks[n.Name()].EndpointID = ep.ID() |
|
690 |
+ |
|
691 |
+ iface := epInfo.Iface() |
|
692 |
+ if iface == nil { |
|
693 |
+ return nil |
|
694 |
+ } |
|
695 |
+ |
|
696 |
+ if iface.MacAddress() != nil { |
|
697 |
+ networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String() |
|
698 |
+ } |
|
699 |
+ |
|
700 |
+ if iface.Address() != nil { |
|
701 |
+ ones, _ := iface.Address().Mask.Size() |
|
702 |
+ networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String() |
|
703 |
+ networkSettings.Networks[n.Name()].IPPrefixLen = ones |
|
704 |
+ } |
|
705 |
+ |
|
706 |
+ if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { |
|
707 |
+ onesv6, _ := iface.AddressIPv6().Mask.Size() |
|
708 |
+ networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String() |
|
709 |
+ networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6 |
|
710 |
+ } |
|
711 |
+ |
|
712 |
+ return nil |
|
713 |
+} |
|
714 |
+ |
|
715 |
+// UpdateJoinInfo updates network settings when container joins network n with endpoint ep. |
|
716 |
+func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { |
|
717 |
+ if err := container.buildPortMapInfo(ep); err != nil { |
|
718 |
+ return err |
|
719 |
+ } |
|
720 |
+ |
|
721 |
+ epInfo := ep.Info() |
|
722 |
+ if epInfo == nil { |
|
723 |
+ // It is not an error to get an empty endpoint info |
|
724 |
+ return nil |
|
725 |
+ } |
|
726 |
+ if epInfo.Gateway() != nil { |
|
727 |
+ container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() |
|
728 |
+ } |
|
729 |
+ if epInfo.GatewayIPv6().To16() != nil { |
|
730 |
+ container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() |
|
731 |
+ } |
|
732 |
+ |
|
733 |
+ return nil |
|
734 |
+} |
|
735 |
+ |
|
736 |
+// UpdateSandboxNetworkSettings updates the sandbox ID and Key. |
|
737 |
+func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error { |
|
738 |
+ container.NetworkSettings.SandboxID = sb.ID() |
|
739 |
+ container.NetworkSettings.SandboxKey = sb.Key() |
|
740 |
+ return nil |
|
741 |
+} |
|
742 |
+ |
|
743 |
+// BuildJoinOptions builds endpoint Join options from a given network. |
|
744 |
+func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) { |
|
745 |
+ var joinOptions []libnetwork.EndpointOption |
|
746 |
+ if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok { |
|
747 |
+ for _, str := range epConfig.Links { |
|
748 |
+ name, alias, err := runconfigopts.ParseLink(str) |
|
749 |
+ if err != nil { |
|
750 |
+ return nil, err |
|
751 |
+ } |
|
752 |
+ joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias)) |
|
753 |
+ } |
|
754 |
+ } |
|
755 |
+ return joinOptions, nil |
|
756 |
+} |
|
757 |
+ |
|
758 |
+// BuildCreateEndpointOptions builds endpoint options from a given network. |
|
759 |
+func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) { |
|
760 |
+ var ( |
|
761 |
+ bindings = make(nat.PortMap) |
|
762 |
+ pbList []types.PortBinding |
|
763 |
+ exposeList []types.TransportPort |
|
764 |
+ createOptions []libnetwork.EndpointOption |
|
765 |
+ ) |
|
766 |
+ |
|
767 |
+ defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() |
|
768 |
+ |
|
769 |
+ if n.Name() == defaultNetName || container.NetworkSettings.IsAnonymousEndpoint { |
|
770 |
+ createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) |
|
771 |
+ } |
|
772 |
+ |
|
773 |
+ if epConfig != nil { |
|
774 |
+ ipam := epConfig.IPAMConfig |
|
775 |
+ if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") { |
|
776 |
+ createOptions = append(createOptions, |
|
777 |
+ libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil)) |
|
778 |
+ } |
|
779 |
+ |
|
780 |
+ for _, alias := range epConfig.Aliases { |
|
781 |
+ createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) |
|
782 |
+ } |
|
783 |
+ } |
|
784 |
+ |
|
785 |
+ if !containertypes.NetworkMode(n.Name()).IsUserDefined() { |
|
786 |
+ createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) |
|
787 |
+ } |
|
788 |
+ |
|
789 |
+ // configs that are applicable only for the endpoint in the network |
|
790 |
+ // to which container was connected to on docker run. |
|
791 |
+ // Ideally all these network-specific endpoint configurations must be moved under |
|
792 |
+ // container.NetworkSettings.Networks[n.Name()] |
|
793 |
+ if n.Name() == container.HostConfig.NetworkMode.NetworkName() || |
|
794 |
+ (n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) { |
|
795 |
+ if container.Config.MacAddress != "" { |
|
796 |
+ mac, err := net.ParseMAC(container.Config.MacAddress) |
|
797 |
+ if err != nil { |
|
798 |
+ return nil, err |
|
799 |
+ } |
|
800 |
+ |
|
801 |
+ genericOption := options.Generic{ |
|
802 |
+ netlabel.MacAddress: mac, |
|
803 |
+ } |
|
804 |
+ |
|
805 |
+ createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) |
|
806 |
+ } |
|
807 |
+ } |
|
808 |
+ |
|
809 |
+ // Port-mapping rules belong to the container & applicable only to non-internal networks |
|
810 |
+ portmaps := getSandboxPortMapInfo(sb) |
|
811 |
+ if n.Info().Internal() || len(portmaps) > 0 { |
|
812 |
+ return createOptions, nil |
|
813 |
+ } |
|
814 |
+ |
|
815 |
+ if container.HostConfig.PortBindings != nil { |
|
816 |
+ for p, b := range container.HostConfig.PortBindings { |
|
817 |
+ bindings[p] = []nat.PortBinding{} |
|
818 |
+ for _, bb := range b { |
|
819 |
+ bindings[p] = append(bindings[p], nat.PortBinding{ |
|
820 |
+ HostIP: bb.HostIP, |
|
821 |
+ HostPort: bb.HostPort, |
|
822 |
+ }) |
|
823 |
+ } |
|
824 |
+ } |
|
825 |
+ } |
|
826 |
+ |
|
827 |
+ portSpecs := container.Config.ExposedPorts |
|
828 |
+ ports := make([]nat.Port, len(portSpecs)) |
|
829 |
+ var i int |
|
830 |
+ for p := range portSpecs { |
|
831 |
+ ports[i] = p |
|
832 |
+ i++ |
|
833 |
+ } |
|
834 |
+ nat.SortPortMap(ports, bindings) |
|
835 |
+ for _, port := range ports { |
|
836 |
+ expose := types.TransportPort{} |
|
837 |
+ expose.Proto = types.ParseProtocol(port.Proto()) |
|
838 |
+ expose.Port = uint16(port.Int()) |
|
839 |
+ exposeList = append(exposeList, expose) |
|
840 |
+ |
|
841 |
+ pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} |
|
842 |
+ binding := bindings[port] |
|
843 |
+ for i := 0; i < len(binding); i++ { |
|
844 |
+ pbCopy := pb.GetCopy() |
|
845 |
+ newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) |
|
846 |
+ var portStart, portEnd int |
|
847 |
+ if err == nil { |
|
848 |
+ portStart, portEnd, err = newP.Range() |
|
849 |
+ } |
|
850 |
+ if err != nil { |
|
851 |
+ return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) |
|
852 |
+ } |
|
853 |
+ pbCopy.HostPort = uint16(portStart) |
|
854 |
+ pbCopy.HostPortEnd = uint16(portEnd) |
|
855 |
+ pbCopy.HostIP = net.ParseIP(binding[i].HostIP) |
|
856 |
+ pbList = append(pbList, pbCopy) |
|
857 |
+ } |
|
858 |
+ |
|
859 |
+ if container.HostConfig.PublishAllPorts && len(binding) == 0 { |
|
860 |
+ pbList = append(pbList, pb) |
|
861 |
+ } |
|
862 |
+ } |
|
863 |
+ |
|
864 |
+ createOptions = append(createOptions, |
|
865 |
+ libnetwork.CreateOptionPortMapping(pbList), |
|
866 |
+ libnetwork.CreateOptionExposedPorts(exposeList)) |
|
867 |
+ |
|
868 |
+ return createOptions, nil |
|
869 |
+} |
|
870 |
+ |
|
584 | 871 |
// UpdateMonitor updates monitor configure for running container |
585 | 872 |
func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) { |
586 | 873 |
monitor := container.monitor |
... | ... |
@@ -5,10 +5,8 @@ package container |
5 | 5 |
import ( |
6 | 6 |
"fmt" |
7 | 7 |
"io/ioutil" |
8 |
- "net" |
|
9 | 8 |
"os" |
10 | 9 |
"path/filepath" |
11 |
- "strconv" |
|
12 | 10 |
"strings" |
13 | 11 |
"syscall" |
14 | 12 |
|
... | ... |
@@ -17,27 +15,15 @@ import ( |
17 | 17 |
"github.com/docker/docker/pkg/chrootarchive" |
18 | 18 |
"github.com/docker/docker/pkg/symlink" |
19 | 19 |
"github.com/docker/docker/pkg/system" |
20 |
- runconfigopts "github.com/docker/docker/runconfig/opts" |
|
21 | 20 |
"github.com/docker/docker/utils" |
22 | 21 |
"github.com/docker/docker/volume" |
23 | 22 |
containertypes "github.com/docker/engine-api/types/container" |
24 |
- "github.com/docker/engine-api/types/network" |
|
25 |
- "github.com/docker/go-connections/nat" |
|
26 |
- "github.com/docker/libnetwork" |
|
27 |
- "github.com/docker/libnetwork/netlabel" |
|
28 |
- "github.com/docker/libnetwork/options" |
|
29 |
- "github.com/docker/libnetwork/types" |
|
30 | 23 |
"github.com/opencontainers/runc/libcontainer/label" |
31 | 24 |
) |
32 | 25 |
|
33 | 26 |
// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container |
34 | 27 |
const DefaultSHMSize int64 = 67108864 |
35 | 28 |
|
36 |
-var ( |
|
37 |
- errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info") |
|
38 |
- errInvalidNetwork = fmt.Errorf("invalid network settings while building port map info") |
|
39 |
-) |
|
40 |
- |
|
41 | 29 |
// Container holds the fields specific to unixen implementations. |
42 | 30 |
// See CommonContainer for standard fields common to all containers. |
43 | 31 |
type Container struct { |
... | ... |
@@ -113,291 +99,6 @@ func (container *Container) BuildHostnameFile() error { |
113 | 113 |
return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) |
114 | 114 |
} |
115 | 115 |
|
116 |
-// GetEndpointInNetwork returns the container's endpoint to the provided network. |
|
117 |
-func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) { |
|
118 |
- endpointName := strings.TrimPrefix(container.Name, "/") |
|
119 |
- return n.EndpointByName(endpointName) |
|
120 |
-} |
|
121 |
- |
|
122 |
-func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error { |
|
123 |
- if ep == nil { |
|
124 |
- return errInvalidEndpoint |
|
125 |
- } |
|
126 |
- |
|
127 |
- networkSettings := container.NetworkSettings |
|
128 |
- if networkSettings == nil { |
|
129 |
- return errInvalidNetwork |
|
130 |
- } |
|
131 |
- |
|
132 |
- if len(networkSettings.Ports) == 0 { |
|
133 |
- pm, err := getEndpointPortMapInfo(ep) |
|
134 |
- if err != nil { |
|
135 |
- return err |
|
136 |
- } |
|
137 |
- networkSettings.Ports = pm |
|
138 |
- } |
|
139 |
- return nil |
|
140 |
-} |
|
141 |
- |
|
142 |
-func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) { |
|
143 |
- pm := nat.PortMap{} |
|
144 |
- driverInfo, err := ep.DriverInfo() |
|
145 |
- if err != nil { |
|
146 |
- return pm, err |
|
147 |
- } |
|
148 |
- |
|
149 |
- if driverInfo == nil { |
|
150 |
- // It is not an error for epInfo to be nil |
|
151 |
- return pm, nil |
|
152 |
- } |
|
153 |
- |
|
154 |
- if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { |
|
155 |
- if exposedPorts, ok := expData.([]types.TransportPort); ok { |
|
156 |
- for _, tp := range exposedPorts { |
|
157 |
- natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) |
|
158 |
- if err != nil { |
|
159 |
- return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err) |
|
160 |
- } |
|
161 |
- pm[natPort] = nil |
|
162 |
- } |
|
163 |
- } |
|
164 |
- } |
|
165 |
- |
|
166 |
- mapData, ok := driverInfo[netlabel.PortMap] |
|
167 |
- if !ok { |
|
168 |
- return pm, nil |
|
169 |
- } |
|
170 |
- |
|
171 |
- if portMapping, ok := mapData.([]types.PortBinding); ok { |
|
172 |
- for _, pp := range portMapping { |
|
173 |
- natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) |
|
174 |
- if err != nil { |
|
175 |
- return pm, err |
|
176 |
- } |
|
177 |
- natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} |
|
178 |
- pm[natPort] = append(pm[natPort], natBndg) |
|
179 |
- } |
|
180 |
- } |
|
181 |
- |
|
182 |
- return pm, nil |
|
183 |
-} |
|
184 |
- |
|
185 |
-func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap { |
|
186 |
- pm := nat.PortMap{} |
|
187 |
- if sb == nil { |
|
188 |
- return pm |
|
189 |
- } |
|
190 |
- |
|
191 |
- for _, ep := range sb.Endpoints() { |
|
192 |
- pm, _ = getEndpointPortMapInfo(ep) |
|
193 |
- if len(pm) > 0 { |
|
194 |
- break |
|
195 |
- } |
|
196 |
- } |
|
197 |
- return pm |
|
198 |
-} |
|
199 |
- |
|
200 |
-// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint. |
|
201 |
-func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { |
|
202 |
- if ep == nil { |
|
203 |
- return errInvalidEndpoint |
|
204 |
- } |
|
205 |
- |
|
206 |
- networkSettings := container.NetworkSettings |
|
207 |
- if networkSettings == nil { |
|
208 |
- return errInvalidNetwork |
|
209 |
- } |
|
210 |
- |
|
211 |
- epInfo := ep.Info() |
|
212 |
- if epInfo == nil { |
|
213 |
- // It is not an error to get an empty endpoint info |
|
214 |
- return nil |
|
215 |
- } |
|
216 |
- |
|
217 |
- if _, ok := networkSettings.Networks[n.Name()]; !ok { |
|
218 |
- networkSettings.Networks[n.Name()] = new(network.EndpointSettings) |
|
219 |
- } |
|
220 |
- networkSettings.Networks[n.Name()].NetworkID = n.ID() |
|
221 |
- networkSettings.Networks[n.Name()].EndpointID = ep.ID() |
|
222 |
- |
|
223 |
- iface := epInfo.Iface() |
|
224 |
- if iface == nil { |
|
225 |
- return nil |
|
226 |
- } |
|
227 |
- |
|
228 |
- if iface.MacAddress() != nil { |
|
229 |
- networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String() |
|
230 |
- } |
|
231 |
- |
|
232 |
- if iface.Address() != nil { |
|
233 |
- ones, _ := iface.Address().Mask.Size() |
|
234 |
- networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String() |
|
235 |
- networkSettings.Networks[n.Name()].IPPrefixLen = ones |
|
236 |
- } |
|
237 |
- |
|
238 |
- if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { |
|
239 |
- onesv6, _ := iface.AddressIPv6().Mask.Size() |
|
240 |
- networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String() |
|
241 |
- networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6 |
|
242 |
- } |
|
243 |
- |
|
244 |
- return nil |
|
245 |
-} |
|
246 |
- |
|
247 |
-// UpdateJoinInfo updates network settings when container joins network n with endpoint ep. |
|
248 |
-func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { |
|
249 |
- if err := container.buildPortMapInfo(ep); err != nil { |
|
250 |
- return err |
|
251 |
- } |
|
252 |
- |
|
253 |
- epInfo := ep.Info() |
|
254 |
- if epInfo == nil { |
|
255 |
- // It is not an error to get an empty endpoint info |
|
256 |
- return nil |
|
257 |
- } |
|
258 |
- if epInfo.Gateway() != nil { |
|
259 |
- container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String() |
|
260 |
- } |
|
261 |
- if epInfo.GatewayIPv6().To16() != nil { |
|
262 |
- container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String() |
|
263 |
- } |
|
264 |
- |
|
265 |
- return nil |
|
266 |
-} |
|
267 |
- |
|
268 |
-// UpdateSandboxNetworkSettings updates the sandbox ID and Key. |
|
269 |
-func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error { |
|
270 |
- container.NetworkSettings.SandboxID = sb.ID() |
|
271 |
- container.NetworkSettings.SandboxKey = sb.Key() |
|
272 |
- return nil |
|
273 |
-} |
|
274 |
- |
|
275 |
-// BuildJoinOptions builds endpoint Join options from a given network. |
|
276 |
-func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) { |
|
277 |
- var joinOptions []libnetwork.EndpointOption |
|
278 |
- if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok { |
|
279 |
- for _, str := range epConfig.Links { |
|
280 |
- name, alias, err := runconfigopts.ParseLink(str) |
|
281 |
- if err != nil { |
|
282 |
- return nil, err |
|
283 |
- } |
|
284 |
- joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias)) |
|
285 |
- } |
|
286 |
- } |
|
287 |
- return joinOptions, nil |
|
288 |
-} |
|
289 |
- |
|
290 |
-// BuildCreateEndpointOptions builds endpoint options from a given network. |
|
291 |
-func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) { |
|
292 |
- var ( |
|
293 |
- bindings = make(nat.PortMap) |
|
294 |
- pbList []types.PortBinding |
|
295 |
- exposeList []types.TransportPort |
|
296 |
- createOptions []libnetwork.EndpointOption |
|
297 |
- ) |
|
298 |
- |
|
299 |
- if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint { |
|
300 |
- createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) |
|
301 |
- } |
|
302 |
- |
|
303 |
- if epConfig != nil { |
|
304 |
- ipam := epConfig.IPAMConfig |
|
305 |
- if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") { |
|
306 |
- createOptions = append(createOptions, |
|
307 |
- libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil)) |
|
308 |
- } |
|
309 |
- |
|
310 |
- for _, alias := range epConfig.Aliases { |
|
311 |
- createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) |
|
312 |
- } |
|
313 |
- } |
|
314 |
- |
|
315 |
- if !containertypes.NetworkMode(n.Name()).IsUserDefined() { |
|
316 |
- createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) |
|
317 |
- } |
|
318 |
- |
|
319 |
- // configs that are applicable only for the endpoint in the network |
|
320 |
- // to which container was connected to on docker run. |
|
321 |
- // Ideally all these network-specific endpoint configurations must be moved under |
|
322 |
- // container.NetworkSettings.Networks[n.Name()] |
|
323 |
- if n.Name() == container.HostConfig.NetworkMode.NetworkName() || |
|
324 |
- (n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) { |
|
325 |
- if container.Config.MacAddress != "" { |
|
326 |
- mac, err := net.ParseMAC(container.Config.MacAddress) |
|
327 |
- if err != nil { |
|
328 |
- return nil, err |
|
329 |
- } |
|
330 |
- |
|
331 |
- genericOption := options.Generic{ |
|
332 |
- netlabel.MacAddress: mac, |
|
333 |
- } |
|
334 |
- |
|
335 |
- createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) |
|
336 |
- } |
|
337 |
- } |
|
338 |
- |
|
339 |
- // Port-mapping rules belong to the container & applicable only to non-internal networks |
|
340 |
- portmaps := getSandboxPortMapInfo(sb) |
|
341 |
- if n.Info().Internal() || len(portmaps) > 0 { |
|
342 |
- return createOptions, nil |
|
343 |
- } |
|
344 |
- |
|
345 |
- if container.HostConfig.PortBindings != nil { |
|
346 |
- for p, b := range container.HostConfig.PortBindings { |
|
347 |
- bindings[p] = []nat.PortBinding{} |
|
348 |
- for _, bb := range b { |
|
349 |
- bindings[p] = append(bindings[p], nat.PortBinding{ |
|
350 |
- HostIP: bb.HostIP, |
|
351 |
- HostPort: bb.HostPort, |
|
352 |
- }) |
|
353 |
- } |
|
354 |
- } |
|
355 |
- } |
|
356 |
- |
|
357 |
- portSpecs := container.Config.ExposedPorts |
|
358 |
- ports := make([]nat.Port, len(portSpecs)) |
|
359 |
- var i int |
|
360 |
- for p := range portSpecs { |
|
361 |
- ports[i] = p |
|
362 |
- i++ |
|
363 |
- } |
|
364 |
- nat.SortPortMap(ports, bindings) |
|
365 |
- for _, port := range ports { |
|
366 |
- expose := types.TransportPort{} |
|
367 |
- expose.Proto = types.ParseProtocol(port.Proto()) |
|
368 |
- expose.Port = uint16(port.Int()) |
|
369 |
- exposeList = append(exposeList, expose) |
|
370 |
- |
|
371 |
- pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} |
|
372 |
- binding := bindings[port] |
|
373 |
- for i := 0; i < len(binding); i++ { |
|
374 |
- pbCopy := pb.GetCopy() |
|
375 |
- newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) |
|
376 |
- var portStart, portEnd int |
|
377 |
- if err == nil { |
|
378 |
- portStart, portEnd, err = newP.Range() |
|
379 |
- } |
|
380 |
- if err != nil { |
|
381 |
- return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) |
|
382 |
- } |
|
383 |
- pbCopy.HostPort = uint16(portStart) |
|
384 |
- pbCopy.HostPortEnd = uint16(portEnd) |
|
385 |
- pbCopy.HostIP = net.ParseIP(binding[i].HostIP) |
|
386 |
- pbList = append(pbList, pbCopy) |
|
387 |
- } |
|
388 |
- |
|
389 |
- if container.HostConfig.PublishAllPorts && len(binding) == 0 { |
|
390 |
- pbList = append(pbList, pb) |
|
391 |
- } |
|
392 |
- } |
|
393 |
- |
|
394 |
- createOptions = append(createOptions, |
|
395 |
- libnetwork.CreateOptionPortMapping(pbList), |
|
396 |
- libnetwork.CreateOptionExposedPorts(exposeList)) |
|
397 |
- |
|
398 |
- return createOptions, nil |
|
399 |
-} |
|
400 |
- |
|
401 | 116 |
// appendNetworkMounts appends any network mounts to the array of mount points passed in |
402 | 117 |
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) { |
403 | 118 |
for _, mnt := range container.NetworkMounts() { |
... | ... |
@@ -17,6 +17,9 @@ import ( |
17 | 17 |
type Container struct { |
18 | 18 |
CommonContainer |
19 | 19 |
|
20 |
+ HostnamePath string |
|
21 |
+ HostsPath string |
|
22 |
+ ResolvConfPath string |
|
20 | 23 |
// Fields below here are platform specific. |
21 | 24 |
} |
22 | 25 |
|
... | ... |
@@ -84,6 +87,11 @@ func cleanResourcePath(path string) string { |
84 | 84 |
return filepath.Join(string(os.PathSeparator), path) |
85 | 85 |
} |
86 | 86 |
|
87 |
+// BuildHostnameFile writes the container's hostname file. |
|
88 |
+func (container *Container) BuildHostnameFile() error { |
|
89 |
+ return nil |
|
90 |
+} |
|
91 |
+ |
|
87 | 92 |
// canMountFS determines if the file system for the container |
88 | 93 |
// can be mounted locally. In the case of Windows, this is not possible |
89 | 94 |
// for Hyper-V containers during WORKDIR execution for example. |
... | ... |
@@ -15,7 +15,9 @@ var ( |
15 | 15 |
// bridgeConfig stores all the bridge driver specific |
16 | 16 |
// configuration. |
17 | 17 |
type bridgeConfig struct { |
18 |
- VirtualSwitchName string `json:"bridge,omitempty"` |
|
18 |
+ FixedCIDR string |
|
19 |
+ NetworkMode string |
|
20 |
+ Iface string `json:"bridge,omitempty"` |
|
19 | 21 |
} |
20 | 22 |
|
21 | 23 |
// Config defines the configuration of a docker daemon. |
... | ... |
@@ -37,6 +39,7 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin |
37 | 37 |
config.InstallCommonFlags(cmd, usageFn) |
38 | 38 |
|
39 | 39 |
// Then platform-specific install flags. |
40 |
- cmd.StringVar(&config.bridgeConfig.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch") |
|
40 |
+ cmd.StringVar(&config.bridgeConfig.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs")) |
|
41 |
+ cmd.StringVar(&config.bridgeConfig.Iface, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch") |
|
41 | 42 |
cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "", usageFn("Users or groups that can access the named pipe")) |
42 | 43 |
} |
... | ... |
@@ -1,9 +1,745 @@ |
1 | 1 |
package daemon |
2 | 2 |
|
3 |
-import "errors" |
|
3 |
+import ( |
|
4 |
+ "errors" |
|
5 |
+ "fmt" |
|
6 |
+ "net" |
|
7 |
+ "os" |
|
8 |
+ "path" |
|
9 |
+ "strings" |
|
10 |
+ |
|
11 |
+ "github.com/Sirupsen/logrus" |
|
12 |
+ "github.com/docker/docker/container" |
|
13 |
+ "github.com/docker/docker/daemon/network" |
|
14 |
+ derr "github.com/docker/docker/errors" |
|
15 |
+ "github.com/docker/docker/runconfig" |
|
16 |
+ containertypes "github.com/docker/engine-api/types/container" |
|
17 |
+ networktypes "github.com/docker/engine-api/types/network" |
|
18 |
+ "github.com/docker/go-connections/nat" |
|
19 |
+ "github.com/docker/libnetwork" |
|
20 |
+ "github.com/docker/libnetwork/netlabel" |
|
21 |
+ "github.com/docker/libnetwork/options" |
|
22 |
+ "github.com/docker/libnetwork/types" |
|
23 |
+) |
|
4 | 24 |
|
5 | 25 |
var ( |
6 | 26 |
// ErrRootFSReadOnly is returned when a container |
7 | 27 |
// rootfs is marked readonly. |
8 | 28 |
ErrRootFSReadOnly = errors.New("container rootfs is marked read-only") |
9 | 29 |
) |
30 |
+ |
|
31 |
+func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libnetwork.Network) ([]libnetwork.SandboxOption, error) { |
|
32 |
+ var ( |
|
33 |
+ sboxOptions []libnetwork.SandboxOption |
|
34 |
+ err error |
|
35 |
+ dns []string |
|
36 |
+ dnsSearch []string |
|
37 |
+ dnsOptions []string |
|
38 |
+ bindings = make(nat.PortMap) |
|
39 |
+ pbList []types.PortBinding |
|
40 |
+ exposeList []types.TransportPort |
|
41 |
+ ) |
|
42 |
+ |
|
43 |
+ defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() |
|
44 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), |
|
45 |
+ libnetwork.OptionDomainname(container.Config.Domainname)) |
|
46 |
+ |
|
47 |
+ if container.HostConfig.NetworkMode.IsHost() { |
|
48 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) |
|
49 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) |
|
50 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) |
|
51 |
+ } else if daemon.execDriver.SupportsHooks() { |
|
52 |
+ // OptionUseExternalKey is mandatory for userns support. |
|
53 |
+ // But optional for non-userns support |
|
54 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) |
|
55 |
+ } |
|
56 |
+ |
|
57 |
+ container.HostsPath, err = container.GetRootResourcePath("hosts") |
|
58 |
+ if err != nil { |
|
59 |
+ return nil, err |
|
60 |
+ } |
|
61 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) |
|
62 |
+ |
|
63 |
+ container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf") |
|
64 |
+ if err != nil { |
|
65 |
+ return nil, err |
|
66 |
+ } |
|
67 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) |
|
68 |
+ |
|
69 |
+ if len(container.HostConfig.DNS) > 0 { |
|
70 |
+ dns = container.HostConfig.DNS |
|
71 |
+ } else if len(daemon.configStore.DNS) > 0 { |
|
72 |
+ dns = daemon.configStore.DNS |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ for _, d := range dns { |
|
76 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) |
|
77 |
+ } |
|
78 |
+ |
|
79 |
+ if len(container.HostConfig.DNSSearch) > 0 { |
|
80 |
+ dnsSearch = container.HostConfig.DNSSearch |
|
81 |
+ } else if len(daemon.configStore.DNSSearch) > 0 { |
|
82 |
+ dnsSearch = daemon.configStore.DNSSearch |
|
83 |
+ } |
|
84 |
+ |
|
85 |
+ for _, ds := range dnsSearch { |
|
86 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+ if len(container.HostConfig.DNSOptions) > 0 { |
|
90 |
+ dnsOptions = container.HostConfig.DNSOptions |
|
91 |
+ } else if len(daemon.configStore.DNSOptions) > 0 { |
|
92 |
+ dnsOptions = daemon.configStore.DNSOptions |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ for _, ds := range dnsOptions { |
|
96 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) |
|
97 |
+ } |
|
98 |
+ |
|
99 |
+ if container.NetworkSettings.SecondaryIPAddresses != nil { |
|
100 |
+ name := container.Config.Hostname |
|
101 |
+ if container.Config.Domainname != "" { |
|
102 |
+ name = name + "." + container.Config.Domainname |
|
103 |
+ } |
|
104 |
+ |
|
105 |
+ for _, a := range container.NetworkSettings.SecondaryIPAddresses { |
|
106 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) |
|
107 |
+ } |
|
108 |
+ } |
|
109 |
+ |
|
110 |
+ for _, extraHost := range container.HostConfig.ExtraHosts { |
|
111 |
+ // allow IPv6 addresses in extra hosts; only split on first ":" |
|
112 |
+ parts := strings.SplitN(extraHost, ":", 2) |
|
113 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) |
|
114 |
+ } |
|
115 |
+ |
|
116 |
+ if container.HostConfig.PortBindings != nil { |
|
117 |
+ for p, b := range container.HostConfig.PortBindings { |
|
118 |
+ bindings[p] = []nat.PortBinding{} |
|
119 |
+ for _, bb := range b { |
|
120 |
+ bindings[p] = append(bindings[p], nat.PortBinding{ |
|
121 |
+ HostIP: bb.HostIP, |
|
122 |
+ HostPort: bb.HostPort, |
|
123 |
+ }) |
|
124 |
+ } |
|
125 |
+ } |
|
126 |
+ } |
|
127 |
+ |
|
128 |
+ portSpecs := container.Config.ExposedPorts |
|
129 |
+ ports := make([]nat.Port, len(portSpecs)) |
|
130 |
+ var i int |
|
131 |
+ for p := range portSpecs { |
|
132 |
+ ports[i] = p |
|
133 |
+ i++ |
|
134 |
+ } |
|
135 |
+ nat.SortPortMap(ports, bindings) |
|
136 |
+ for _, port := range ports { |
|
137 |
+ expose := types.TransportPort{} |
|
138 |
+ expose.Proto = types.ParseProtocol(port.Proto()) |
|
139 |
+ expose.Port = uint16(port.Int()) |
|
140 |
+ exposeList = append(exposeList, expose) |
|
141 |
+ |
|
142 |
+ pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} |
|
143 |
+ binding := bindings[port] |
|
144 |
+ for i := 0; i < len(binding); i++ { |
|
145 |
+ pbCopy := pb.GetCopy() |
|
146 |
+ newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) |
|
147 |
+ var portStart, portEnd int |
|
148 |
+ if err == nil { |
|
149 |
+ portStart, portEnd, err = newP.Range() |
|
150 |
+ } |
|
151 |
+ if err != nil { |
|
152 |
+ return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) |
|
153 |
+ } |
|
154 |
+ pbCopy.HostPort = uint16(portStart) |
|
155 |
+ pbCopy.HostPortEnd = uint16(portEnd) |
|
156 |
+ pbCopy.HostIP = net.ParseIP(binding[i].HostIP) |
|
157 |
+ pbList = append(pbList, pbCopy) |
|
158 |
+ } |
|
159 |
+ |
|
160 |
+ if container.HostConfig.PublishAllPorts && len(binding) == 0 { |
|
161 |
+ pbList = append(pbList, pb) |
|
162 |
+ } |
|
163 |
+ } |
|
164 |
+ |
|
165 |
+ sboxOptions = append(sboxOptions, |
|
166 |
+ libnetwork.OptionPortMapping(pbList), |
|
167 |
+ libnetwork.OptionExposedPorts(exposeList)) |
|
168 |
+ |
|
169 |
+ // Link feature is supported only for the default bridge network. |
|
170 |
+ // return if this call to build join options is not for default bridge network |
|
171 |
+ if n.Name() != defaultNetName { |
|
172 |
+ return sboxOptions, nil |
|
173 |
+ } |
|
174 |
+ |
|
175 |
+ ep, _ := container.GetEndpointInNetwork(n) |
|
176 |
+ if ep == nil { |
|
177 |
+ return sboxOptions, nil |
|
178 |
+ } |
|
179 |
+ |
|
180 |
+ var childEndpoints, parentEndpoints []string |
|
181 |
+ |
|
182 |
+ children := daemon.children(container) |
|
183 |
+ for linkAlias, child := range children { |
|
184 |
+ if !isLinkable(child) { |
|
185 |
+ return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name) |
|
186 |
+ } |
|
187 |
+ _, alias := path.Split(linkAlias) |
|
188 |
+ // allow access to the linked container via the alias, real name, and container hostname |
|
189 |
+ aliasList := alias + " " + child.Config.Hostname |
|
190 |
+ // only add the name if alias isn't equal to the name |
|
191 |
+ if alias != child.Name[1:] { |
|
192 |
+ aliasList = aliasList + " " + child.Name[1:] |
|
193 |
+ } |
|
194 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress)) |
|
195 |
+ cEndpoint, _ := child.GetEndpointInNetwork(n) |
|
196 |
+ if cEndpoint != nil && cEndpoint.ID() != "" { |
|
197 |
+ childEndpoints = append(childEndpoints, cEndpoint.ID()) |
|
198 |
+ } |
|
199 |
+ } |
|
200 |
+ |
|
201 |
+ bridgeSettings := container.NetworkSettings.Networks[defaultNetName] |
|
202 |
+ for alias, parent := range daemon.parents(container) { |
|
203 |
+ if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() { |
|
204 |
+ continue |
|
205 |
+ } |
|
206 |
+ |
|
207 |
+ _, alias = path.Split(alias) |
|
208 |
+ logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress) |
|
209 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate( |
|
210 |
+ parent.ID, |
|
211 |
+ alias, |
|
212 |
+ bridgeSettings.IPAddress, |
|
213 |
+ )) |
|
214 |
+ if ep.ID() != "" { |
|
215 |
+ parentEndpoints = append(parentEndpoints, ep.ID()) |
|
216 |
+ } |
|
217 |
+ } |
|
218 |
+ |
|
219 |
+ linkOptions := options.Generic{ |
|
220 |
+ netlabel.GenericData: options.Generic{ |
|
221 |
+ "ParentEndpoints": parentEndpoints, |
|
222 |
+ "ChildEndpoints": childEndpoints, |
|
223 |
+ }, |
|
224 |
+ } |
|
225 |
+ |
|
226 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) |
|
227 |
+ return sboxOptions, nil |
|
228 |
+} |
|
229 |
+ |
|
230 |
+func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network) error { |
|
231 |
+ if container.NetworkSettings == nil { |
|
232 |
+ container.NetworkSettings = &network.Settings{Networks: make(map[string]*networktypes.EndpointSettings)} |
|
233 |
+ } |
|
234 |
+ |
|
235 |
+ if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { |
|
236 |
+ return runconfig.ErrConflictHostNetwork |
|
237 |
+ } |
|
238 |
+ |
|
239 |
+ for s := range container.NetworkSettings.Networks { |
|
240 |
+ sn, err := daemon.FindNetwork(s) |
|
241 |
+ if err != nil { |
|
242 |
+ continue |
|
243 |
+ } |
|
244 |
+ |
|
245 |
+ if sn.Name() == n.Name() { |
|
246 |
+ // Avoid duplicate config |
|
247 |
+ return nil |
|
248 |
+ } |
|
249 |
+ if !containertypes.NetworkMode(sn.Type()).IsPrivate() || |
|
250 |
+ !containertypes.NetworkMode(n.Type()).IsPrivate() { |
|
251 |
+ return runconfig.ErrConflictSharedNetwork |
|
252 |
+ } |
|
253 |
+ if containertypes.NetworkMode(sn.Name()).IsNone() || |
|
254 |
+ containertypes.NetworkMode(n.Name()).IsNone() { |
|
255 |
+ return runconfig.ErrConflictNoNetwork |
|
256 |
+ } |
|
257 |
+ } |
|
258 |
+ |
|
259 |
+ if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok { |
|
260 |
+ container.NetworkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings) |
|
261 |
+ } |
|
262 |
+ |
|
263 |
+ return nil |
|
264 |
+} |
|
265 |
+ |
|
266 |
+func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error { |
|
267 |
+ if err := container.BuildEndpointInfo(n, ep); err != nil { |
|
268 |
+ return err |
|
269 |
+ } |
|
270 |
+ |
|
271 |
+ if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() { |
|
272 |
+ container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface |
|
273 |
+ } |
|
274 |
+ |
|
275 |
+ return nil |
|
276 |
+} |
|
277 |
+ |
|
278 |
+// UpdateNetwork is used to update the container's network (e.g. when linked containers |
|
279 |
+// get removed/unlinked). |
|
280 |
+func (daemon *Daemon) updateNetwork(container *container.Container) error { |
|
281 |
+ ctrl := daemon.netController |
|
282 |
+ sid := container.NetworkSettings.SandboxID |
|
283 |
+ |
|
284 |
+ sb, err := ctrl.SandboxByID(sid) |
|
285 |
+ if err != nil { |
|
286 |
+ return fmt.Errorf("error locating sandbox id %s: %v", sid, err) |
|
287 |
+ } |
|
288 |
+ |
|
289 |
+ // Find if container is connected to the default bridge network |
|
290 |
+ var n libnetwork.Network |
|
291 |
+ for name := range container.NetworkSettings.Networks { |
|
292 |
+ sn, err := daemon.FindNetwork(name) |
|
293 |
+ if err != nil { |
|
294 |
+ continue |
|
295 |
+ } |
|
296 |
+ if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() { |
|
297 |
+ n = sn |
|
298 |
+ break |
|
299 |
+ } |
|
300 |
+ } |
|
301 |
+ |
|
302 |
+ if n == nil { |
|
303 |
+ // Not connected to the default bridge network; Nothing to do |
|
304 |
+ return nil |
|
305 |
+ } |
|
306 |
+ |
|
307 |
+ options, err := daemon.buildSandboxOptions(container, n) |
|
308 |
+ if err != nil { |
|
309 |
+ return fmt.Errorf("Update network failed: %v", err) |
|
310 |
+ } |
|
311 |
+ |
|
312 |
+ if err := sb.Refresh(options...); err != nil { |
|
313 |
+ return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err) |
|
314 |
+ } |
|
315 |
+ |
|
316 |
+ return nil |
|
317 |
+} |
|
318 |
+ |
|
319 |
+// updateContainerNetworkSettings update the network settings |
|
320 |
+func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error { |
|
321 |
+ var ( |
|
322 |
+ n libnetwork.Network |
|
323 |
+ err error |
|
324 |
+ ) |
|
325 |
+ |
|
326 |
+ // TODO Windows: Remove this once TP4 builds are not supported |
|
327 |
+ // Windows TP4 build don't support libnetwork and in that case |
|
328 |
+ // daemon.netController will be nil |
|
329 |
+ if daemon.netController == nil { |
|
330 |
+ return nil |
|
331 |
+ } |
|
332 |
+ |
|
333 |
+ mode := container.HostConfig.NetworkMode |
|
334 |
+ if container.Config.NetworkDisabled || mode.IsContainer() { |
|
335 |
+ return nil |
|
336 |
+ } |
|
337 |
+ |
|
338 |
+ networkName := mode.NetworkName() |
|
339 |
+ if mode.IsDefault() { |
|
340 |
+ networkName = daemon.netController.Config().Daemon.DefaultNetwork |
|
341 |
+ } |
|
342 |
+ if mode.IsUserDefined() { |
|
343 |
+ n, err = daemon.FindNetwork(networkName) |
|
344 |
+ if err != nil { |
|
345 |
+ return err |
|
346 |
+ } |
|
347 |
+ networkName = n.Name() |
|
348 |
+ } |
|
349 |
+ if container.NetworkSettings == nil { |
|
350 |
+ container.NetworkSettings = &network.Settings{} |
|
351 |
+ } |
|
352 |
+ if len(endpointsConfig) > 0 { |
|
353 |
+ container.NetworkSettings.Networks = endpointsConfig |
|
354 |
+ } |
|
355 |
+ if container.NetworkSettings.Networks == nil { |
|
356 |
+ container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings) |
|
357 |
+ container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings) |
|
358 |
+ } |
|
359 |
+ if !mode.IsUserDefined() { |
|
360 |
+ return nil |
|
361 |
+ } |
|
362 |
+ // Make sure to internally store the per network endpoint config by network name |
|
363 |
+ if _, ok := container.NetworkSettings.Networks[networkName]; ok { |
|
364 |
+ return nil |
|
365 |
+ } |
|
366 |
+ if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok { |
|
367 |
+ container.NetworkSettings.Networks[networkName] = nwConfig |
|
368 |
+ delete(container.NetworkSettings.Networks, n.ID()) |
|
369 |
+ return nil |
|
370 |
+ } |
|
371 |
+ |
|
372 |
+ return nil |
|
373 |
+} |
|
374 |
+ |
|
375 |
+func (daemon *Daemon) allocateNetwork(container *container.Container) error { |
|
376 |
+ controller := daemon.netController |
|
377 |
+ |
|
378 |
+ if daemon.netController == nil { |
|
379 |
+ return nil |
|
380 |
+ } |
|
381 |
+ |
|
382 |
+ // Cleanup any stale sandbox left over due to ungraceful daemon shutdown |
|
383 |
+ if err := controller.SandboxDestroy(container.ID); err != nil { |
|
384 |
+ logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID) |
|
385 |
+ } |
|
386 |
+ |
|
387 |
+ updateSettings := false |
|
388 |
+ if len(container.NetworkSettings.Networks) == 0 { |
|
389 |
+ if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() { |
|
390 |
+ return nil |
|
391 |
+ } |
|
392 |
+ |
|
393 |
+ err := daemon.updateContainerNetworkSettings(container, nil) |
|
394 |
+ if err != nil { |
|
395 |
+ return err |
|
396 |
+ } |
|
397 |
+ updateSettings = true |
|
398 |
+ } |
|
399 |
+ |
|
400 |
+ for n, nConf := range container.NetworkSettings.Networks { |
|
401 |
+ if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil { |
|
402 |
+ return err |
|
403 |
+ } |
|
404 |
+ } |
|
405 |
+ |
|
406 |
+ return container.WriteHostConfig() |
|
407 |
+} |
|
408 |
+ |
|
409 |
+func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox { |
|
410 |
+ var sb libnetwork.Sandbox |
|
411 |
+ daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool { |
|
412 |
+ if s.ContainerID() == container.ID { |
|
413 |
+ sb = s |
|
414 |
+ return true |
|
415 |
+ } |
|
416 |
+ return false |
|
417 |
+ }) |
|
418 |
+ return sb |
|
419 |
+} |
|
420 |
+ |
|
421 |
+// hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration |
|
422 |
+func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool { |
|
423 |
+ return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0) |
|
424 |
+} |
|
425 |
+ |
|
426 |
+// User specified ip address is acceptable only for networks with user specified subnets. |
|
427 |
+func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error { |
|
428 |
+ if n == nil || epConfig == nil { |
|
429 |
+ return nil |
|
430 |
+ } |
|
431 |
+ if !hasUserDefinedIPAddress(epConfig) { |
|
432 |
+ return nil |
|
433 |
+ } |
|
434 |
+ _, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig() |
|
435 |
+ for _, s := range []struct { |
|
436 |
+ ipConfigured bool |
|
437 |
+ subnetConfigs []*libnetwork.IpamConf |
|
438 |
+ }{ |
|
439 |
+ { |
|
440 |
+ ipConfigured: len(epConfig.IPAMConfig.IPv4Address) > 0, |
|
441 |
+ subnetConfigs: nwIPv4Configs, |
|
442 |
+ }, |
|
443 |
+ { |
|
444 |
+ ipConfigured: len(epConfig.IPAMConfig.IPv6Address) > 0, |
|
445 |
+ subnetConfigs: nwIPv6Configs, |
|
446 |
+ }, |
|
447 |
+ } { |
|
448 |
+ if s.ipConfigured { |
|
449 |
+ foundSubnet := false |
|
450 |
+ for _, cfg := range s.subnetConfigs { |
|
451 |
+ if len(cfg.PreferredPool) > 0 { |
|
452 |
+ foundSubnet = true |
|
453 |
+ break |
|
454 |
+ } |
|
455 |
+ } |
|
456 |
+ if !foundSubnet { |
|
457 |
+ return runconfig.ErrUnsupportedNetworkNoSubnetAndIP |
|
458 |
+ } |
|
459 |
+ } |
|
460 |
+ } |
|
461 |
+ |
|
462 |
+ return nil |
|
463 |
+} |
|
464 |
+ |
|
465 |
+// cleanOperationalData resets the operational data from the passed endpoint settings |
|
466 |
+func cleanOperationalData(es *networktypes.EndpointSettings) { |
|
467 |
+ es.EndpointID = "" |
|
468 |
+ es.Gateway = "" |
|
469 |
+ es.IPAddress = "" |
|
470 |
+ es.IPPrefixLen = 0 |
|
471 |
+ es.IPv6Gateway = "" |
|
472 |
+ es.GlobalIPv6Address = "" |
|
473 |
+ es.GlobalIPv6PrefixLen = 0 |
|
474 |
+ es.MacAddress = "" |
|
475 |
+} |
|
476 |
+ |
|
477 |
+func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) { |
|
478 |
+ if container.HostConfig.NetworkMode.IsContainer() { |
|
479 |
+ return nil, runconfig.ErrConflictSharedNetwork |
|
480 |
+ } |
|
481 |
+ |
|
482 |
+ if containertypes.NetworkMode(idOrName).IsBridge() && |
|
483 |
+ daemon.configStore.DisableBridge { |
|
484 |
+ container.Config.NetworkDisabled = true |
|
485 |
+ return nil, nil |
|
486 |
+ } |
|
487 |
+ |
|
488 |
+ if !containertypes.NetworkMode(idOrName).IsUserDefined() { |
|
489 |
+ if hasUserDefinedIPAddress(endpointConfig) { |
|
490 |
+ return nil, runconfig.ErrUnsupportedNetworkAndIP |
|
491 |
+ } |
|
492 |
+ if endpointConfig != nil && len(endpointConfig.Aliases) > 0 { |
|
493 |
+ return nil, runconfig.ErrUnsupportedNetworkAndAlias |
|
494 |
+ } |
|
495 |
+ } |
|
496 |
+ |
|
497 |
+ n, err := daemon.FindNetwork(idOrName) |
|
498 |
+ if err != nil { |
|
499 |
+ return nil, err |
|
500 |
+ } |
|
501 |
+ |
|
502 |
+ if err := validateNetworkingConfig(n, endpointConfig); err != nil { |
|
503 |
+ return nil, err |
|
504 |
+ } |
|
505 |
+ |
|
506 |
+ if updateSettings { |
|
507 |
+ if err := daemon.updateNetworkSettings(container, n); err != nil { |
|
508 |
+ return nil, err |
|
509 |
+ } |
|
510 |
+ } |
|
511 |
+ return n, nil |
|
512 |
+} |
|
513 |
+ |
|
514 |
+func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) { |
|
515 |
+ // TODO Windows: Remove this once TP4 builds are not supported |
|
516 |
+ // Windows TP4 build don't support libnetwork and in that case |
|
517 |
+ // daemon.netController will be nil |
|
518 |
+ if daemon.netController == nil { |
|
519 |
+ return nil |
|
520 |
+ } |
|
521 |
+ |
|
522 |
+ n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings) |
|
523 |
+ if err != nil { |
|
524 |
+ return err |
|
525 |
+ } |
|
526 |
+ if n == nil { |
|
527 |
+ return nil |
|
528 |
+ } |
|
529 |
+ |
|
530 |
+ controller := daemon.netController |
|
531 |
+ |
|
532 |
+ sb := daemon.getNetworkSandbox(container) |
|
533 |
+ createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb) |
|
534 |
+ if err != nil { |
|
535 |
+ return err |
|
536 |
+ } |
|
537 |
+ |
|
538 |
+ endpointName := strings.TrimPrefix(container.Name, "/") |
|
539 |
+ ep, err := n.CreateEndpoint(endpointName, createOptions...) |
|
540 |
+ if err != nil { |
|
541 |
+ return err |
|
542 |
+ } |
|
543 |
+ defer func() { |
|
544 |
+ if err != nil { |
|
545 |
+ if e := ep.Delete(false); e != nil { |
|
546 |
+ logrus.Warnf("Could not rollback container connection to network %s", idOrName) |
|
547 |
+ } |
|
548 |
+ } |
|
549 |
+ }() |
|
550 |
+ |
|
551 |
+ if endpointConfig != nil { |
|
552 |
+ container.NetworkSettings.Networks[n.Name()] = endpointConfig |
|
553 |
+ } |
|
554 |
+ |
|
555 |
+ if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil { |
|
556 |
+ return err |
|
557 |
+ } |
|
558 |
+ |
|
559 |
+ if sb == nil { |
|
560 |
+ options, err := daemon.buildSandboxOptions(container, n) |
|
561 |
+ if err != nil { |
|
562 |
+ return err |
|
563 |
+ } |
|
564 |
+ sb, err = controller.NewSandbox(container.ID, options...) |
|
565 |
+ if err != nil { |
|
566 |
+ return err |
|
567 |
+ } |
|
568 |
+ |
|
569 |
+ container.UpdateSandboxNetworkSettings(sb) |
|
570 |
+ } |
|
571 |
+ |
|
572 |
+ joinOptions, err := container.BuildJoinOptions(n) |
|
573 |
+ if err != nil { |
|
574 |
+ return err |
|
575 |
+ } |
|
576 |
+ |
|
577 |
+ if err := ep.Join(sb, joinOptions...); err != nil { |
|
578 |
+ return err |
|
579 |
+ } |
|
580 |
+ |
|
581 |
+ if err := container.UpdateJoinInfo(n, ep); err != nil { |
|
582 |
+ return fmt.Errorf("Updating join info failed: %v", err) |
|
583 |
+ } |
|
584 |
+ |
|
585 |
+ daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID}) |
|
586 |
+ return nil |
|
587 |
+} |
|
588 |
+ |
|
589 |
+// ForceEndpointDelete deletes an endpoing from a network forcefully |
|
590 |
+func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error { |
|
591 |
+ ep, err := n.EndpointByName(name) |
|
592 |
+ if err != nil { |
|
593 |
+ return err |
|
594 |
+ } |
|
595 |
+ return ep.Delete(true) |
|
596 |
+} |
|
597 |
+ |
|
598 |
+func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { |
|
599 |
+ var ( |
|
600 |
+ ep libnetwork.Endpoint |
|
601 |
+ sbox libnetwork.Sandbox |
|
602 |
+ ) |
|
603 |
+ |
|
604 |
+ s := func(current libnetwork.Endpoint) bool { |
|
605 |
+ epInfo := current.Info() |
|
606 |
+ if epInfo == nil { |
|
607 |
+ return false |
|
608 |
+ } |
|
609 |
+ if sb := epInfo.Sandbox(); sb != nil { |
|
610 |
+ if sb.ContainerID() == container.ID { |
|
611 |
+ ep = current |
|
612 |
+ sbox = sb |
|
613 |
+ return true |
|
614 |
+ } |
|
615 |
+ } |
|
616 |
+ return false |
|
617 |
+ } |
|
618 |
+ n.WalkEndpoints(s) |
|
619 |
+ |
|
620 |
+ if ep == nil && force { |
|
621 |
+ epName := strings.TrimPrefix(container.Name, "/") |
|
622 |
+ ep, err := n.EndpointByName(epName) |
|
623 |
+ if err != nil { |
|
624 |
+ return err |
|
625 |
+ } |
|
626 |
+ return ep.Delete(force) |
|
627 |
+ } |
|
628 |
+ |
|
629 |
+ if ep == nil { |
|
630 |
+ return fmt.Errorf("container %s is not connected to the network", container.ID) |
|
631 |
+ } |
|
632 |
+ |
|
633 |
+ if err := ep.Leave(sbox); err != nil { |
|
634 |
+ return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err) |
|
635 |
+ } |
|
636 |
+ |
|
637 |
+ if err := ep.Delete(false); err != nil { |
|
638 |
+ return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) |
|
639 |
+ } |
|
640 |
+ |
|
641 |
+ delete(container.NetworkSettings.Networks, n.Name()) |
|
642 |
+ return nil |
|
643 |
+} |
|
644 |
+ |
|
645 |
+func (daemon *Daemon) initializeNetworking(container *container.Container) error { |
|
646 |
+ var err error |
|
647 |
+ |
|
648 |
+ // TODO Windows: Remove this once TP4 builds are not supported |
|
649 |
+ // Windows TP4 build don't support libnetwork and in that case |
|
650 |
+ // daemon.netController will be nil |
|
651 |
+ if daemon.netController == nil { |
|
652 |
+ return nil |
|
653 |
+ } |
|
654 |
+ |
|
655 |
+ if container.HostConfig.NetworkMode.IsContainer() { |
|
656 |
+ // we need to get the hosts files from the container to join |
|
657 |
+ nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer()) |
|
658 |
+ if err != nil { |
|
659 |
+ return err |
|
660 |
+ } |
|
661 |
+ container.HostnamePath = nc.HostnamePath |
|
662 |
+ container.HostsPath = nc.HostsPath |
|
663 |
+ container.ResolvConfPath = nc.ResolvConfPath |
|
664 |
+ container.Config.Hostname = nc.Config.Hostname |
|
665 |
+ container.Config.Domainname = nc.Config.Domainname |
|
666 |
+ return nil |
|
667 |
+ } |
|
668 |
+ |
|
669 |
+ if container.HostConfig.NetworkMode.IsHost() { |
|
670 |
+ container.Config.Hostname, err = os.Hostname() |
|
671 |
+ if err != nil { |
|
672 |
+ return err |
|
673 |
+ } |
|
674 |
+ |
|
675 |
+ parts := strings.SplitN(container.Config.Hostname, ".", 2) |
|
676 |
+ if len(parts) > 1 { |
|
677 |
+ container.Config.Hostname = parts[0] |
|
678 |
+ container.Config.Domainname = parts[1] |
|
679 |
+ } |
|
680 |
+ |
|
681 |
+ } |
|
682 |
+ |
|
683 |
+ if err := daemon.allocateNetwork(container); err != nil { |
|
684 |
+ return err |
|
685 |
+ } |
|
686 |
+ |
|
687 |
+ return container.BuildHostnameFile() |
|
688 |
+} |
|
689 |
+ |
|
690 |
+func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) { |
|
691 |
+ nc, err := daemon.GetContainer(connectedContainerID) |
|
692 |
+ if err != nil { |
|
693 |
+ return nil, err |
|
694 |
+ } |
|
695 |
+ if containerID == nc.ID { |
|
696 |
+ return nil, fmt.Errorf("cannot join own network") |
|
697 |
+ } |
|
698 |
+ if !nc.IsRunning() { |
|
699 |
+ err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID) |
|
700 |
+ return nil, derr.NewRequestConflictError(err) |
|
701 |
+ } |
|
702 |
+ if nc.IsRestarting() { |
|
703 |
+ return nil, errContainerIsRestarting(connectedContainerID) |
|
704 |
+ } |
|
705 |
+ return nc, nil |
|
706 |
+} |
|
707 |
+ |
|
708 |
+func (daemon *Daemon) releaseNetwork(container *container.Container) { |
|
709 |
+ if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled { |
|
710 |
+ return |
|
711 |
+ } |
|
712 |
+ |
|
713 |
+ sid := container.NetworkSettings.SandboxID |
|
714 |
+ settings := container.NetworkSettings.Networks |
|
715 |
+ container.NetworkSettings.Ports = nil |
|
716 |
+ |
|
717 |
+ if sid == "" || len(settings) == 0 { |
|
718 |
+ return |
|
719 |
+ } |
|
720 |
+ |
|
721 |
+ var networks []libnetwork.Network |
|
722 |
+ for n, epSettings := range settings { |
|
723 |
+ if nw, err := daemon.FindNetwork(n); err == nil { |
|
724 |
+ networks = append(networks, nw) |
|
725 |
+ } |
|
726 |
+ cleanOperationalData(epSettings) |
|
727 |
+ } |
|
728 |
+ |
|
729 |
+ sb, err := daemon.netController.SandboxByID(sid) |
|
730 |
+ if err != nil { |
|
731 |
+ logrus.Errorf("error locating sandbox id %s: %v", sid, err) |
|
732 |
+ return |
|
733 |
+ } |
|
734 |
+ |
|
735 |
+ if err := sb.Delete(); err != nil { |
|
736 |
+ logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) |
|
737 |
+ } |
|
738 |
+ |
|
739 |
+ attributes := map[string]string{ |
|
740 |
+ "container": container.ID, |
|
741 |
+ } |
|
742 |
+ for _, nw := range networks { |
|
743 |
+ daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes) |
|
744 |
+ } |
|
745 |
+} |
... | ... |
@@ -4,9 +4,7 @@ package daemon |
4 | 4 |
|
5 | 5 |
import ( |
6 | 6 |
"fmt" |
7 |
- "net" |
|
8 | 7 |
"os" |
9 |
- "path" |
|
10 | 8 |
"path/filepath" |
11 | 9 |
"strconv" |
12 | 10 |
"strings" |
... | ... |
@@ -17,8 +15,6 @@ import ( |
17 | 17 |
"github.com/docker/docker/container" |
18 | 18 |
"github.com/docker/docker/daemon/execdriver" |
19 | 19 |
"github.com/docker/docker/daemon/links" |
20 |
- "github.com/docker/docker/daemon/network" |
|
21 |
- "github.com/docker/docker/errors" |
|
22 | 20 |
"github.com/docker/docker/pkg/fileutils" |
23 | 21 |
"github.com/docker/docker/pkg/idtools" |
24 | 22 |
"github.com/docker/docker/pkg/mount" |
... | ... |
@@ -26,12 +22,8 @@ import ( |
26 | 26 |
"github.com/docker/docker/runconfig" |
27 | 27 |
containertypes "github.com/docker/engine-api/types/container" |
28 | 28 |
networktypes "github.com/docker/engine-api/types/network" |
29 |
- "github.com/docker/go-connections/nat" |
|
30 | 29 |
"github.com/docker/go-units" |
31 | 30 |
"github.com/docker/libnetwork" |
32 |
- "github.com/docker/libnetwork/netlabel" |
|
33 |
- "github.com/docker/libnetwork/options" |
|
34 |
- "github.com/docker/libnetwork/types" |
|
35 | 31 |
"github.com/opencontainers/runc/libcontainer/configs" |
36 | 32 |
"github.com/opencontainers/runc/libcontainer/devices" |
37 | 33 |
"github.com/opencontainers/runc/libcontainer/label" |
... | ... |
@@ -41,7 +33,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s |
41 | 41 |
var env []string |
42 | 42 |
children := daemon.children(container) |
43 | 43 |
|
44 |
- bridgeSettings := container.NetworkSettings.Networks["bridge"] |
|
44 |
+ bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()] |
|
45 | 45 |
if bridgeSettings == nil { |
46 | 46 |
return nil, nil |
47 | 47 |
} |
... | ... |
@@ -51,7 +43,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s |
51 | 51 |
return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias) |
52 | 52 |
} |
53 | 53 |
|
54 |
- childBridgeSettings := child.NetworkSettings.Networks["bridge"] |
|
54 |
+ childBridgeSettings := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()] |
|
55 | 55 |
if childBridgeSettings == nil { |
56 | 56 |
return nil, fmt.Errorf("container %s not attached to default bridge network", child.ID) |
57 | 57 |
} |
... | ... |
@@ -316,477 +308,6 @@ func (daemon *Daemon) getSize(container *container.Container) (int64, int64) { |
316 | 316 |
return sizeRw, sizeRootfs |
317 | 317 |
} |
318 | 318 |
|
319 |
-func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libnetwork.Network) ([]libnetwork.SandboxOption, error) { |
|
320 |
- var ( |
|
321 |
- sboxOptions []libnetwork.SandboxOption |
|
322 |
- err error |
|
323 |
- dns []string |
|
324 |
- dnsSearch []string |
|
325 |
- dnsOptions []string |
|
326 |
- bindings = make(nat.PortMap) |
|
327 |
- pbList []types.PortBinding |
|
328 |
- exposeList []types.TransportPort |
|
329 |
- ) |
|
330 |
- |
|
331 |
- sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), |
|
332 |
- libnetwork.OptionDomainname(container.Config.Domainname)) |
|
333 |
- |
|
334 |
- if container.HostConfig.NetworkMode.IsHost() { |
|
335 |
- sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) |
|
336 |
- sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) |
|
337 |
- sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) |
|
338 |
- } else if daemon.execDriver.SupportsHooks() { |
|
339 |
- // OptionUseExternalKey is mandatory for userns support. |
|
340 |
- // But optional for non-userns support |
|
341 |
- sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) |
|
342 |
- } |
|
343 |
- |
|
344 |
- container.HostsPath, err = container.GetRootResourcePath("hosts") |
|
345 |
- if err != nil { |
|
346 |
- return nil, err |
|
347 |
- } |
|
348 |
- sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) |
|
349 |
- |
|
350 |
- container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf") |
|
351 |
- if err != nil { |
|
352 |
- return nil, err |
|
353 |
- } |
|
354 |
- sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) |
|
355 |
- |
|
356 |
- if len(container.HostConfig.DNS) > 0 { |
|
357 |
- dns = container.HostConfig.DNS |
|
358 |
- } else if len(daemon.configStore.DNS) > 0 { |
|
359 |
- dns = daemon.configStore.DNS |
|
360 |
- } |
|
361 |
- |
|
362 |
- for _, d := range dns { |
|
363 |
- sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) |
|
364 |
- } |
|
365 |
- |
|
366 |
- if len(container.HostConfig.DNSSearch) > 0 { |
|
367 |
- dnsSearch = container.HostConfig.DNSSearch |
|
368 |
- } else if len(daemon.configStore.DNSSearch) > 0 { |
|
369 |
- dnsSearch = daemon.configStore.DNSSearch |
|
370 |
- } |
|
371 |
- |
|
372 |
- for _, ds := range dnsSearch { |
|
373 |
- sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) |
|
374 |
- } |
|
375 |
- |
|
376 |
- if len(container.HostConfig.DNSOptions) > 0 { |
|
377 |
- dnsOptions = container.HostConfig.DNSOptions |
|
378 |
- } else if len(daemon.configStore.DNSOptions) > 0 { |
|
379 |
- dnsOptions = daemon.configStore.DNSOptions |
|
380 |
- } |
|
381 |
- |
|
382 |
- for _, ds := range dnsOptions { |
|
383 |
- sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds)) |
|
384 |
- } |
|
385 |
- |
|
386 |
- if container.NetworkSettings.SecondaryIPAddresses != nil { |
|
387 |
- name := container.Config.Hostname |
|
388 |
- if container.Config.Domainname != "" { |
|
389 |
- name = name + "." + container.Config.Domainname |
|
390 |
- } |
|
391 |
- |
|
392 |
- for _, a := range container.NetworkSettings.SecondaryIPAddresses { |
|
393 |
- sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) |
|
394 |
- } |
|
395 |
- } |
|
396 |
- |
|
397 |
- for _, extraHost := range container.HostConfig.ExtraHosts { |
|
398 |
- // allow IPv6 addresses in extra hosts; only split on first ":" |
|
399 |
- parts := strings.SplitN(extraHost, ":", 2) |
|
400 |
- sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) |
|
401 |
- } |
|
402 |
- |
|
403 |
- if container.HostConfig.PortBindings != nil { |
|
404 |
- for p, b := range container.HostConfig.PortBindings { |
|
405 |
- bindings[p] = []nat.PortBinding{} |
|
406 |
- for _, bb := range b { |
|
407 |
- bindings[p] = append(bindings[p], nat.PortBinding{ |
|
408 |
- HostIP: bb.HostIP, |
|
409 |
- HostPort: bb.HostPort, |
|
410 |
- }) |
|
411 |
- } |
|
412 |
- } |
|
413 |
- } |
|
414 |
- |
|
415 |
- portSpecs := container.Config.ExposedPorts |
|
416 |
- ports := make([]nat.Port, len(portSpecs)) |
|
417 |
- var i int |
|
418 |
- for p := range portSpecs { |
|
419 |
- ports[i] = p |
|
420 |
- i++ |
|
421 |
- } |
|
422 |
- nat.SortPortMap(ports, bindings) |
|
423 |
- for _, port := range ports { |
|
424 |
- expose := types.TransportPort{} |
|
425 |
- expose.Proto = types.ParseProtocol(port.Proto()) |
|
426 |
- expose.Port = uint16(port.Int()) |
|
427 |
- exposeList = append(exposeList, expose) |
|
428 |
- |
|
429 |
- pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} |
|
430 |
- binding := bindings[port] |
|
431 |
- for i := 0; i < len(binding); i++ { |
|
432 |
- pbCopy := pb.GetCopy() |
|
433 |
- newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) |
|
434 |
- var portStart, portEnd int |
|
435 |
- if err == nil { |
|
436 |
- portStart, portEnd, err = newP.Range() |
|
437 |
- } |
|
438 |
- if err != nil { |
|
439 |
- return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) |
|
440 |
- } |
|
441 |
- pbCopy.HostPort = uint16(portStart) |
|
442 |
- pbCopy.HostPortEnd = uint16(portEnd) |
|
443 |
- pbCopy.HostIP = net.ParseIP(binding[i].HostIP) |
|
444 |
- pbList = append(pbList, pbCopy) |
|
445 |
- } |
|
446 |
- |
|
447 |
- if container.HostConfig.PublishAllPorts && len(binding) == 0 { |
|
448 |
- pbList = append(pbList, pb) |
|
449 |
- } |
|
450 |
- } |
|
451 |
- |
|
452 |
- sboxOptions = append(sboxOptions, |
|
453 |
- libnetwork.OptionPortMapping(pbList), |
|
454 |
- libnetwork.OptionExposedPorts(exposeList)) |
|
455 |
- |
|
456 |
- // Link feature is supported only for the default bridge network. |
|
457 |
- // return if this call to build join options is not for default bridge network |
|
458 |
- if n.Name() != "bridge" { |
|
459 |
- return sboxOptions, nil |
|
460 |
- } |
|
461 |
- |
|
462 |
- ep, _ := container.GetEndpointInNetwork(n) |
|
463 |
- if ep == nil { |
|
464 |
- return sboxOptions, nil |
|
465 |
- } |
|
466 |
- |
|
467 |
- var childEndpoints, parentEndpoints []string |
|
468 |
- |
|
469 |
- children := daemon.children(container) |
|
470 |
- for linkAlias, child := range children { |
|
471 |
- if !isLinkable(child) { |
|
472 |
- return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name) |
|
473 |
- } |
|
474 |
- _, alias := path.Split(linkAlias) |
|
475 |
- // allow access to the linked container via the alias, real name, and container hostname |
|
476 |
- aliasList := alias + " " + child.Config.Hostname |
|
477 |
- // only add the name if alias isn't equal to the name |
|
478 |
- if alias != child.Name[1:] { |
|
479 |
- aliasList = aliasList + " " + child.Name[1:] |
|
480 |
- } |
|
481 |
- sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks["bridge"].IPAddress)) |
|
482 |
- cEndpoint, _ := child.GetEndpointInNetwork(n) |
|
483 |
- if cEndpoint != nil && cEndpoint.ID() != "" { |
|
484 |
- childEndpoints = append(childEndpoints, cEndpoint.ID()) |
|
485 |
- } |
|
486 |
- } |
|
487 |
- |
|
488 |
- bridgeSettings := container.NetworkSettings.Networks["bridge"] |
|
489 |
- for alias, parent := range daemon.parents(container) { |
|
490 |
- if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() { |
|
491 |
- continue |
|
492 |
- } |
|
493 |
- |
|
494 |
- _, alias = path.Split(alias) |
|
495 |
- logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress) |
|
496 |
- sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate( |
|
497 |
- parent.ID, |
|
498 |
- alias, |
|
499 |
- bridgeSettings.IPAddress, |
|
500 |
- )) |
|
501 |
- if ep.ID() != "" { |
|
502 |
- parentEndpoints = append(parentEndpoints, ep.ID()) |
|
503 |
- } |
|
504 |
- } |
|
505 |
- |
|
506 |
- linkOptions := options.Generic{ |
|
507 |
- netlabel.GenericData: options.Generic{ |
|
508 |
- "ParentEndpoints": parentEndpoints, |
|
509 |
- "ChildEndpoints": childEndpoints, |
|
510 |
- }, |
|
511 |
- } |
|
512 |
- |
|
513 |
- sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) |
|
514 |
- return sboxOptions, nil |
|
515 |
-} |
|
516 |
- |
|
517 |
-func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network) error { |
|
518 |
- if container.NetworkSettings == nil { |
|
519 |
- container.NetworkSettings = &network.Settings{Networks: make(map[string]*networktypes.EndpointSettings)} |
|
520 |
- } |
|
521 |
- |
|
522 |
- if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { |
|
523 |
- return runconfig.ErrConflictHostNetwork |
|
524 |
- } |
|
525 |
- |
|
526 |
- for s := range container.NetworkSettings.Networks { |
|
527 |
- sn, err := daemon.FindNetwork(s) |
|
528 |
- if err != nil { |
|
529 |
- continue |
|
530 |
- } |
|
531 |
- |
|
532 |
- if sn.Name() == n.Name() { |
|
533 |
- // Avoid duplicate config |
|
534 |
- return nil |
|
535 |
- } |
|
536 |
- if !containertypes.NetworkMode(sn.Type()).IsPrivate() || |
|
537 |
- !containertypes.NetworkMode(n.Type()).IsPrivate() { |
|
538 |
- return runconfig.ErrConflictSharedNetwork |
|
539 |
- } |
|
540 |
- if containertypes.NetworkMode(sn.Name()).IsNone() || |
|
541 |
- containertypes.NetworkMode(n.Name()).IsNone() { |
|
542 |
- return runconfig.ErrConflictNoNetwork |
|
543 |
- } |
|
544 |
- } |
|
545 |
- |
|
546 |
- if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok { |
|
547 |
- container.NetworkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings) |
|
548 |
- } |
|
549 |
- |
|
550 |
- return nil |
|
551 |
-} |
|
552 |
- |
|
553 |
-func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error { |
|
554 |
- if err := container.BuildEndpointInfo(n, ep); err != nil { |
|
555 |
- return err |
|
556 |
- } |
|
557 |
- |
|
558 |
- if container.HostConfig.NetworkMode == containertypes.NetworkMode("bridge") { |
|
559 |
- container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface |
|
560 |
- } |
|
561 |
- |
|
562 |
- return nil |
|
563 |
-} |
|
564 |
- |
|
565 |
-// UpdateNetwork is used to update the container's network (e.g. when linked containers |
|
566 |
-// get removed/unlinked). |
|
567 |
-func (daemon *Daemon) updateNetwork(container *container.Container) error { |
|
568 |
- ctrl := daemon.netController |
|
569 |
- sid := container.NetworkSettings.SandboxID |
|
570 |
- |
|
571 |
- sb, err := ctrl.SandboxByID(sid) |
|
572 |
- if err != nil { |
|
573 |
- return fmt.Errorf("error locating sandbox id %s: %v", sid, err) |
|
574 |
- } |
|
575 |
- |
|
576 |
- // Find if container is connected to the default bridge network |
|
577 |
- var n libnetwork.Network |
|
578 |
- for name := range container.NetworkSettings.Networks { |
|
579 |
- sn, err := daemon.FindNetwork(name) |
|
580 |
- if err != nil { |
|
581 |
- continue |
|
582 |
- } |
|
583 |
- if sn.Name() == "bridge" { |
|
584 |
- n = sn |
|
585 |
- break |
|
586 |
- } |
|
587 |
- } |
|
588 |
- |
|
589 |
- if n == nil { |
|
590 |
- // Not connected to the default bridge network; Nothing to do |
|
591 |
- return nil |
|
592 |
- } |
|
593 |
- |
|
594 |
- options, err := daemon.buildSandboxOptions(container, n) |
|
595 |
- if err != nil { |
|
596 |
- return fmt.Errorf("Update network failed: %v", err) |
|
597 |
- } |
|
598 |
- |
|
599 |
- if err := sb.Refresh(options...); err != nil { |
|
600 |
- return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err) |
|
601 |
- } |
|
602 |
- |
|
603 |
- return nil |
|
604 |
-} |
|
605 |
- |
|
606 |
-// updateContainerNetworkSettings update the network settings |
|
607 |
-func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error { |
|
608 |
- var ( |
|
609 |
- n libnetwork.Network |
|
610 |
- err error |
|
611 |
- ) |
|
612 |
- |
|
613 |
- mode := container.HostConfig.NetworkMode |
|
614 |
- if container.Config.NetworkDisabled || mode.IsContainer() { |
|
615 |
- return nil |
|
616 |
- } |
|
617 |
- |
|
618 |
- networkName := mode.NetworkName() |
|
619 |
- if mode.IsDefault() { |
|
620 |
- networkName = daemon.netController.Config().Daemon.DefaultNetwork |
|
621 |
- } |
|
622 |
- if mode.IsUserDefined() { |
|
623 |
- n, err = daemon.FindNetwork(networkName) |
|
624 |
- if err != nil { |
|
625 |
- return err |
|
626 |
- } |
|
627 |
- networkName = n.Name() |
|
628 |
- } |
|
629 |
- if container.NetworkSettings == nil { |
|
630 |
- container.NetworkSettings = &network.Settings{} |
|
631 |
- } |
|
632 |
- if len(endpointsConfig) > 0 { |
|
633 |
- container.NetworkSettings.Networks = endpointsConfig |
|
634 |
- } |
|
635 |
- if container.NetworkSettings.Networks == nil { |
|
636 |
- container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings) |
|
637 |
- container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings) |
|
638 |
- } |
|
639 |
- if !mode.IsUserDefined() { |
|
640 |
- return nil |
|
641 |
- } |
|
642 |
- // Make sure to internally store the per network endpoint config by network name |
|
643 |
- if _, ok := container.NetworkSettings.Networks[networkName]; ok { |
|
644 |
- return nil |
|
645 |
- } |
|
646 |
- if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok { |
|
647 |
- container.NetworkSettings.Networks[networkName] = nwConfig |
|
648 |
- delete(container.NetworkSettings.Networks, n.ID()) |
|
649 |
- return nil |
|
650 |
- } |
|
651 |
- |
|
652 |
- return nil |
|
653 |
-} |
|
654 |
- |
|
655 |
-func (daemon *Daemon) allocateNetwork(container *container.Container) error { |
|
656 |
- controller := daemon.netController |
|
657 |
- |
|
658 |
- // Cleanup any stale sandbox left over due to ungraceful daemon shutdown |
|
659 |
- if err := controller.SandboxDestroy(container.ID); err != nil { |
|
660 |
- logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID) |
|
661 |
- } |
|
662 |
- |
|
663 |
- updateSettings := false |
|
664 |
- if len(container.NetworkSettings.Networks) == 0 { |
|
665 |
- if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() { |
|
666 |
- return nil |
|
667 |
- } |
|
668 |
- |
|
669 |
- err := daemon.updateContainerNetworkSettings(container, nil) |
|
670 |
- if err != nil { |
|
671 |
- return err |
|
672 |
- } |
|
673 |
- updateSettings = true |
|
674 |
- } |
|
675 |
- |
|
676 |
- for n, nConf := range container.NetworkSettings.Networks { |
|
677 |
- if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil { |
|
678 |
- return err |
|
679 |
- } |
|
680 |
- } |
|
681 |
- |
|
682 |
- return container.WriteHostConfig() |
|
683 |
-} |
|
684 |
- |
|
685 |
-func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox { |
|
686 |
- var sb libnetwork.Sandbox |
|
687 |
- daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool { |
|
688 |
- if s.ContainerID() == container.ID { |
|
689 |
- sb = s |
|
690 |
- return true |
|
691 |
- } |
|
692 |
- return false |
|
693 |
- }) |
|
694 |
- return sb |
|
695 |
-} |
|
696 |
- |
|
697 |
-// hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration |
|
698 |
-func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool { |
|
699 |
- return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0) |
|
700 |
-} |
|
701 |
- |
|
702 |
-// User specified ip address is acceptable only for networks with user specified subnets. |
|
703 |
-func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error { |
|
704 |
- if n == nil || epConfig == nil { |
|
705 |
- return nil |
|
706 |
- } |
|
707 |
- if !hasUserDefinedIPAddress(epConfig) { |
|
708 |
- return nil |
|
709 |
- } |
|
710 |
- _, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig() |
|
711 |
- for _, s := range []struct { |
|
712 |
- ipConfigured bool |
|
713 |
- subnetConfigs []*libnetwork.IpamConf |
|
714 |
- }{ |
|
715 |
- { |
|
716 |
- ipConfigured: len(epConfig.IPAMConfig.IPv4Address) > 0, |
|
717 |
- subnetConfigs: nwIPv4Configs, |
|
718 |
- }, |
|
719 |
- { |
|
720 |
- ipConfigured: len(epConfig.IPAMConfig.IPv6Address) > 0, |
|
721 |
- subnetConfigs: nwIPv6Configs, |
|
722 |
- }, |
|
723 |
- } { |
|
724 |
- if s.ipConfigured { |
|
725 |
- foundSubnet := false |
|
726 |
- for _, cfg := range s.subnetConfigs { |
|
727 |
- if len(cfg.PreferredPool) > 0 { |
|
728 |
- foundSubnet = true |
|
729 |
- break |
|
730 |
- } |
|
731 |
- } |
|
732 |
- if !foundSubnet { |
|
733 |
- return runconfig.ErrUnsupportedNetworkNoSubnetAndIP |
|
734 |
- } |
|
735 |
- } |
|
736 |
- } |
|
737 |
- |
|
738 |
- return nil |
|
739 |
-} |
|
740 |
- |
|
741 |
-// cleanOperationalData resets the operational data from the passed endpoint settings |
|
742 |
-func cleanOperationalData(es *networktypes.EndpointSettings) { |
|
743 |
- es.EndpointID = "" |
|
744 |
- es.Gateway = "" |
|
745 |
- es.IPAddress = "" |
|
746 |
- es.IPPrefixLen = 0 |
|
747 |
- es.IPv6Gateway = "" |
|
748 |
- es.GlobalIPv6Address = "" |
|
749 |
- es.GlobalIPv6PrefixLen = 0 |
|
750 |
- es.MacAddress = "" |
|
751 |
-} |
|
752 |
- |
|
753 |
-func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) { |
|
754 |
- if container.HostConfig.NetworkMode.IsContainer() { |
|
755 |
- return nil, runconfig.ErrConflictSharedNetwork |
|
756 |
- } |
|
757 |
- |
|
758 |
- if containertypes.NetworkMode(idOrName).IsBridge() && |
|
759 |
- daemon.configStore.DisableBridge { |
|
760 |
- container.Config.NetworkDisabled = true |
|
761 |
- return nil, nil |
|
762 |
- } |
|
763 |
- |
|
764 |
- if !containertypes.NetworkMode(idOrName).IsUserDefined() { |
|
765 |
- if hasUserDefinedIPAddress(endpointConfig) { |
|
766 |
- return nil, runconfig.ErrUnsupportedNetworkAndIP |
|
767 |
- } |
|
768 |
- if endpointConfig != nil && len(endpointConfig.Aliases) > 0 { |
|
769 |
- return nil, runconfig.ErrUnsupportedNetworkAndAlias |
|
770 |
- } |
|
771 |
- } |
|
772 |
- |
|
773 |
- n, err := daemon.FindNetwork(idOrName) |
|
774 |
- if err != nil { |
|
775 |
- return nil, err |
|
776 |
- } |
|
777 |
- |
|
778 |
- if err := validateNetworkingConfig(n, endpointConfig); err != nil { |
|
779 |
- return nil, err |
|
780 |
- } |
|
781 |
- |
|
782 |
- if updateSettings { |
|
783 |
- if err := daemon.updateNetworkSettings(container, n); err != nil { |
|
784 |
- return nil, err |
|
785 |
- } |
|
786 |
- } |
|
787 |
- return n, nil |
|
788 |
-} |
|
789 |
- |
|
790 | 319 |
// ConnectToNetwork connects a container to a network |
791 | 320 |
func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error { |
792 | 321 |
if !container.Running { |
... | ... |
@@ -810,83 +331,6 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName |
810 | 810 |
return nil |
811 | 811 |
} |
812 | 812 |
|
813 |
-func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) { |
|
814 |
- n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings) |
|
815 |
- if err != nil { |
|
816 |
- return err |
|
817 |
- } |
|
818 |
- if n == nil { |
|
819 |
- return nil |
|
820 |
- } |
|
821 |
- |
|
822 |
- controller := daemon.netController |
|
823 |
- |
|
824 |
- sb := daemon.getNetworkSandbox(container) |
|
825 |
- createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb) |
|
826 |
- if err != nil { |
|
827 |
- return err |
|
828 |
- } |
|
829 |
- |
|
830 |
- endpointName := strings.TrimPrefix(container.Name, "/") |
|
831 |
- ep, err := n.CreateEndpoint(endpointName, createOptions...) |
|
832 |
- if err != nil { |
|
833 |
- return err |
|
834 |
- } |
|
835 |
- defer func() { |
|
836 |
- if err != nil { |
|
837 |
- if e := ep.Delete(false); e != nil { |
|
838 |
- logrus.Warnf("Could not rollback container connection to network %s", idOrName) |
|
839 |
- } |
|
840 |
- } |
|
841 |
- }() |
|
842 |
- |
|
843 |
- if endpointConfig != nil { |
|
844 |
- container.NetworkSettings.Networks[n.Name()] = endpointConfig |
|
845 |
- } |
|
846 |
- |
|
847 |
- if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil { |
|
848 |
- return err |
|
849 |
- } |
|
850 |
- |
|
851 |
- if sb == nil { |
|
852 |
- options, err := daemon.buildSandboxOptions(container, n) |
|
853 |
- if err != nil { |
|
854 |
- return err |
|
855 |
- } |
|
856 |
- sb, err = controller.NewSandbox(container.ID, options...) |
|
857 |
- if err != nil { |
|
858 |
- return err |
|
859 |
- } |
|
860 |
- |
|
861 |
- container.UpdateSandboxNetworkSettings(sb) |
|
862 |
- } |
|
863 |
- |
|
864 |
- joinOptions, err := container.BuildJoinOptions(n) |
|
865 |
- if err != nil { |
|
866 |
- return err |
|
867 |
- } |
|
868 |
- |
|
869 |
- if err := ep.Join(sb, joinOptions...); err != nil { |
|
870 |
- return err |
|
871 |
- } |
|
872 |
- |
|
873 |
- if err := container.UpdateJoinInfo(n, ep); err != nil { |
|
874 |
- return fmt.Errorf("Updating join info failed: %v", err) |
|
875 |
- } |
|
876 |
- |
|
877 |
- daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID}) |
|
878 |
- return nil |
|
879 |
-} |
|
880 |
- |
|
881 |
-// ForceEndpointDelete deletes an endpoing from a network forcefully |
|
882 |
-func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error { |
|
883 |
- ep, err := n.EndpointByName(name) |
|
884 |
- if err != nil { |
|
885 |
- return err |
|
886 |
- } |
|
887 |
- return ep.Delete(true) |
|
888 |
-} |
|
889 |
- |
|
890 | 813 |
// DisconnectFromNetwork disconnects container from network n. |
891 | 814 |
func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { |
892 | 815 |
if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { |
... | ... |
@@ -918,91 +362,6 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li |
918 | 918 |
return nil |
919 | 919 |
} |
920 | 920 |
|
921 |
-func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { |
|
922 |
- var ( |
|
923 |
- ep libnetwork.Endpoint |
|
924 |
- sbox libnetwork.Sandbox |
|
925 |
- ) |
|
926 |
- |
|
927 |
- s := func(current libnetwork.Endpoint) bool { |
|
928 |
- epInfo := current.Info() |
|
929 |
- if epInfo == nil { |
|
930 |
- return false |
|
931 |
- } |
|
932 |
- if sb := epInfo.Sandbox(); sb != nil { |
|
933 |
- if sb.ContainerID() == container.ID { |
|
934 |
- ep = current |
|
935 |
- sbox = sb |
|
936 |
- return true |
|
937 |
- } |
|
938 |
- } |
|
939 |
- return false |
|
940 |
- } |
|
941 |
- n.WalkEndpoints(s) |
|
942 |
- |
|
943 |
- if ep == nil && force { |
|
944 |
- epName := strings.TrimPrefix(container.Name, "/") |
|
945 |
- ep, err := n.EndpointByName(epName) |
|
946 |
- if err != nil { |
|
947 |
- return err |
|
948 |
- } |
|
949 |
- return ep.Delete(force) |
|
950 |
- } |
|
951 |
- |
|
952 |
- if ep == nil { |
|
953 |
- return fmt.Errorf("container %s is not connected to the network", container.ID) |
|
954 |
- } |
|
955 |
- |
|
956 |
- if err := ep.Leave(sbox); err != nil { |
|
957 |
- return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err) |
|
958 |
- } |
|
959 |
- |
|
960 |
- if err := ep.Delete(false); err != nil { |
|
961 |
- return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err) |
|
962 |
- } |
|
963 |
- |
|
964 |
- delete(container.NetworkSettings.Networks, n.Name()) |
|
965 |
- return nil |
|
966 |
-} |
|
967 |
- |
|
968 |
-func (daemon *Daemon) initializeNetworking(container *container.Container) error { |
|
969 |
- var err error |
|
970 |
- |
|
971 |
- if container.HostConfig.NetworkMode.IsContainer() { |
|
972 |
- // we need to get the hosts files from the container to join |
|
973 |
- nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer()) |
|
974 |
- if err != nil { |
|
975 |
- return err |
|
976 |
- } |
|
977 |
- container.HostnamePath = nc.HostnamePath |
|
978 |
- container.HostsPath = nc.HostsPath |
|
979 |
- container.ResolvConfPath = nc.ResolvConfPath |
|
980 |
- container.Config.Hostname = nc.Config.Hostname |
|
981 |
- container.Config.Domainname = nc.Config.Domainname |
|
982 |
- return nil |
|
983 |
- } |
|
984 |
- |
|
985 |
- if container.HostConfig.NetworkMode.IsHost() { |
|
986 |
- container.Config.Hostname, err = os.Hostname() |
|
987 |
- if err != nil { |
|
988 |
- return err |
|
989 |
- } |
|
990 |
- |
|
991 |
- parts := strings.SplitN(container.Config.Hostname, ".", 2) |
|
992 |
- if len(parts) > 1 { |
|
993 |
- container.Config.Hostname = parts[0] |
|
994 |
- container.Config.Domainname = parts[1] |
|
995 |
- } |
|
996 |
- |
|
997 |
- } |
|
998 |
- |
|
999 |
- if err := daemon.allocateNetwork(container); err != nil { |
|
1000 |
- return err |
|
1001 |
- } |
|
1002 |
- |
|
1003 |
- return container.BuildHostnameFile() |
|
1004 |
-} |
|
1005 |
- |
|
1006 | 921 |
// called from the libcontainer pre-start hook to set the network |
1007 | 922 |
// namespace configuration linkage to the libnetwork "sandbox" entity |
1008 | 923 |
func (daemon *Daemon) setNetworkNamespaceKey(containerID string, pid int) error { |
... | ... |
@@ -1032,63 +391,6 @@ func (daemon *Daemon) getIpcContainer(container *container.Container) (*containe |
1032 | 1032 |
return c, nil |
1033 | 1033 |
} |
1034 | 1034 |
|
1035 |
-func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) { |
|
1036 |
- nc, err := daemon.GetContainer(connectedContainerID) |
|
1037 |
- if err != nil { |
|
1038 |
- return nil, err |
|
1039 |
- } |
|
1040 |
- if containerID == nc.ID { |
|
1041 |
- return nil, fmt.Errorf("cannot join own network") |
|
1042 |
- } |
|
1043 |
- if !nc.IsRunning() { |
|
1044 |
- err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID) |
|
1045 |
- return nil, errors.NewRequestConflictError(err) |
|
1046 |
- } |
|
1047 |
- if nc.IsRestarting() { |
|
1048 |
- return nil, errContainerIsRestarting(connectedContainerID) |
|
1049 |
- } |
|
1050 |
- return nc, nil |
|
1051 |
-} |
|
1052 |
- |
|
1053 |
-func (daemon *Daemon) releaseNetwork(container *container.Container) { |
|
1054 |
- if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled { |
|
1055 |
- return |
|
1056 |
- } |
|
1057 |
- |
|
1058 |
- sid := container.NetworkSettings.SandboxID |
|
1059 |
- settings := container.NetworkSettings.Networks |
|
1060 |
- container.NetworkSettings.Ports = nil |
|
1061 |
- |
|
1062 |
- if sid == "" || len(settings) == 0 { |
|
1063 |
- return |
|
1064 |
- } |
|
1065 |
- |
|
1066 |
- var networks []libnetwork.Network |
|
1067 |
- for n, epSettings := range settings { |
|
1068 |
- if nw, err := daemon.FindNetwork(n); err == nil { |
|
1069 |
- networks = append(networks, nw) |
|
1070 |
- } |
|
1071 |
- cleanOperationalData(epSettings) |
|
1072 |
- } |
|
1073 |
- |
|
1074 |
- sb, err := daemon.netController.SandboxByID(sid) |
|
1075 |
- if err != nil { |
|
1076 |
- logrus.Errorf("error locating sandbox id %s: %v", sid, err) |
|
1077 |
- return |
|
1078 |
- } |
|
1079 |
- |
|
1080 |
- if err := sb.Delete(); err != nil { |
|
1081 |
- logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) |
|
1082 |
- } |
|
1083 |
- |
|
1084 |
- attributes := map[string]string{ |
|
1085 |
- "container": container.ID, |
|
1086 |
- } |
|
1087 |
- for _, nw := range networks { |
|
1088 |
- daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes) |
|
1089 |
- } |
|
1090 |
-} |
|
1091 |
- |
|
1092 | 1035 |
func (daemon *Daemon) setupIpcDirs(c *container.Container) error { |
1093 | 1036 |
rootUID, rootGID := daemon.GetRemappedUIDGID() |
1094 | 1037 |
if !c.HasMountFor("/dev/shm") { |
... | ... |
@@ -1242,7 +544,7 @@ func detachMounted(path string) error { |
1242 | 1242 |
|
1243 | 1243 |
func isLinkable(child *container.Container) bool { |
1244 | 1244 |
// A container is linkable only if it belongs to the default network |
1245 |
- _, ok := child.NetworkSettings.Networks["bridge"] |
|
1245 |
+ _, ok := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()] |
|
1246 | 1246 |
return ok |
1247 | 1247 |
} |
1248 | 1248 |
|
... | ... |
@@ -6,11 +6,12 @@ import ( |
6 | 6 |
"fmt" |
7 | 7 |
"strings" |
8 | 8 |
|
9 |
+ networktypes "github.com/docker/engine-api/types/network" |
|
10 |
+ |
|
9 | 11 |
"github.com/docker/docker/container" |
10 | 12 |
"github.com/docker/docker/daemon/execdriver" |
11 | 13 |
"github.com/docker/docker/daemon/execdriver/windows" |
12 | 14 |
"github.com/docker/docker/layer" |
13 |
- networktypes "github.com/docker/engine-api/types/network" |
|
14 | 15 |
"github.com/docker/libnetwork" |
15 | 16 |
) |
16 | 17 |
|
... | ... |
@@ -18,28 +19,14 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s |
18 | 18 |
return nil, nil |
19 | 19 |
} |
20 | 20 |
|
21 |
-// updateContainerNetworkSettings update the network settings |
|
22 |
-func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error { |
|
23 |
- return nil |
|
24 |
-} |
|
25 |
- |
|
26 |
-func (daemon *Daemon) initializeNetworking(container *container.Container) error { |
|
27 |
- return nil |
|
28 |
-} |
|
29 |
- |
|
30 |
-// ConnectToNetwork connects a container to the network |
|
21 |
+// ConnectToNetwork connects a container to a network |
|
31 | 22 |
func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error { |
32 |
- return nil |
|
23 |
+ return fmt.Errorf("Windows does not support connecting a running container to a network") |
|
33 | 24 |
} |
34 | 25 |
|
35 |
-// ForceEndpointDelete deletes an endpoing from a network forcefully |
|
36 |
-func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error { |
|
37 |
- return nil |
|
38 |
-} |
|
39 |
- |
|
40 |
-// DisconnectFromNetwork disconnects a container from the network. |
|
26 |
+// DisconnectFromNetwork disconnects container from a network. |
|
41 | 27 |
func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { |
42 |
- return nil |
|
28 |
+ return fmt.Errorf("Windows does not support disconnecting a running container from a network") |
|
43 | 29 |
} |
44 | 30 |
|
45 | 31 |
func (daemon *Daemon) populateCommand(c *container.Container, env []string) error { |
... | ... |
@@ -47,24 +34,51 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro |
47 | 47 |
Interface: nil, |
48 | 48 |
} |
49 | 49 |
|
50 |
- parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2) |
|
51 |
- switch parts[0] { |
|
52 |
- case "none": |
|
53 |
- case "default", "": // empty string to support existing containers |
|
54 |
- if !c.Config.NetworkDisabled { |
|
55 |
- en.Interface = &execdriver.NetworkInterface{ |
|
56 |
- MacAddress: c.Config.MacAddress, |
|
57 |
- Bridge: daemon.configStore.bridgeConfig.VirtualSwitchName, |
|
58 |
- PortBindings: c.HostConfig.PortBindings, |
|
59 |
- |
|
60 |
- // TODO Windows. Include IPAddress. There already is a |
|
61 |
- // property IPAddress on execDrive.CommonNetworkInterface, |
|
62 |
- // but there is no CLI option in docker to pass through |
|
63 |
- // an IPAddress on docker run. |
|
50 |
+ var epList []string |
|
51 |
+ |
|
52 |
+ // Connect all the libnetwork allocated networks to the container |
|
53 |
+ if c.NetworkSettings != nil { |
|
54 |
+ for n := range c.NetworkSettings.Networks { |
|
55 |
+ sn, err := daemon.FindNetwork(n) |
|
56 |
+ if err != nil { |
|
57 |
+ continue |
|
58 |
+ } |
|
59 |
+ |
|
60 |
+ ep, err := c.GetEndpointInNetwork(sn) |
|
61 |
+ if err != nil { |
|
62 |
+ continue |
|
63 |
+ } |
|
64 |
+ |
|
65 |
+ data, err := ep.DriverInfo() |
|
66 |
+ if err != nil { |
|
67 |
+ continue |
|
68 |
+ } |
|
69 |
+ if data["hnsid"] != nil { |
|
70 |
+ epList = append(epList, data["hnsid"].(string)) |
|
64 | 71 |
} |
65 | 72 |
} |
66 |
- default: |
|
67 |
- return fmt.Errorf("invalid network mode: %s", c.HostConfig.NetworkMode) |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ if daemon.netController == nil { |
|
76 |
+ parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2) |
|
77 |
+ switch parts[0] { |
|
78 |
+ case "none": |
|
79 |
+ case "default", "": // empty string to support existing containers |
|
80 |
+ if !c.Config.NetworkDisabled { |
|
81 |
+ en.Interface = &execdriver.NetworkInterface{ |
|
82 |
+ MacAddress: c.Config.MacAddress, |
|
83 |
+ Bridge: daemon.configStore.bridgeConfig.Iface, |
|
84 |
+ PortBindings: c.HostConfig.PortBindings, |
|
85 |
+ |
|
86 |
+ // TODO Windows. Include IPAddress. There already is a |
|
87 |
+ // property IPAddress on execDrive.CommonNetworkInterface, |
|
88 |
+ // but there is no CLI option in docker to pass through |
|
89 |
+ // an IPAddress on docker run. |
|
90 |
+ } |
|
91 |
+ } |
|
92 |
+ default: |
|
93 |
+ return fmt.Errorf("invalid network mode: %s", c.HostConfig.NetworkMode) |
|
94 |
+ } |
|
68 | 95 |
} |
69 | 96 |
|
70 | 97 |
// TODO Windows. More resource controls to be implemented later. |
... | ... |
@@ -138,6 +152,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro |
138 | 138 |
Isolation: string(c.HostConfig.Isolation), |
139 | 139 |
ArgsEscaped: c.Config.ArgsEscaped, |
140 | 140 |
HvPartition: hvPartition, |
141 |
+ EpList: epList, |
|
141 | 142 |
} |
142 | 143 |
|
143 | 144 |
return nil |
... | ... |
@@ -154,18 +169,6 @@ func (daemon *Daemon) setNetworkNamespaceKey(containerID string, pid int) error |
154 | 154 |
return nil |
155 | 155 |
} |
156 | 156 |
|
157 |
-// allocateNetwork is a no-op on Windows. |
|
158 |
-func (daemon *Daemon) allocateNetwork(container *container.Container) error { |
|
159 |
- return nil |
|
160 |
-} |
|
161 |
- |
|
162 |
-func (daemon *Daemon) updateNetwork(container *container.Container) error { |
|
163 |
- return nil |
|
164 |
-} |
|
165 |
- |
|
166 |
-func (daemon *Daemon) releaseNetwork(container *container.Container) { |
|
167 |
-} |
|
168 |
- |
|
169 | 157 |
func (daemon *Daemon) setupIpcDirs(container *container.Container) error { |
170 | 158 |
return nil |
171 | 159 |
} |
... | ... |
@@ -187,3 +190,7 @@ func detachMounted(path string) error { |
187 | 187 |
func killProcessDirectly(container *container.Container) error { |
188 | 188 |
return nil |
189 | 189 |
} |
190 |
+ |
|
191 |
+func isLinkable(child *container.Container) bool { |
|
192 |
+ return false |
|
193 |
+} |
... | ... |
@@ -71,6 +71,7 @@ import ( |
71 | 71 |
"github.com/docker/docker/volume/store" |
72 | 72 |
"github.com/docker/go-connections/nat" |
73 | 73 |
"github.com/docker/libnetwork" |
74 |
+ nwconfig "github.com/docker/libnetwork/config" |
|
74 | 75 |
lntypes "github.com/docker/libnetwork/types" |
75 | 76 |
"github.com/docker/libtrust" |
76 | 77 |
"github.com/opencontainers/runc/libcontainer" |
... | ... |
@@ -1693,3 +1694,45 @@ func validateID(id string) error { |
1693 | 1693 |
} |
1694 | 1694 |
return nil |
1695 | 1695 |
} |
1696 |
+ |
|
1697 |
+func isBridgeNetworkDisabled(config *Config) bool { |
|
1698 |
+ return config.bridgeConfig.Iface == disableNetworkBridge |
|
1699 |
+} |
|
1700 |
+ |
|
1701 |
+func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) { |
|
1702 |
+ options := []nwconfig.Option{} |
|
1703 |
+ if dconfig == nil { |
|
1704 |
+ return options, nil |
|
1705 |
+ } |
|
1706 |
+ |
|
1707 |
+ options = append(options, nwconfig.OptionDataDir(dconfig.Root)) |
|
1708 |
+ |
|
1709 |
+ dd := runconfig.DefaultDaemonNetworkMode() |
|
1710 |
+ dn := runconfig.DefaultDaemonNetworkMode().NetworkName() |
|
1711 |
+ options = append(options, nwconfig.OptionDefaultDriver(string(dd))) |
|
1712 |
+ options = append(options, nwconfig.OptionDefaultNetwork(dn)) |
|
1713 |
+ |
|
1714 |
+ if strings.TrimSpace(dconfig.ClusterStore) != "" { |
|
1715 |
+ kv := strings.Split(dconfig.ClusterStore, "://") |
|
1716 |
+ if len(kv) != 2 { |
|
1717 |
+ return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL") |
|
1718 |
+ } |
|
1719 |
+ options = append(options, nwconfig.OptionKVProvider(kv[0])) |
|
1720 |
+ options = append(options, nwconfig.OptionKVProviderURL(kv[1])) |
|
1721 |
+ } |
|
1722 |
+ if len(dconfig.ClusterOpts) > 0 { |
|
1723 |
+ options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts)) |
|
1724 |
+ } |
|
1725 |
+ |
|
1726 |
+ if daemon.discoveryWatcher != nil { |
|
1727 |
+ options = append(options, nwconfig.OptionDiscoveryWatcher(daemon.discoveryWatcher)) |
|
1728 |
+ } |
|
1729 |
+ |
|
1730 |
+ if dconfig.ClusterAdvertise != "" { |
|
1731 |
+ options = append(options, nwconfig.OptionDiscoveryAddress(dconfig.ClusterAdvertise)) |
|
1732 |
+ } |
|
1733 |
+ |
|
1734 |
+ options = append(options, nwconfig.OptionLabels(dconfig.Labels)) |
|
1735 |
+ options = append(options, driverOptions(dconfig)...) |
|
1736 |
+ return options, nil |
|
1737 |
+} |
... | ... |
@@ -518,48 +518,6 @@ func configureKernelSecuritySupport(config *Config, driverName string) error { |
518 | 518 |
return nil |
519 | 519 |
} |
520 | 520 |
|
521 |
-func isBridgeNetworkDisabled(config *Config) bool { |
|
522 |
- return config.bridgeConfig.Iface == disableNetworkBridge |
|
523 |
-} |
|
524 |
- |
|
525 |
-func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) { |
|
526 |
- options := []nwconfig.Option{} |
|
527 |
- if dconfig == nil { |
|
528 |
- return options, nil |
|
529 |
- } |
|
530 |
- |
|
531 |
- options = append(options, nwconfig.OptionDataDir(dconfig.Root)) |
|
532 |
- |
|
533 |
- dd := runconfig.DefaultDaemonNetworkMode() |
|
534 |
- dn := runconfig.DefaultDaemonNetworkMode().NetworkName() |
|
535 |
- options = append(options, nwconfig.OptionDefaultDriver(string(dd))) |
|
536 |
- options = append(options, nwconfig.OptionDefaultNetwork(dn)) |
|
537 |
- |
|
538 |
- if strings.TrimSpace(dconfig.ClusterStore) != "" { |
|
539 |
- kv := strings.Split(dconfig.ClusterStore, "://") |
|
540 |
- if len(kv) != 2 { |
|
541 |
- return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL") |
|
542 |
- } |
|
543 |
- options = append(options, nwconfig.OptionKVProvider(kv[0])) |
|
544 |
- options = append(options, nwconfig.OptionKVProviderURL(kv[1])) |
|
545 |
- } |
|
546 |
- if len(dconfig.ClusterOpts) > 0 { |
|
547 |
- options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts)) |
|
548 |
- } |
|
549 |
- |
|
550 |
- if daemon.discoveryWatcher != nil { |
|
551 |
- options = append(options, nwconfig.OptionDiscoveryWatcher(daemon.discoveryWatcher)) |
|
552 |
- } |
|
553 |
- |
|
554 |
- if dconfig.ClusterAdvertise != "" { |
|
555 |
- options = append(options, nwconfig.OptionDiscoveryAddress(dconfig.ClusterAdvertise)) |
|
556 |
- } |
|
557 |
- |
|
558 |
- options = append(options, nwconfig.OptionLabels(dconfig.Labels)) |
|
559 |
- options = append(options, driverOptions(dconfig)...) |
|
560 |
- return options, nil |
|
561 |
-} |
|
562 |
- |
|
563 | 521 |
func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) { |
564 | 522 |
netOptions, err := daemon.networkOptions(config) |
565 | 523 |
if err != nil { |
... | ... |
@@ -9,6 +9,7 @@ import ( |
9 | 9 |
"runtime" |
10 | 10 |
"strings" |
11 | 11 |
|
12 |
+ "github.com/Microsoft/hcsshim" |
|
12 | 13 |
"github.com/Sirupsen/logrus" |
13 | 14 |
"github.com/docker/docker/container" |
14 | 15 |
"github.com/docker/docker/daemon/graphdriver" |
... | ... |
@@ -16,6 +17,7 @@ import ( |
16 | 16 |
"github.com/docker/docker/image" |
17 | 17 |
"github.com/docker/docker/layer" |
18 | 18 |
"github.com/docker/docker/reference" |
19 |
+ "github.com/docker/docker/runconfig" |
|
19 | 20 |
containertypes "github.com/docker/engine-api/types/container" |
20 | 21 |
// register the windows graph driver |
21 | 22 |
"github.com/docker/docker/daemon/graphdriver/windows" |
... | ... |
@@ -23,11 +25,15 @@ import ( |
23 | 23 |
"github.com/docker/docker/pkg/system" |
24 | 24 |
"github.com/docker/libnetwork" |
25 | 25 |
nwconfig "github.com/docker/libnetwork/config" |
26 |
+ winlibnetwork "github.com/docker/libnetwork/drivers/windows" |
|
27 |
+ "github.com/docker/libnetwork/netlabel" |
|
28 |
+ "github.com/docker/libnetwork/options" |
|
26 | 29 |
blkiodev "github.com/opencontainers/runc/libcontainer/configs" |
27 | 30 |
) |
28 | 31 |
|
29 | 32 |
const ( |
30 | 33 |
defaultVirtualSwitch = "Virtual Switch" |
34 |
+ defaultNetworkSpace = "172.16.0.0/12" |
|
31 | 35 |
platformSupported = true |
32 | 36 |
windowsMinCPUShares = 1 |
33 | 37 |
windowsMaxCPUShares = 10000 |
... | ... |
@@ -125,16 +131,154 @@ func configureMaxThreads(config *Config) error { |
125 | 125 |
return nil |
126 | 126 |
} |
127 | 127 |
|
128 |
-func isBridgeNetworkDisabled(config *Config) bool { |
|
129 |
- return false |
|
128 |
+func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) { |
|
129 |
+ // TODO Windows: Remove this check once TP4 is no longer supported |
|
130 |
+ osv, err := system.GetOSVersion() |
|
131 |
+ if err != nil { |
|
132 |
+ return nil, err |
|
133 |
+ } |
|
134 |
+ |
|
135 |
+ if osv.Build < 14260 { |
|
136 |
+ // Set the name of the virtual switch if not specified by -b on daemon start |
|
137 |
+ if config.bridgeConfig.Iface == "" { |
|
138 |
+ config.bridgeConfig.Iface = defaultVirtualSwitch |
|
139 |
+ } |
|
140 |
+ logrus.Warnf("Network controller is not supported by the current platform build version") |
|
141 |
+ return nil, nil |
|
142 |
+ } |
|
143 |
+ |
|
144 |
+ netOptions, err := daemon.networkOptions(config) |
|
145 |
+ if err != nil { |
|
146 |
+ return nil, err |
|
147 |
+ } |
|
148 |
+ controller, err := libnetwork.New(netOptions...) |
|
149 |
+ if err != nil { |
|
150 |
+ return nil, fmt.Errorf("error obtaining controller instance: %v", err) |
|
151 |
+ } |
|
152 |
+ |
|
153 |
+ hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "") |
|
154 |
+ if err != nil { |
|
155 |
+ return nil, err |
|
156 |
+ } |
|
157 |
+ |
|
158 |
+ // Remove networks not present in HNS |
|
159 |
+ for _, v := range controller.Networks() { |
|
160 |
+ options := v.Info().DriverOptions() |
|
161 |
+ hnsid := options[winlibnetwork.HNSID] |
|
162 |
+ found := false |
|
163 |
+ |
|
164 |
+ for _, v := range hnsresponse { |
|
165 |
+ if v.Id == hnsid { |
|
166 |
+ found = true |
|
167 |
+ break |
|
168 |
+ } |
|
169 |
+ } |
|
170 |
+ |
|
171 |
+ if !found { |
|
172 |
+ err = v.Delete() |
|
173 |
+ if err != nil { |
|
174 |
+ return nil, err |
|
175 |
+ } |
|
176 |
+ } |
|
177 |
+ } |
|
178 |
+ |
|
179 |
+ _, err = controller.NewNetwork("null", "none", libnetwork.NetworkOptionPersist(false)) |
|
180 |
+ if err != nil { |
|
181 |
+ return nil, err |
|
182 |
+ } |
|
183 |
+ |
|
184 |
+ // discover and add HNS networks to windows |
|
185 |
+ // network that exist are removed and added again |
|
186 |
+ for _, v := range hnsresponse { |
|
187 |
+ var n libnetwork.Network |
|
188 |
+ s := func(current libnetwork.Network) bool { |
|
189 |
+ options := current.Info().DriverOptions() |
|
190 |
+ if options[winlibnetwork.HNSID] == v.Id { |
|
191 |
+ n = current |
|
192 |
+ return true |
|
193 |
+ } |
|
194 |
+ return false |
|
195 |
+ } |
|
196 |
+ |
|
197 |
+ controller.WalkNetworks(s) |
|
198 |
+ if n != nil { |
|
199 |
+ v.Name = n.Name() |
|
200 |
+ n.Delete() |
|
201 |
+ } |
|
202 |
+ |
|
203 |
+ netOption := map[string]string{ |
|
204 |
+ winlibnetwork.NetworkName: v.Name, |
|
205 |
+ winlibnetwork.HNSID: v.Id, |
|
206 |
+ } |
|
207 |
+ |
|
208 |
+ v4Conf := []*libnetwork.IpamConf{} |
|
209 |
+ for _, subnet := range v.Subnets { |
|
210 |
+ ipamV4Conf := libnetwork.IpamConf{} |
|
211 |
+ ipamV4Conf.PreferredPool = subnet.AddressPrefix |
|
212 |
+ ipamV4Conf.Gateway = subnet.GatewayAddress |
|
213 |
+ v4Conf = append(v4Conf, &ipamV4Conf) |
|
214 |
+ } |
|
215 |
+ |
|
216 |
+ name := v.Name |
|
217 |
+ // There is only one nat network supported in windows. |
|
218 |
+ // If it exists with a different name add it as the default name |
|
219 |
+ if runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) { |
|
220 |
+ name = runconfig.DefaultDaemonNetworkMode().NetworkName() |
|
221 |
+ } |
|
222 |
+ |
|
223 |
+ v6Conf := []*libnetwork.IpamConf{} |
|
224 |
+ _, err := controller.NewNetwork(strings.ToLower(v.Type), name, |
|
225 |
+ libnetwork.NetworkOptionGeneric(options.Generic{ |
|
226 |
+ netlabel.GenericData: netOption, |
|
227 |
+ }), |
|
228 |
+ libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), |
|
229 |
+ ) |
|
230 |
+ |
|
231 |
+ if err != nil { |
|
232 |
+ logrus.Errorf("Error occurred when creating network %v", err) |
|
233 |
+ } |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+ if !config.DisableBridge { |
|
237 |
+ // Initialize default driver "bridge" |
|
238 |
+ if err := initBridgeDriver(controller, config); err != nil { |
|
239 |
+ return nil, err |
|
240 |
+ } |
|
241 |
+ } |
|
242 |
+ |
|
243 |
+ return controller, nil |
|
130 | 244 |
} |
131 | 245 |
|
132 |
-func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) { |
|
133 |
- // Set the name of the virtual switch if not specified by -b on daemon start |
|
134 |
- if config.bridgeConfig.VirtualSwitchName == "" { |
|
135 |
- config.bridgeConfig.VirtualSwitchName = defaultVirtualSwitch |
|
246 |
+func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { |
|
247 |
+ if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil { |
|
248 |
+ return nil |
|
136 | 249 |
} |
137 |
- return nil, nil |
|
250 |
+ |
|
251 |
+ netOption := map[string]string{ |
|
252 |
+ winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(), |
|
253 |
+ } |
|
254 |
+ |
|
255 |
+ ipamV4Conf := libnetwork.IpamConf{} |
|
256 |
+ if config.bridgeConfig.FixedCIDR == "" { |
|
257 |
+ ipamV4Conf.PreferredPool = defaultNetworkSpace |
|
258 |
+ } else { |
|
259 |
+ ipamV4Conf.PreferredPool = config.bridgeConfig.FixedCIDR |
|
260 |
+ } |
|
261 |
+ |
|
262 |
+ v4Conf := []*libnetwork.IpamConf{&ipamV4Conf} |
|
263 |
+ v6Conf := []*libnetwork.IpamConf{} |
|
264 |
+ |
|
265 |
+ _, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), |
|
266 |
+ libnetwork.NetworkOptionGeneric(options.Generic{ |
|
267 |
+ netlabel.GenericData: netOption, |
|
268 |
+ }), |
|
269 |
+ libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), |
|
270 |
+ ) |
|
271 |
+ |
|
272 |
+ if err != nil { |
|
273 |
+ return fmt.Errorf("Error creating default network: %v", err) |
|
274 |
+ } |
|
275 |
+ return nil |
|
138 | 276 |
} |
139 | 277 |
|
140 | 278 |
// registerLinks sets up links between containers and writes the |
... | ... |
@@ -257,6 +401,6 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro |
257 | 257 |
return nil |
258 | 258 |
} |
259 | 259 |
|
260 |
-func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) { |
|
261 |
- return nil, fmt.Errorf("Network controller config reload not aavailable on Windows yet") |
|
260 |
+func driverOptions(config *Config) []nwconfig.Option { |
|
261 |
+ return []nwconfig.Option{} |
|
262 | 262 |
} |
... | ... |
@@ -56,6 +56,7 @@ type Command struct { |
56 | 56 |
Isolation string `json:"isolation"` // Isolation technology for the container |
57 | 57 |
ArgsEscaped bool `json:"args_escaped"` // True if args are already escaped |
58 | 58 |
HvPartition bool `json:"hv_partition"` // True if it's an hypervisor partition |
59 |
+ EpList []string `json:"endpoints"` // List of network endpoints for HNS |
|
59 | 60 |
} |
60 | 61 |
|
61 | 62 |
// ExitStatus provides exit reasons for a container. |
... | ... |
@@ -89,6 +89,7 @@ type containerInit struct { |
89 | 89 |
MappedDirectories []mappedDir // List of mapped directories (volumes/mounts) |
90 | 90 |
SandboxPath string // Location of unmounted sandbox (used for Hyper-V containers, not Windows Server containers) |
91 | 91 |
HvPartition bool // True if it a Hyper-V Container |
92 |
+ EndpointList []string // List of endpoints to be attached to container |
|
92 | 93 |
} |
93 | 94 |
|
94 | 95 |
// defaultOwner is a tag passed to HCS to allow it to differentiate between |
... | ... |
@@ -104,6 +105,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd |
104 | 104 |
err error |
105 | 105 |
) |
106 | 106 |
|
107 |
+ // Allocate Network only if there is no network interface |
|
107 | 108 |
cu := &containerInit{ |
108 | 109 |
SystemType: "Container", |
109 | 110 |
Name: c.ID, |
... | ... |
@@ -114,6 +116,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd |
114 | 114 |
LayerFolderPath: c.LayerFolder, |
115 | 115 |
ProcessorWeight: c.Resources.CPUShares, |
116 | 116 |
HostName: c.Hostname, |
117 |
+ EndpointList: c.EpList, |
|
117 | 118 |
} |
118 | 119 |
|
119 | 120 |
cu.HvPartition = c.HvPartition |
120 | 121 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,20 @@ |
0 |
+#!/bin/bash |
|
1 |
+set -e |
|
2 |
+ |
|
3 |
+# explicit list of os/arch combos that support being a daemon |
|
4 |
+declare -A daemonSupporting |
|
5 |
+daemonSupporting=( |
|
6 |
+ [linux/amd64]=1 |
|
7 |
+ [windows/amd64]=1 |
|
8 |
+) |
|
9 |
+platform="windows/amd64" |
|
10 |
+export DEST="$DEST/$platform" # bundles/VERSION/cross/GOOS/GOARCH/docker-VERSION |
|
11 |
+mkdir -p "$DEST" |
|
12 |
+ABS_DEST="$(cd "$DEST" && pwd -P)" |
|
13 |
+export GOOS=${platform%/*} |
|
14 |
+export GOARCH=${platform##*/} |
|
15 |
+if [ -z "${daemonSupporting[$platform]}" ]; then |
|
16 |
+ export LDFLAGS_STATIC_DOCKER="" # we just need a simple client for these platforms |
|
17 |
+ export BUILDFLAGS=( "${ORIG_BUILDFLAGS[@]/ daemon/}" ) # remove the "daemon" build tag from platforms that aren't supported |
|
18 |
+fi |
|
19 |
+source "${MAKEDIR}/binary" |
... | ... |
@@ -10,25 +10,22 @@ import ( |
10 | 10 |
// DefaultDaemonNetworkMode returns the default network stack the daemon should |
11 | 11 |
// use. |
12 | 12 |
func DefaultDaemonNetworkMode() container.NetworkMode { |
13 |
- return container.NetworkMode("default") |
|
13 |
+ return container.NetworkMode("nat") |
|
14 | 14 |
} |
15 | 15 |
|
16 | 16 |
// IsPreDefinedNetwork indicates if a network is predefined by the daemon |
17 | 17 |
func IsPreDefinedNetwork(network string) bool { |
18 |
- return false |
|
18 |
+ return !container.NetworkMode(network).IsUserDefined() |
|
19 | 19 |
} |
20 | 20 |
|
21 | 21 |
// ValidateNetMode ensures that the various combinations of requested |
22 | 22 |
// network settings are valid. |
23 | 23 |
func ValidateNetMode(c *container.Config, hc *container.HostConfig) error { |
24 |
- // We may not be passed a host config, such as in the case of docker commit |
|
25 | 24 |
if hc == nil { |
26 | 25 |
return nil |
27 | 26 |
} |
28 | 27 |
parts := strings.Split(string(hc.NetworkMode), ":") |
29 |
- switch mode := parts[0]; mode { |
|
30 |
- case "default", "none": |
|
31 |
- default: |
|
28 |
+ if len(parts) > 1 { |
|
32 | 29 |
return fmt.Errorf("invalid --net: %s", hc.NetworkMode) |
33 | 30 |
} |
34 | 31 |
return nil |