| ... | ... |
@@ -8,6 +8,14 @@ ciargs = -e CIRCLECI -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER= |
| 8 | 8 |
cidocker = docker run ${dockerargs} ${ciargs} $$EXTRA_ARGS ${container_env} ${build_image}
|
| 9 | 9 |
CROSS_PLATFORMS = linux/amd64 linux/386 linux/arm windows/amd64 |
| 10 | 10 |
export PATH := $(CURDIR)/bin:$(PATH) |
| 11 |
+hostOS = ${shell go env GOHOSTOS}
|
|
| 12 |
+ifeq (${hostOS}, solaris)
|
|
| 13 |
+ gnufind=gfind |
|
| 14 |
+ gnutail=gtail |
|
| 15 |
+else |
|
| 16 |
+ gnufind=find |
|
| 17 |
+ gnutail=tail |
|
| 18 |
+endif |
|
| 11 | 19 |
|
| 12 | 20 |
all: ${build_image}.created build check integration-tests clean
|
| 13 | 21 |
|
| ... | ... |
@@ -62,7 +70,40 @@ check-format: |
| 62 | 62 |
run-tests: |
| 63 | 63 |
@echo "Running tests... " |
| 64 | 64 |
@echo "mode: count" > coverage.coverprofile |
| 65 |
- @for dir in $$(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \ |
|
| 65 |
+ @for dir in $$( ${gnufind} . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \
|
|
| 66 |
+ if [ ${hostOS} == solaris ]; then \
|
|
| 67 |
+ case "$$dir" in \ |
|
| 68 |
+ "./cmd/dnet" ) \ |
|
| 69 |
+ ;& \ |
|
| 70 |
+ "./cmd/ovrouter" ) \ |
|
| 71 |
+ ;& \ |
|
| 72 |
+ "./ns" ) \ |
|
| 73 |
+ ;& \ |
|
| 74 |
+ "./iptables" ) \ |
|
| 75 |
+ ;& \ |
|
| 76 |
+ "./ipvs" ) \ |
|
| 77 |
+ ;& \ |
|
| 78 |
+ "./drivers/bridge" ) \ |
|
| 79 |
+ ;& \ |
|
| 80 |
+ "./drivers/host" ) \ |
|
| 81 |
+ ;& \ |
|
| 82 |
+ "./drivers/ipvlan" ) \ |
|
| 83 |
+ ;& \ |
|
| 84 |
+ "./drivers/macvlan" ) \ |
|
| 85 |
+ ;& \ |
|
| 86 |
+ "./drivers/overlay" ) \ |
|
| 87 |
+ ;& \ |
|
| 88 |
+ "./drivers/remote" ) \ |
|
| 89 |
+ ;& \ |
|
| 90 |
+ "./drivers/windows" ) \ |
|
| 91 |
+ echo "Skipping $$dir on solaris host... "; \ |
|
| 92 |
+ continue; \ |
|
| 93 |
+ ;; \ |
|
| 94 |
+ * )\ |
|
| 95 |
+ echo "Entering $$dir ... "; \ |
|
| 96 |
+ ;; \ |
|
| 97 |
+ esac; \ |
|
| 98 |
+ fi; \ |
|
| 66 | 99 |
if ls $$dir/*.go &> /dev/null; then \ |
| 67 | 100 |
pushd . &> /dev/null ; \ |
| 68 | 101 |
cd $$dir ; \ |
| ... | ... |
@@ -71,7 +112,7 @@ run-tests: |
| 71 | 71 |
if [ $$ret -ne 0 ]; then exit $$ret; fi ;\ |
| 72 | 72 |
popd &> /dev/null; \ |
| 73 | 73 |
if [ -f $$dir/profile.tmp ]; then \ |
| 74 |
- cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \ |
|
| 74 |
+ cat $$dir/profile.tmp | ${gnutail} -n +2 >> coverage.coverprofile ; \
|
|
| 75 | 75 |
rm $$dir/profile.tmp ; \ |
| 76 | 76 |
fi ; \ |
| 77 | 77 |
fi ; \ |
| 78 | 78 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,18 @@ |
| 0 |
+package api |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/libnetwork/drivers/bridge" |
|
| 4 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func GetOpsMap(bridgeName, defaultMTU string) map[string]string {
|
|
| 8 |
+ if defaultMTU == "" {
|
|
| 9 |
+ return map[string]string{
|
|
| 10 |
+ bridge.BridgeName: bridgeName, |
|
| 11 |
+ } |
|
| 12 |
+ } |
|
| 13 |
+ return map[string]string{
|
|
| 14 |
+ bridge.BridgeName: bridgeName, |
|
| 15 |
+ netlabel.DriverMTU: defaultMTU, |
|
| 16 |
+ } |
|
| 17 |
+} |
| 0 | 18 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,18 @@ |
| 0 |
+package api |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/libnetwork/drivers/solaris/bridge" |
|
| 4 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func GetOpsMap(bridgeName, defaultMTU string) map[string]string {
|
|
| 8 |
+ if defaultMTU == "" {
|
|
| 9 |
+ return map[string]string{
|
|
| 10 |
+ bridge.BridgeName: bridgeName, |
|
| 11 |
+ } |
|
| 12 |
+ } |
|
| 13 |
+ return map[string]string{
|
|
| 14 |
+ bridge.BridgeName: bridgeName, |
|
| 15 |
+ netlabel.DriverMTU: defaultMTU, |
|
| 16 |
+ } |
|
| 17 |
+} |
| ... | ... |
@@ -15,7 +15,6 @@ import ( |
| 15 | 15 |
"github.com/docker/docker/pkg/reexec" |
| 16 | 16 |
"github.com/docker/libnetwork" |
| 17 | 17 |
"github.com/docker/libnetwork/datastore" |
| 18 |
- "github.com/docker/libnetwork/drivers/bridge" |
|
| 19 | 18 |
"github.com/docker/libnetwork/netlabel" |
| 20 | 19 |
"github.com/docker/libnetwork/options" |
| 21 | 20 |
"github.com/docker/libnetwork/testutils" |
| ... | ... |
@@ -225,9 +224,7 @@ func TestCreateDeleteNetwork(t *testing.T) {
|
| 225 | 225 |
t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
|
| 226 | 226 |
} |
| 227 | 227 |
|
| 228 |
- dops := map[string]string{
|
|
| 229 |
- bridge.BridgeName: "abc", |
|
| 230 |
- } |
|
| 228 |
+ dops := GetOpsMap("abc", "")
|
|
| 231 | 229 |
nops := map[string]string{
|
| 232 | 230 |
netlabel.EnableIPv6: "true", |
| 233 | 231 |
} |
| ... | ... |
@@ -273,9 +270,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
| 273 | 273 |
} |
| 274 | 274 |
defer c.Stop() |
| 275 | 275 |
|
| 276 |
- ops := map[string]string{
|
|
| 277 |
- bridge.BridgeName: "api_test_nw", |
|
| 278 |
- } |
|
| 276 |
+ ops := GetOpsMap("api_test_nw", "")
|
|
| 279 | 277 |
nc := networkCreate{Name: "sh", NetworkType: bridgeNetType, DriverOpts: ops}
|
| 280 | 278 |
body, err := json.Marshal(nc) |
| 281 | 279 |
if err != nil {
|
| ... | ... |
@@ -544,7 +539,7 @@ func TestProcGetServices(t *testing.T) {
|
| 544 | 544 |
t.Fatal(err) |
| 545 | 545 |
} |
| 546 | 546 |
|
| 547 |
- netName2 := "work-dev" |
|
| 547 |
+ netName2 := "workdev" |
|
| 548 | 548 |
netOption = options.Generic{
|
| 549 | 549 |
netlabel.GenericData: options.Generic{
|
| 550 | 550 |
"BridgeName": netName2, |
| ... | ... |
@@ -1811,10 +1806,7 @@ func TestEndToEnd(t *testing.T) {
|
| 1811 | 1811 |
|
| 1812 | 1812 |
handleRequest := NewHTTPHandler(c) |
| 1813 | 1813 |
|
| 1814 |
- dops := map[string]string{
|
|
| 1815 |
- bridge.BridgeName: "cdef", |
|
| 1816 |
- netlabel.DriverMTU: "1460", |
|
| 1817 |
- } |
|
| 1814 |
+ dops := GetOpsMap("cdef", "1460")
|
|
| 1818 | 1815 |
nops := map[string]string{
|
| 1819 | 1816 |
netlabel.EnableIPv6: "true", |
| 1820 | 1817 |
} |
| 1821 | 1818 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,1254 @@ |
| 0 |
+// +build solaris |
|
| 1 |
+ |
|
| 2 |
+package bridge |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "bufio" |
|
| 6 |
+ "errors" |
|
| 7 |
+ "fmt" |
|
| 8 |
+ "net" |
|
| 9 |
+ "os" |
|
| 10 |
+ "os/exec" |
|
| 11 |
+ "strconv" |
|
| 12 |
+ "strings" |
|
| 13 |
+ "sync" |
|
| 14 |
+ |
|
| 15 |
+ "github.com/Sirupsen/logrus" |
|
| 16 |
+ "github.com/docker/libnetwork/datastore" |
|
| 17 |
+ "github.com/docker/libnetwork/discoverapi" |
|
| 18 |
+ "github.com/docker/libnetwork/driverapi" |
|
| 19 |
+ "github.com/docker/libnetwork/iptables" |
|
| 20 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 21 |
+ "github.com/docker/libnetwork/netutils" |
|
| 22 |
+ "github.com/docker/libnetwork/options" |
|
| 23 |
+ "github.com/docker/libnetwork/portmapper" |
|
| 24 |
+ "github.com/docker/libnetwork/types" |
|
| 25 |
+) |
|
| 26 |
+ |
|
| 27 |
+const ( |
|
| 28 |
+ networkType = "bridge" |
|
| 29 |
+ |
|
| 30 |
+ // DefaultBridgeName is the default name for the bridge interface managed |
|
| 31 |
+ // by the driver when unspecified by the caller. |
|
| 32 |
+ DefaultBridgeName = "docker0" |
|
| 33 |
+ |
|
| 34 |
+ // BridgeName label for bridge driver |
|
| 35 |
+ BridgeName = "com.docker.network.bridge.name" |
|
| 36 |
+ |
|
| 37 |
+ // EnableIPMasquerade label for bridge driver |
|
| 38 |
+ EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade" |
|
| 39 |
+ |
|
| 40 |
+ // EnableICC label |
|
| 41 |
+ EnableICC = "com.docker.network.bridge.enable_icc" |
|
| 42 |
+ |
|
| 43 |
+ // DefaultBindingIP label |
|
| 44 |
+ DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4" |
|
| 45 |
+ |
|
| 46 |
+ // DefaultBridge label |
|
| 47 |
+ DefaultBridge = "com.docker.network.bridge.default_bridge" |
|
| 48 |
+ |
|
| 49 |
+ // DefaultGatewayV4AuxKey represents the default-gateway configured by the user |
|
| 50 |
+ DefaultGatewayV4AuxKey = "DefaultGatewayIPv4" |
|
| 51 |
+ |
|
| 52 |
+ // DefaultGatewayV6AuxKey represents the ipv6 default-gateway configured by the user |
|
| 53 |
+ DefaultGatewayV6AuxKey = "DefaultGatewayIPv6" |
|
| 54 |
+) |
|
| 55 |
+ |
|
| 56 |
+// configuration info for the "bridge" driver. |
|
| 57 |
+type configuration struct {
|
|
| 58 |
+ EnableIPForwarding bool |
|
| 59 |
+ EnableIPTables bool |
|
| 60 |
+ EnableUserlandProxy bool |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 63 |
+// networkConfiguration for network specific configuration |
|
| 64 |
+type networkConfiguration struct {
|
|
| 65 |
+ ID string |
|
| 66 |
+ BridgeName string |
|
| 67 |
+ BridgeNameInternal string |
|
| 68 |
+ EnableIPv6 bool |
|
| 69 |
+ EnableIPMasquerade bool |
|
| 70 |
+ EnableICC bool |
|
| 71 |
+ Mtu int |
|
| 72 |
+ DefaultBindingIntf string |
|
| 73 |
+ DefaultBindingIP net.IP |
|
| 74 |
+ DefaultBridge bool |
|
| 75 |
+ // Internal fields set after ipam data parsing |
|
| 76 |
+ AddressIPv4 *net.IPNet |
|
| 77 |
+ AddressIPv6 *net.IPNet |
|
| 78 |
+ DefaultGatewayIPv4 net.IP |
|
| 79 |
+ DefaultGatewayIPv6 net.IP |
|
| 80 |
+ dbIndex uint64 |
|
| 81 |
+ dbExists bool |
|
| 82 |
+ Internal bool |
|
| 83 |
+} |
|
| 84 |
+ |
|
| 85 |
+// endpointConfiguration represents the user specified configuration for the sandbox endpoint |
|
| 86 |
+type endpointConfiguration struct {
|
|
| 87 |
+ MacAddress net.HardwareAddr |
|
| 88 |
+ PortBindings []types.PortBinding |
|
| 89 |
+ ExposedPorts []types.TransportPort |
|
| 90 |
+} |
|
| 91 |
+ |
|
| 92 |
+// containerConfiguration represents the user specified configuration for a container |
|
| 93 |
+type containerConfiguration struct {
|
|
| 94 |
+ ParentEndpoints []string |
|
| 95 |
+ ChildEndpoints []string |
|
| 96 |
+} |
|
| 97 |
+ |
|
| 98 |
+// cnnectivityConfiguration represents the user specified configuration regarding the external connectivity |
|
| 99 |
+type connectivityConfiguration struct {
|
|
| 100 |
+ PortBindings []types.PortBinding |
|
| 101 |
+ ExposedPorts []types.TransportPort |
|
| 102 |
+} |
|
| 103 |
+ |
|
| 104 |
+type bridgeEndpoint struct {
|
|
| 105 |
+ id string |
|
| 106 |
+ nid string |
|
| 107 |
+ srcName string |
|
| 108 |
+ addr *net.IPNet |
|
| 109 |
+ addrv6 *net.IPNet |
|
| 110 |
+ macAddress net.HardwareAddr |
|
| 111 |
+ config *endpointConfiguration // User specified parameters |
|
| 112 |
+ containerConfig *containerConfiguration |
|
| 113 |
+ extConnConfig *connectivityConfiguration |
|
| 114 |
+ portMapping []types.PortBinding // Operation port bindings |
|
| 115 |
+ dbIndex uint64 |
|
| 116 |
+ dbExists bool |
|
| 117 |
+} |
|
| 118 |
+ |
|
| 119 |
+type bridgeInterface struct {
|
|
| 120 |
+ bridgeIPv4 *net.IPNet |
|
| 121 |
+ bridgeIPv6 *net.IPNet |
|
| 122 |
+ gatewayIPv4 net.IP |
|
| 123 |
+ gatewayIPv6 net.IP |
|
| 124 |
+} |
|
| 125 |
+ |
|
| 126 |
+type bridgeNetwork struct {
|
|
| 127 |
+ id string |
|
| 128 |
+ bridge *bridgeInterface |
|
| 129 |
+ config *networkConfiguration |
|
| 130 |
+ endpoints map[string]*bridgeEndpoint // key: endpoint id |
|
| 131 |
+ portMapper *portmapper.PortMapper |
|
| 132 |
+ driver *driver // The network's driver |
|
| 133 |
+ sync.Mutex |
|
| 134 |
+} |
|
| 135 |
+ |
|
| 136 |
+type driver struct {
|
|
| 137 |
+ config *configuration |
|
| 138 |
+ network *bridgeNetwork |
|
| 139 |
+ natChain *iptables.ChainInfo |
|
| 140 |
+ filterChain *iptables.ChainInfo |
|
| 141 |
+ isolationChain *iptables.ChainInfo |
|
| 142 |
+ networks map[string]*bridgeNetwork |
|
| 143 |
+ store datastore.DataStore |
|
| 144 |
+ sync.Mutex |
|
| 145 |
+ defrouteIP net.IP |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 148 |
+// New constructs a new bridge driver |
|
| 149 |
+func newDriver() *driver {
|
|
| 150 |
+ return &driver{networks: map[string]*bridgeNetwork{}}
|
|
| 151 |
+} |
|
| 152 |
+ |
|
| 153 |
+// Init registers a new instance of bridge driver |
|
| 154 |
+func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
|
| 155 |
+ d := newDriver() |
|
| 156 |
+ if err := d.configure(config); err != nil {
|
|
| 157 |
+ return err |
|
| 158 |
+ } |
|
| 159 |
+ |
|
| 160 |
+ c := driverapi.Capability{
|
|
| 161 |
+ DataScope: datastore.LocalScope, |
|
| 162 |
+ } |
|
| 163 |
+ return dc.RegisterDriver(networkType, d, c) |
|
| 164 |
+} |
|
| 165 |
+ |
|
| 166 |
+func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
|
|
| 167 |
+ return nil, types.NotImplementedErrorf("not implemented")
|
|
| 168 |
+} |
|
| 169 |
+ |
|
| 170 |
+func (d *driver) NetworkFree(id string) error {
|
|
| 171 |
+ return types.NotImplementedErrorf("not implemented")
|
|
| 172 |
+} |
|
| 173 |
+ |
|
| 174 |
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
|
| 175 |
+} |
|
| 176 |
+ |
|
| 177 |
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
|
| 178 |
+ if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
|
|
| 179 |
+ return types.BadRequestErrorf("ipv4 pool is empty")
|
|
| 180 |
+ } |
|
| 181 |
+ // Sanity checks |
|
| 182 |
+ d.Lock() |
|
| 183 |
+ if _, ok := d.networks[id]; ok {
|
|
| 184 |
+ d.Unlock() |
|
| 185 |
+ return types.ForbiddenErrorf("network %s exists", id)
|
|
| 186 |
+ } |
|
| 187 |
+ d.Unlock() |
|
| 188 |
+ |
|
| 189 |
+ // Parse and validate the config. It should not conflict with existing networks' config |
|
| 190 |
+ config, err := parseNetworkOptions(d, id, option) |
|
| 191 |
+ if err != nil {
|
|
| 192 |
+ return err |
|
| 193 |
+ } |
|
| 194 |
+ |
|
| 195 |
+ err = config.processIPAM(id, ipV4Data, ipV6Data) |
|
| 196 |
+ if err != nil {
|
|
| 197 |
+ return err |
|
| 198 |
+ } |
|
| 199 |
+ |
|
| 200 |
+ if err = d.createNetwork(config); err != nil {
|
|
| 201 |
+ return err |
|
| 202 |
+ } |
|
| 203 |
+ |
|
| 204 |
+ return d.storeUpdate(config) |
|
| 205 |
+} |
|
| 206 |
+ |
|
| 207 |
+func newInterface(config *networkConfiguration) *bridgeInterface {
|
|
| 208 |
+ i := &bridgeInterface{}
|
|
| 209 |
+ |
|
| 210 |
+ i.bridgeIPv4 = config.AddressIPv4 |
|
| 211 |
+ i.gatewayIPv4 = config.AddressIPv4.IP |
|
| 212 |
+ if config.BridgeName == "" {
|
|
| 213 |
+ config.BridgeName = DefaultBridgeName |
|
| 214 |
+ } |
|
| 215 |
+ return i |
|
| 216 |
+} |
|
| 217 |
+ |
|
| 218 |
+// This function prunes the pf.conf for the firewall |
|
| 219 |
+// that enable the service successfully. |
|
| 220 |
+func fixPFConf() error {
|
|
| 221 |
+ conf := "/etc/firewall/pf.conf" |
|
| 222 |
+ f, err := os.Open("/etc/firewall/pf.conf")
|
|
| 223 |
+ if err != nil {
|
|
| 224 |
+ return fmt.Errorf("cannot open %s: %v", conf, err)
|
|
| 225 |
+ } |
|
| 226 |
+ defer f.Close() |
|
| 227 |
+ |
|
| 228 |
+ // Look for line beginning with "REMOVE THIS LINE" |
|
| 229 |
+ modify := false |
|
| 230 |
+ lines := []string{}
|
|
| 231 |
+ scanner := bufio.NewScanner(f) |
|
| 232 |
+ for scanner.Scan() {
|
|
| 233 |
+ l := scanner.Text() |
|
| 234 |
+ if strings.Contains(l, "REMOVE THIS LINE") {
|
|
| 235 |
+ modify = true |
|
| 236 |
+ continue |
|
| 237 |
+ } |
|
| 238 |
+ lines = append(lines, fmt.Sprintf("%s\n", l))
|
|
| 239 |
+ } |
|
| 240 |
+ if err = scanner.Err(); err != nil {
|
|
| 241 |
+ return fmt.Errorf("cannot open %s: %v", conf, err)
|
|
| 242 |
+ } |
|
| 243 |
+ |
|
| 244 |
+ // No changes needed to fix pf.conf |
|
| 245 |
+ if !modify {
|
|
| 246 |
+ return nil |
|
| 247 |
+ } |
|
| 248 |
+ |
|
| 249 |
+ // Write back the file removing the line found above |
|
| 250 |
+ tmpname := "/etc/firewall/pf.conf.tmp." + strconv.Itoa(os.Getpid()) |
|
| 251 |
+ tmp, err := os.OpenFile(tmpname, |
|
| 252 |
+ os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_APPEND, 0644) |
|
| 253 |
+ if err != nil {
|
|
| 254 |
+ return fmt.Errorf("cannot open %s: %v", tmpname, err)
|
|
| 255 |
+ } |
|
| 256 |
+ defer tmp.Close() |
|
| 257 |
+ for _, l := range lines {
|
|
| 258 |
+ _, err = tmp.WriteString(l) |
|
| 259 |
+ if err != nil {
|
|
| 260 |
+ return fmt.Errorf("cannot write to %s: %v",
|
|
| 261 |
+ tmpname, err) |
|
| 262 |
+ } |
|
| 263 |
+ } |
|
| 264 |
+ if err = tmp.Sync(); err != nil {
|
|
| 265 |
+ return fmt.Errorf("cannot sync %s: %v", tmpname, err)
|
|
| 266 |
+ } |
|
| 267 |
+ if err = os.Rename(tmpname, conf); err != nil {
|
|
| 268 |
+ return fmt.Errorf("cannot rename %s to %s: %v",
|
|
| 269 |
+ tmpname, conf, err) |
|
| 270 |
+ } |
|
| 271 |
+ return nil |
|
| 272 |
+} |
|
| 273 |
+ |
|
| 274 |
+func (d *driver) initFirewall() error {
|
|
| 275 |
+ out, err := exec.Command("/usr/bin/svcs", "-Ho", "state",
|
|
| 276 |
+ "firewall").Output() |
|
| 277 |
+ if err != nil {
|
|
| 278 |
+ return fmt.Errorf("cannot check firewall state: %v", err)
|
|
| 279 |
+ } |
|
| 280 |
+ state := strings.TrimSpace(string(out)) |
|
| 281 |
+ if state != "online" {
|
|
| 282 |
+ if state != "disabled" {
|
|
| 283 |
+ return fmt.Errorf("firewall service is in %s state. "+
|
|
| 284 |
+ "please enable service manually.", state) |
|
| 285 |
+ } |
|
| 286 |
+ if err = fixPFConf(); err != nil {
|
|
| 287 |
+ return fmt.Errorf("cannot verify pf.conf: %v", err)
|
|
| 288 |
+ } |
|
| 289 |
+ err = exec.Command("/usr/sbin/svcadm", "enable", "-ts",
|
|
| 290 |
+ "firewall").Run() |
|
| 291 |
+ if err != nil {
|
|
| 292 |
+ return fmt.Errorf("cannot enable firewall service: %v", err)
|
|
| 293 |
+ } |
|
| 294 |
+ } |
|
| 295 |
+ out, err = exec.Command("/usr/sbin/pfctl", "-sr").Output()
|
|
| 296 |
+ if err != nil {
|
|
| 297 |
+ return fmt.Errorf("failed to list firewall rules: %v", err)
|
|
| 298 |
+ } |
|
| 299 |
+ if strings.Contains(string(out), "anchor \"_auto/docker/*\" all") {
|
|
| 300 |
+ return nil |
|
| 301 |
+ } |
|
| 302 |
+ pfctlCmd := "(/usr/sbin/pfctl -sr; " + |
|
| 303 |
+ "/usr/bin/echo \"anchor \\\"_auto/docker/*\\\"\") |" + |
|
| 304 |
+ "/usr/sbin/pfctl -f -" |
|
| 305 |
+ err = exec.Command("/usr/bin/bash", "-c", pfctlCmd).Run()
|
|
| 306 |
+ if err != nil {
|
|
| 307 |
+ return fmt.Errorf("failed to add docker firewall rules: %v", err)
|
|
| 308 |
+ } |
|
| 309 |
+ return nil |
|
| 310 |
+} |
|
| 311 |
+ |
|
| 312 |
+func (d *driver) initRouting() error {
|
|
| 313 |
+ err := exec.Command("/usr/sbin/ipadm", "set-prop", "-t",
|
|
| 314 |
+ "-p", "forwarding=on", "ipv4").Run() |
|
| 315 |
+ if err != nil {
|
|
| 316 |
+ return fmt.Errorf("cannot switch-on IP forwarding: %v", err)
|
|
| 317 |
+ } |
|
| 318 |
+ routeCmd := "/usr/sbin/ipadm show-addr -p -o addr " + |
|
| 319 |
+ "`/usr/sbin/route get default | /usr/bin/grep interface | " + |
|
| 320 |
+ "/usr/bin/awk '{print $2}'`"
|
|
| 321 |
+ out, err := exec.Command("/usr/bin/bash", "-c", routeCmd).Output()
|
|
| 322 |
+ if err != nil {
|
|
| 323 |
+ return fmt.Errorf("cannot get default route: %v", err)
|
|
| 324 |
+ } |
|
| 325 |
+ defroute := strings.SplitN(string(out), "/", 2) |
|
| 326 |
+ d.defrouteIP = net.ParseIP(defroute[0]) |
|
| 327 |
+ if d.defrouteIP == nil {
|
|
| 328 |
+ return &ErrNoIPAddr{}
|
|
| 329 |
+ } |
|
| 330 |
+ return nil |
|
| 331 |
+} |
|
| 332 |
+ |
|
| 333 |
+func (d *driver) configure(option map[string]interface{}) error {
|
|
| 334 |
+ var err error |
|
| 335 |
+ |
|
| 336 |
+ if err = d.initFirewall(); err != nil {
|
|
| 337 |
+ return fmt.Errorf("failed to configure firewall: %v", err)
|
|
| 338 |
+ } |
|
| 339 |
+ if err = d.initRouting(); err != nil {
|
|
| 340 |
+ return fmt.Errorf("failed to configure routing: %v", err)
|
|
| 341 |
+ } |
|
| 342 |
+ if err = d.initStore(option); err != nil {
|
|
| 343 |
+ return fmt.Errorf("failed to initialize datastore: %v", err)
|
|
| 344 |
+ } |
|
| 345 |
+ |
|
| 346 |
+ return nil |
|
| 347 |
+} |
|
| 348 |
+ |
|
| 349 |
+func (d *driver) getNetwork(id string) (*bridgeNetwork, error) {
|
|
| 350 |
+ d.Lock() |
|
| 351 |
+ defer d.Unlock() |
|
| 352 |
+ |
|
| 353 |
+ if id == "" {
|
|
| 354 |
+ return nil, types.BadRequestErrorf("invalid network id: %s", id)
|
|
| 355 |
+ } |
|
| 356 |
+ |
|
| 357 |
+ if nw, ok := d.networks[id]; ok {
|
|
| 358 |
+ return nw, nil |
|
| 359 |
+ } |
|
| 360 |
+ |
|
| 361 |
+ return nil, types.NotFoundErrorf("network not found: %s", id)
|
|
| 362 |
+} |
|
| 363 |
+ |
|
| 364 |
+// Return a slice of networks over which caller can iterate safely |
|
| 365 |
+func (d *driver) getNetworks() []*bridgeNetwork {
|
|
| 366 |
+ d.Lock() |
|
| 367 |
+ defer d.Unlock() |
|
| 368 |
+ |
|
| 369 |
+ ls := make([]*bridgeNetwork, 0, len(d.networks)) |
|
| 370 |
+ for _, nw := range d.networks {
|
|
| 371 |
+ ls = append(ls, nw) |
|
| 372 |
+ } |
|
| 373 |
+ return ls |
|
| 374 |
+} |
|
| 375 |
+ |
|
| 376 |
+func bridgeSetup(config *networkConfiguration) error {
|
|
| 377 |
+ var err error |
|
| 378 |
+ var bindingIntf string |
|
| 379 |
+ |
|
| 380 |
+ bridgeName := config.BridgeName |
|
| 381 |
+ gwName := fmt.Sprintf("%s_gw0", bridgeName)
|
|
| 382 |
+ gwIP := config.AddressIPv4.String() |
|
| 383 |
+ |
|
| 384 |
+ if config.DefaultBindingIP == nil {
|
|
| 385 |
+ // Default to net0 if bindingIP is not provided. |
|
| 386 |
+ bindingIntf = "net0" |
|
| 387 |
+ } else {
|
|
| 388 |
+ ipadmCmd := "/usr/sbin/ipadm show-addr -p -o addrobj,addr |" + |
|
| 389 |
+ "/usr/bin/grep " + config.DefaultBindingIP.String() |
|
| 390 |
+ out, err := exec.Command("/usr/bin/bash", "-c", ipadmCmd).Output()
|
|
| 391 |
+ if err != nil {
|
|
| 392 |
+ logrus.Warnf("cannot find binding interface")
|
|
| 393 |
+ return err |
|
| 394 |
+ } |
|
| 395 |
+ bindingIntf = strings.SplitN(string(out), "/", 2)[0] |
|
| 396 |
+ if bindingIntf == "" {
|
|
| 397 |
+ logrus.Warnf("cannot parse binding interface %s", string(out))
|
|
| 398 |
+ return &ErrNoIPAddr{}
|
|
| 399 |
+ } |
|
| 400 |
+ } |
|
| 401 |
+ config.DefaultBindingIntf = bindingIntf |
|
| 402 |
+ |
|
| 403 |
+ err = exec.Command("/usr/sbin/dladm", "create-etherstub",
|
|
| 404 |
+ "-t", config.BridgeNameInternal).Run() |
|
| 405 |
+ if err != nil {
|
|
| 406 |
+ logrus.Warnf("cannot create etherstub %s: %+v", config.BridgeNameInternal, err)
|
|
| 407 |
+ return err |
|
| 408 |
+ } |
|
| 409 |
+ err = exec.Command("/usr/sbin/dladm", "create-vnic",
|
|
| 410 |
+ "-t", "-l", config.BridgeNameInternal, gwName).Run() |
|
| 411 |
+ if err != nil {
|
|
| 412 |
+ logrus.Warnf("cannot create vnic %s", gwName)
|
|
| 413 |
+ return err |
|
| 414 |
+ } |
|
| 415 |
+ err = exec.Command("/usr/sbin/ifconfig", gwName,
|
|
| 416 |
+ "plumb", gwIP, "up").Run() |
|
| 417 |
+ if err != nil {
|
|
| 418 |
+ logrus.Warnf("cannot create gateway interface %s on %s",
|
|
| 419 |
+ gwIP, gwName) |
|
| 420 |
+ return err |
|
| 421 |
+ } |
|
| 422 |
+ |
|
| 423 |
+ tableName := "bridge_nw_subnets" |
|
| 424 |
+ pfAnchor := fmt.Sprintf("_auto/docker/%s", tableName)
|
|
| 425 |
+ err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-t", tableName, "-T", "add", gwIP).Run()
|
|
| 426 |
+ if err != nil {
|
|
| 427 |
+ logrus.Warnf("cannot add bridge network '%s' to PF table", bridgeName)
|
|
| 428 |
+ } |
|
| 429 |
+ |
|
| 430 |
+ pfCmd := fmt.Sprintf( |
|
| 431 |
+ "/usr/bin/echo \"pass out on %s from %s:network to any nat-to (%s)\n"+ |
|
| 432 |
+ "block in quick from { <%s>, ! %s } to %s\" |"+
|
|
| 433 |
+ "/usr/sbin/pfctl -a _auto/docker/%s -f -", |
|
| 434 |
+ bindingIntf, gwName, bindingIntf, |
|
| 435 |
+ tableName, gwIP, gwIP, |
|
| 436 |
+ bridgeName) |
|
| 437 |
+ err = exec.Command("/usr/bin/bash", "-c", pfCmd).Run()
|
|
| 438 |
+ if err != nil {
|
|
| 439 |
+ logrus.Warnf("cannot add pf rule using: %s", pfCmd)
|
|
| 440 |
+ return err |
|
| 441 |
+ } |
|
| 442 |
+ |
|
| 443 |
+ return nil |
|
| 444 |
+} |
|
| 445 |
+ |
|
| 446 |
+func bridgeCleanup(config *networkConfiguration, logErr bool) {
|
|
| 447 |
+ var err error |
|
| 448 |
+ |
|
| 449 |
+ bridgeName := config.BridgeName |
|
| 450 |
+ tableName := "bridge_nw_subnets" |
|
| 451 |
+ gwName := fmt.Sprintf("%s_gw0", bridgeName)
|
|
| 452 |
+ gwIP := config.AddressIPv4.String() |
|
| 453 |
+ pfAnchor := fmt.Sprintf("_auto/docker/%s", bridgeName)
|
|
| 454 |
+ tableAnchor := fmt.Sprintf("_auto/docker/%s", tableName)
|
|
| 455 |
+ |
|
| 456 |
+ err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-F", "all").Run()
|
|
| 457 |
+ if err != nil && logErr {
|
|
| 458 |
+ logrus.Warnf("cannot flush firewall rules")
|
|
| 459 |
+ } |
|
| 460 |
+ err = exec.Command("/usr/sbin/ifconfig", gwName, "unplumb").Run()
|
|
| 461 |
+ if err != nil && logErr {
|
|
| 462 |
+ logrus.Warnf("cannot remove gateway interface")
|
|
| 463 |
+ } |
|
| 464 |
+ err = exec.Command("/usr/sbin/dladm", "delete-vnic",
|
|
| 465 |
+ "-t", gwName).Run() |
|
| 466 |
+ if err != nil && logErr {
|
|
| 467 |
+ logrus.Warnf("cannot delete vnic")
|
|
| 468 |
+ } |
|
| 469 |
+ err = exec.Command("/usr/sbin/dladm", "delete-etherstub",
|
|
| 470 |
+ "-t", config.BridgeNameInternal).Run() |
|
| 471 |
+ if err != nil && logErr {
|
|
| 472 |
+ logrus.Warnf("cannot delete etherstub")
|
|
| 473 |
+ } |
|
| 474 |
+ err = exec.Command("/usr/sbin/pfctl", "-a", tableAnchor, "-t", tableName, "-T", "delete", gwIP).Run()
|
|
| 475 |
+ if err != nil && logErr {
|
|
| 476 |
+ logrus.Warnf("cannot remove bridge network '%s' from PF table", bridgeName)
|
|
| 477 |
+ } |
|
| 478 |
+} |
|
| 479 |
+ |
|
| 480 |
+func (d *driver) createNetwork(config *networkConfiguration) error {
|
|
| 481 |
+ var err error |
|
| 482 |
+ |
|
| 483 |
+ logrus.Infof("Creating bridge network: %s %s %s", config.ID,
|
|
| 484 |
+ config.BridgeName, config.AddressIPv4) |
|
| 485 |
+ |
|
| 486 |
+ networkList := d.getNetworks() |
|
| 487 |
+ for i, nw := range networkList {
|
|
| 488 |
+ nw.Lock() |
|
| 489 |
+ nwConfig := nw.config |
|
| 490 |
+ nw.Unlock() |
|
| 491 |
+ if err := nwConfig.Conflicts(config); err != nil {
|
|
| 492 |
+ if config.DefaultBridge {
|
|
| 493 |
+ // We encountered and identified a stale default network |
|
| 494 |
+ // We must delete it as libnetwork is the source of thruth |
|
| 495 |
+ // The default network being created must be the only one |
|
| 496 |
+ // This can happen only from docker 1.12 on ward |
|
| 497 |
+ logrus.Infof("Removing stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName)
|
|
| 498 |
+ if err := d.DeleteNetwork(nwConfig.ID); err != nil {
|
|
| 499 |
+ logrus.Warnf("Failed to remove stale default network: %s (%s): %v. Will remove from store.", nwConfig.ID, nwConfig.BridgeName, err)
|
|
| 500 |
+ d.storeDelete(nwConfig) |
|
| 501 |
+ } |
|
| 502 |
+ networkList = append(networkList[:i], networkList[i+1:]...) |
|
| 503 |
+ } else {
|
|
| 504 |
+ return types.ForbiddenErrorf( |
|
| 505 |
+ "cannot create network %s (%s): "+ |
|
| 506 |
+ "conflicts with network %s (%s): %s", |
|
| 507 |
+ nwConfig.BridgeName, config.ID, nw.id, |
|
| 508 |
+ nw.config.BridgeName, err.Error()) |
|
| 509 |
+ } |
|
| 510 |
+ } |
|
| 511 |
+ } |
|
| 512 |
+ if config.DefaultBindingIP == nil || |
|
| 513 |
+ config.DefaultBindingIP.IsUnspecified() {
|
|
| 514 |
+ config.DefaultBindingIP = d.defrouteIP |
|
| 515 |
+ } |
|
| 516 |
+ |
|
| 517 |
+ // Create and set network handler in driver |
|
| 518 |
+ network := &bridgeNetwork{
|
|
| 519 |
+ id: config.ID, |
|
| 520 |
+ endpoints: make(map[string]*bridgeEndpoint), |
|
| 521 |
+ config: config, |
|
| 522 |
+ portMapper: portmapper.New(""),
|
|
| 523 |
+ driver: d, |
|
| 524 |
+ } |
|
| 525 |
+ |
|
| 526 |
+ d.Lock() |
|
| 527 |
+ d.networks[config.ID] = network |
|
| 528 |
+ d.Unlock() |
|
| 529 |
+ |
|
| 530 |
+ // On failure make sure to reset driver network handler to nil |
|
| 531 |
+ defer func() {
|
|
| 532 |
+ if err != nil {
|
|
| 533 |
+ d.Lock() |
|
| 534 |
+ delete(d.networks, config.ID) |
|
| 535 |
+ d.Unlock() |
|
| 536 |
+ } |
|
| 537 |
+ }() |
|
| 538 |
+ |
|
| 539 |
+ // Create or retrieve the bridge L3 interface |
|
| 540 |
+ bridgeIface := newInterface(config) |
|
| 541 |
+ network.bridge = bridgeIface |
|
| 542 |
+ |
|
| 543 |
+ // Verify the network configuration does not conflict with previously installed |
|
| 544 |
+ // networks. This step is needed now because driver might have now set the bridge |
|
| 545 |
+ // name on this config struct. And because we need to check for possible address |
|
| 546 |
+ // conflicts, so we need to check against operational networks. |
|
| 547 |
+ if err = config.conflictsWithNetworks(config.ID, networkList); err != nil {
|
|
| 548 |
+ return err |
|
| 549 |
+ } |
|
| 550 |
+ |
|
| 551 |
+ // We only attempt to create the bridge when the requested device name is |
|
| 552 |
+ // the default one. |
|
| 553 |
+ if config.BridgeName != DefaultBridgeName && config.DefaultBridge {
|
|
| 554 |
+ return NonDefaultBridgeExistError(config.BridgeName) |
|
| 555 |
+ } |
|
| 556 |
+ |
|
| 557 |
+ bridgeCleanup(config, false) |
|
| 558 |
+ err = bridgeSetup(config) |
|
| 559 |
+ if err != nil {
|
|
| 560 |
+ return err |
|
| 561 |
+ } |
|
| 562 |
+ return nil |
|
| 563 |
+} |
|
| 564 |
+ |
|
| 565 |
+func (d *driver) DeleteNetwork(nid string) error {
|
|
| 566 |
+ var err error |
|
| 567 |
+ // Get network handler and remove it from driver |
|
| 568 |
+ d.Lock() |
|
| 569 |
+ n, ok := d.networks[nid] |
|
| 570 |
+ d.Unlock() |
|
| 571 |
+ |
|
| 572 |
+ if !ok {
|
|
| 573 |
+ return types.InternalMaskableErrorf("network %s does not exist", nid)
|
|
| 574 |
+ } |
|
| 575 |
+ d.Lock() |
|
| 576 |
+ delete(d.networks, nid) |
|
| 577 |
+ d.Unlock() |
|
| 578 |
+ |
|
| 579 |
+ // On failure set network handler back in driver, but |
|
| 580 |
+ // only if is not already taken over by some other thread |
|
| 581 |
+ defer func() {
|
|
| 582 |
+ if err != nil {
|
|
| 583 |
+ d.Lock() |
|
| 584 |
+ if _, ok := d.networks[nid]; !ok {
|
|
| 585 |
+ d.networks[nid] = n |
|
| 586 |
+ } |
|
| 587 |
+ d.Unlock() |
|
| 588 |
+ } |
|
| 589 |
+ }() |
|
| 590 |
+ |
|
| 591 |
+ // Sanity check |
|
| 592 |
+ if n == nil {
|
|
| 593 |
+ err = driverapi.ErrNoNetwork(nid) |
|
| 594 |
+ return err |
|
| 595 |
+ } |
|
| 596 |
+ |
|
| 597 |
+ // Cannot remove network if endpoints are still present |
|
| 598 |
+ if len(n.endpoints) != 0 {
|
|
| 599 |
+ err = ActiveEndpointsError(n.id) |
|
| 600 |
+ return err |
|
| 601 |
+ } |
|
| 602 |
+ bridgeCleanup(n.config, true) |
|
| 603 |
+ logrus.Infof("Deleting bridge network: %s", nid[:12])
|
|
| 604 |
+ return d.storeDelete(n.config) |
|
| 605 |
+} |
|
| 606 |
+ |
|
| 607 |
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
|
| 608 |
+ if ifInfo == nil {
|
|
| 609 |
+ return errors.New("invalid interface passed")
|
|
| 610 |
+ } |
|
| 611 |
+ |
|
| 612 |
+ // Get the network handler and make sure it exists |
|
| 613 |
+ d.Lock() |
|
| 614 |
+ n, ok := d.networks[nid] |
|
| 615 |
+ d.Unlock() |
|
| 616 |
+ |
|
| 617 |
+ if !ok {
|
|
| 618 |
+ return types.NotFoundErrorf("network %s does not exist", nid)
|
|
| 619 |
+ } |
|
| 620 |
+ if n == nil {
|
|
| 621 |
+ return driverapi.ErrNoNetwork(nid) |
|
| 622 |
+ } |
|
| 623 |
+ |
|
| 624 |
+ // Sanity check |
|
| 625 |
+ n.Lock() |
|
| 626 |
+ if n.id != nid {
|
|
| 627 |
+ n.Unlock() |
|
| 628 |
+ return InvalidNetworkIDError(nid) |
|
| 629 |
+ } |
|
| 630 |
+ n.Unlock() |
|
| 631 |
+ |
|
| 632 |
+ // Check if endpoint id is good and retrieve correspondent endpoint |
|
| 633 |
+ ep, err := n.getEndpoint(eid) |
|
| 634 |
+ if err != nil {
|
|
| 635 |
+ return err |
|
| 636 |
+ } |
|
| 637 |
+ |
|
| 638 |
+ // Endpoint with that id exists either on desired or other sandbox |
|
| 639 |
+ if ep != nil {
|
|
| 640 |
+ return driverapi.ErrEndpointExists(eid) |
|
| 641 |
+ } |
|
| 642 |
+ |
|
| 643 |
+ // Try to convert the options to endpoint configuration |
|
| 644 |
+ epConfig, err := parseEndpointOptions(epOptions) |
|
| 645 |
+ if err != nil {
|
|
| 646 |
+ return err |
|
| 647 |
+ } |
|
| 648 |
+ |
|
| 649 |
+ // Create and add the endpoint |
|
| 650 |
+ n.Lock() |
|
| 651 |
+ endpoint := &bridgeEndpoint{id: eid, config: epConfig}
|
|
| 652 |
+ n.endpoints[eid] = endpoint |
|
| 653 |
+ n.Unlock() |
|
| 654 |
+ |
|
| 655 |
+ // On failure make sure to remove the endpoint |
|
| 656 |
+ defer func() {
|
|
| 657 |
+ if err != nil {
|
|
| 658 |
+ n.Lock() |
|
| 659 |
+ delete(n.endpoints, eid) |
|
| 660 |
+ n.Unlock() |
|
| 661 |
+ } |
|
| 662 |
+ }() |
|
| 663 |
+ |
|
| 664 |
+ // Create the sandbox side pipe interface |
|
| 665 |
+ if ifInfo.MacAddress() == nil {
|
|
| 666 |
+ // No MAC address assigned to interface. Generate a random MAC to assign |
|
| 667 |
+ endpoint.macAddress = netutils.GenerateRandomMAC() |
|
| 668 |
+ if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
|
|
| 669 |
+ logrus.Warnf("Unable to set mac address: %s to endpoint: %s",
|
|
| 670 |
+ endpoint.macAddress.String(), endpoint.id) |
|
| 671 |
+ return err |
|
| 672 |
+ } |
|
| 673 |
+ } else {
|
|
| 674 |
+ endpoint.macAddress = ifInfo.MacAddress() |
|
| 675 |
+ } |
|
| 676 |
+ endpoint.addr = ifInfo.Address() |
|
| 677 |
+ endpoint.addrv6 = ifInfo.AddressIPv6() |
|
| 678 |
+ c := n.config |
|
| 679 |
+ |
|
| 680 |
+ // Program any required port mapping and store them in the endpoint |
|
| 681 |
+ endpoint.portMapping, err = n.allocatePorts(endpoint, c.DefaultBindingIntf, c.DefaultBindingIP, true) |
|
| 682 |
+ if err != nil {
|
|
| 683 |
+ return err |
|
| 684 |
+ } |
|
| 685 |
+ |
|
| 686 |
+ return nil |
|
| 687 |
+} |
|
| 688 |
+ |
|
| 689 |
+func (d *driver) DeleteEndpoint(nid, eid string) error {
|
|
| 690 |
+ var err error |
|
| 691 |
+ |
|
| 692 |
+ // Get the network handler and make sure it exists |
|
| 693 |
+ d.Lock() |
|
| 694 |
+ n, ok := d.networks[nid] |
|
| 695 |
+ d.Unlock() |
|
| 696 |
+ |
|
| 697 |
+ if !ok {
|
|
| 698 |
+ return types.InternalMaskableErrorf("network %s does not exist", nid)
|
|
| 699 |
+ } |
|
| 700 |
+ if n == nil {
|
|
| 701 |
+ return driverapi.ErrNoNetwork(nid) |
|
| 702 |
+ } |
|
| 703 |
+ |
|
| 704 |
+ // Sanity Check |
|
| 705 |
+ n.Lock() |
|
| 706 |
+ if n.id != nid {
|
|
| 707 |
+ n.Unlock() |
|
| 708 |
+ return InvalidNetworkIDError(nid) |
|
| 709 |
+ } |
|
| 710 |
+ n.Unlock() |
|
| 711 |
+ |
|
| 712 |
+ // Check endpoint id and if an endpoint is actually there |
|
| 713 |
+ ep, err := n.getEndpoint(eid) |
|
| 714 |
+ if err != nil {
|
|
| 715 |
+ return err |
|
| 716 |
+ } |
|
| 717 |
+ if ep == nil {
|
|
| 718 |
+ return EndpointNotFoundError(eid) |
|
| 719 |
+ } |
|
| 720 |
+ |
|
| 721 |
+ // Remove it |
|
| 722 |
+ n.Lock() |
|
| 723 |
+ delete(n.endpoints, eid) |
|
| 724 |
+ n.Unlock() |
|
| 725 |
+ |
|
| 726 |
+ // On failure make sure to set back ep in n.endpoints, but only |
|
| 727 |
+ // if it hasn't been taken over already by some other thread. |
|
| 728 |
+ defer func() {
|
|
| 729 |
+ if err != nil {
|
|
| 730 |
+ n.Lock() |
|
| 731 |
+ if _, ok := n.endpoints[eid]; !ok {
|
|
| 732 |
+ n.endpoints[eid] = ep |
|
| 733 |
+ } |
|
| 734 |
+ n.Unlock() |
|
| 735 |
+ } |
|
| 736 |
+ }() |
|
| 737 |
+ |
|
| 738 |
+ err = n.releasePorts(ep) |
|
| 739 |
+ if err != nil {
|
|
| 740 |
+ logrus.Warn(err) |
|
| 741 |
+ } |
|
| 742 |
+ |
|
| 743 |
+ return nil |
|
| 744 |
+} |
|
| 745 |
+ |
|
| 746 |
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
|
| 747 |
+ // Get the network handler and make sure it exists |
|
| 748 |
+ d.Lock() |
|
| 749 |
+ n, ok := d.networks[nid] |
|
| 750 |
+ d.Unlock() |
|
| 751 |
+ if !ok {
|
|
| 752 |
+ return nil, types.NotFoundErrorf("network %s does not exist", nid)
|
|
| 753 |
+ } |
|
| 754 |
+ if n == nil {
|
|
| 755 |
+ return nil, driverapi.ErrNoNetwork(nid) |
|
| 756 |
+ } |
|
| 757 |
+ |
|
| 758 |
+ // Sanity check |
|
| 759 |
+ n.Lock() |
|
| 760 |
+ if n.id != nid {
|
|
| 761 |
+ n.Unlock() |
|
| 762 |
+ return nil, InvalidNetworkIDError(nid) |
|
| 763 |
+ } |
|
| 764 |
+ n.Unlock() |
|
| 765 |
+ |
|
| 766 |
+ // Check if endpoint id is good and retrieve correspondent endpoint |
|
| 767 |
+ ep, err := n.getEndpoint(eid) |
|
| 768 |
+ if err != nil {
|
|
| 769 |
+ return nil, err |
|
| 770 |
+ } |
|
| 771 |
+ if ep == nil {
|
|
| 772 |
+ return nil, driverapi.ErrNoEndpoint(eid) |
|
| 773 |
+ } |
|
| 774 |
+ |
|
| 775 |
+ m := make(map[string]interface{})
|
|
| 776 |
+ |
|
| 777 |
+ if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil {
|
|
| 778 |
+ // Return a copy of the config data |
|
| 779 |
+ epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts)) |
|
| 780 |
+ for _, tp := range ep.extConnConfig.ExposedPorts {
|
|
| 781 |
+ epc = append(epc, tp.GetCopy()) |
|
| 782 |
+ } |
|
| 783 |
+ m[netlabel.ExposedPorts] = epc |
|
| 784 |
+ } |
|
| 785 |
+ |
|
| 786 |
+ if ep.portMapping != nil {
|
|
| 787 |
+ // Return a copy of the operational data |
|
| 788 |
+ pmc := make([]types.PortBinding, 0, len(ep.portMapping)) |
|
| 789 |
+ for _, pm := range ep.portMapping {
|
|
| 790 |
+ pmc = append(pmc, pm.GetCopy()) |
|
| 791 |
+ } |
|
| 792 |
+ m[netlabel.PortMap] = pmc |
|
| 793 |
+ } |
|
| 794 |
+ |
|
| 795 |
+ if len(ep.macAddress) != 0 {
|
|
| 796 |
+ m[netlabel.MacAddress] = ep.macAddress |
|
| 797 |
+ } |
|
| 798 |
+ return m, nil |
|
| 799 |
+} |
|
| 800 |
+ |
|
| 801 |
+// Join method is invoked when a Sandbox is attached to an endpoint. |
|
| 802 |
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
|
| 803 |
+ network, err := d.getNetwork(nid) |
|
| 804 |
+ if err != nil {
|
|
| 805 |
+ return err |
|
| 806 |
+ } |
|
| 807 |
+ |
|
| 808 |
+ endpoint, err := network.getEndpoint(eid) |
|
| 809 |
+ if err != nil {
|
|
| 810 |
+ return err |
|
| 811 |
+ } |
|
| 812 |
+ |
|
| 813 |
+ if endpoint == nil {
|
|
| 814 |
+ return EndpointNotFoundError(eid) |
|
| 815 |
+ } |
|
| 816 |
+ |
|
| 817 |
+ endpoint.containerConfig, err = parseContainerOptions(options) |
|
| 818 |
+ if err != nil {
|
|
| 819 |
+ return err |
|
| 820 |
+ } |
|
| 821 |
+ |
|
| 822 |
+ err = jinfo.SetGateway(network.bridge.gatewayIPv4) |
|
| 823 |
+ if err != nil {
|
|
| 824 |
+ return err |
|
| 825 |
+ } |
|
| 826 |
+ |
|
| 827 |
+ err = jinfo.SetGatewayIPv6(network.bridge.gatewayIPv6) |
|
| 828 |
+ if err != nil {
|
|
| 829 |
+ return err |
|
| 830 |
+ } |
|
| 831 |
+ |
|
| 832 |
+ return nil |
|
| 833 |
+} |
|
| 834 |
+ |
|
| 835 |
+func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) error {
|
|
| 836 |
+ return nil |
|
| 837 |
+} |
|
| 838 |
+ |
|
| 839 |
+// Leave method is invoked when a Sandbox detaches from an endpoint. |
|
| 840 |
+func (d *driver) Leave(nid, eid string) error {
|
|
| 841 |
+ network, err := d.getNetwork(nid) |
|
| 842 |
+ if err != nil {
|
|
| 843 |
+ return types.InternalMaskableErrorf("%s", err)
|
|
| 844 |
+ } |
|
| 845 |
+ |
|
| 846 |
+ endpoint, err := network.getEndpoint(eid) |
|
| 847 |
+ if err != nil {
|
|
| 848 |
+ return err |
|
| 849 |
+ } |
|
| 850 |
+ |
|
| 851 |
+ if endpoint == nil {
|
|
| 852 |
+ return EndpointNotFoundError(eid) |
|
| 853 |
+ } |
|
| 854 |
+ |
|
| 855 |
+ return nil |
|
| 856 |
+} |
|
| 857 |
+ |
|
| 858 |
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
|
|
| 859 |
+ network, err := d.getNetwork(nid) |
|
| 860 |
+ if err != nil {
|
|
| 861 |
+ return err |
|
| 862 |
+ } |
|
| 863 |
+ |
|
| 864 |
+ endpoint, err := network.getEndpoint(eid) |
|
| 865 |
+ if err != nil {
|
|
| 866 |
+ return err |
|
| 867 |
+ } |
|
| 868 |
+ |
|
| 869 |
+ if endpoint == nil {
|
|
| 870 |
+ return EndpointNotFoundError(eid) |
|
| 871 |
+ } |
|
| 872 |
+ |
|
| 873 |
+ endpoint.extConnConfig, err = parseConnectivityOptions(options) |
|
| 874 |
+ if err != nil {
|
|
| 875 |
+ return err |
|
| 876 |
+ } |
|
| 877 |
+ |
|
| 878 |
+ // Program any required port mapping and store them in the endpoint |
|
| 879 |
+ endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIntf, network.config.DefaultBindingIP, true) |
|
| 880 |
+ if err != nil {
|
|
| 881 |
+ return err |
|
| 882 |
+ } |
|
| 883 |
+ |
|
| 884 |
+ if !network.config.EnableICC {
|
|
| 885 |
+ return d.link(network, endpoint, true) |
|
| 886 |
+ } |
|
| 887 |
+ |
|
| 888 |
+ return nil |
|
| 889 |
+} |
|
| 890 |
+ |
|
| 891 |
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
|
|
| 892 |
+ network, err := d.getNetwork(nid) |
|
| 893 |
+ if err != nil {
|
|
| 894 |
+ return err |
|
| 895 |
+ } |
|
| 896 |
+ |
|
| 897 |
+ endpoint, err := network.getEndpoint(eid) |
|
| 898 |
+ if err != nil {
|
|
| 899 |
+ return err |
|
| 900 |
+ } |
|
| 901 |
+ |
|
| 902 |
+ if endpoint == nil {
|
|
| 903 |
+ return EndpointNotFoundError(eid) |
|
| 904 |
+ } |
|
| 905 |
+ |
|
| 906 |
+ err = network.releasePorts(endpoint) |
|
| 907 |
+ if err != nil {
|
|
| 908 |
+ logrus.Warn(err) |
|
| 909 |
+ } |
|
| 910 |
+ |
|
| 911 |
+ return nil |
|
| 912 |
+} |
|
| 913 |
+ |
|
| 914 |
+func (d *driver) Type() string {
|
|
| 915 |
+ return networkType |
|
| 916 |
+} |
|
| 917 |
+ |
|
| 918 |
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster |
|
| 919 |
+func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
|
| 920 |
+ return nil |
|
| 921 |
+} |
|
| 922 |
+ |
|
| 923 |
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster |
|
| 924 |
+func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
|
| 925 |
+ return nil |
|
| 926 |
+} |
|
| 927 |
+ |
|
| 928 |
+// Validate performs a static validation on the network configuration parameters. |
|
| 929 |
+// Whatever can be assessed a priori before attempting any programming. |
|
| 930 |
+func (c *networkConfiguration) Validate() error {
|
|
| 931 |
+ if c.Mtu < 0 {
|
|
| 932 |
+ return ErrInvalidMtu(c.Mtu) |
|
| 933 |
+ } |
|
| 934 |
+ |
|
| 935 |
+ // If bridge v4 subnet is specified |
|
| 936 |
+ if c.AddressIPv4 != nil {
|
|
| 937 |
+ // If default gw is specified, it must be part of bridge subnet |
|
| 938 |
+ if c.DefaultGatewayIPv4 != nil {
|
|
| 939 |
+ if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
|
|
| 940 |
+ return &ErrInvalidGateway{}
|
|
| 941 |
+ } |
|
| 942 |
+ } |
|
| 943 |
+ } |
|
| 944 |
+ |
|
| 945 |
+ // If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet |
|
| 946 |
+ if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
|
|
| 947 |
+ if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) {
|
|
| 948 |
+ return &ErrInvalidGateway{}
|
|
| 949 |
+ } |
|
| 950 |
+ } |
|
| 951 |
+ return nil |
|
| 952 |
+} |
|
| 953 |
+ |
|
| 954 |
+// Checks whether this network's configuration for the network with this id conflicts with any of the passed networks |
|
| 955 |
+func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error {
|
|
| 956 |
+ for _, nw := range others {
|
|
| 957 |
+ |
|
| 958 |
+ nw.Lock() |
|
| 959 |
+ nwID := nw.id |
|
| 960 |
+ nwConfig := nw.config |
|
| 961 |
+ nwBridge := nw.bridge |
|
| 962 |
+ nw.Unlock() |
|
| 963 |
+ |
|
| 964 |
+ if nwID == id {
|
|
| 965 |
+ continue |
|
| 966 |
+ } |
|
| 967 |
+ // Verify the name (which may have been set by newInterface()) does not conflict with |
|
| 968 |
+ // existing bridge interfaces. Ironically the system chosen name gets stored in the config... |
|
| 969 |
+ // Basically we are checking if the two original configs were both empty. |
|
| 970 |
+ if nwConfig.BridgeName == c.BridgeName {
|
|
| 971 |
+ return types.ForbiddenErrorf("conflicts with network %s (%s) by bridge name", nwID, nwConfig.BridgeName)
|
|
| 972 |
+ } |
|
| 973 |
+ // If this network config specifies the AddressIPv4, we need |
|
| 974 |
+ // to make sure it does not conflict with any previously allocated |
|
| 975 |
+ // bridges. This could not be completely caught by the config conflict |
|
| 976 |
+ // check, because networks which config does not specify the AddressIPv4 |
|
| 977 |
+ // get their address and subnet selected by the driver (see electBridgeIPv4()) |
|
| 978 |
+ if c.AddressIPv4 != nil {
|
|
| 979 |
+ if nwBridge.bridgeIPv4.Contains(c.AddressIPv4.IP) || |
|
| 980 |
+ c.AddressIPv4.Contains(nwBridge.bridgeIPv4.IP) {
|
|
| 981 |
+ return types.ForbiddenErrorf("conflicts with network %s (%s) by ip network", nwID, nwConfig.BridgeName)
|
|
| 982 |
+ } |
|
| 983 |
+ } |
|
| 984 |
+ } |
|
| 985 |
+ |
|
| 986 |
+ return nil |
|
| 987 |
+} |
|
| 988 |
+ |
|
| 989 |
+// Conflicts check if two NetworkConfiguration objects overlap |
|
| 990 |
+func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
|
|
| 991 |
+ if o == nil {
|
|
| 992 |
+ return fmt.Errorf("same configuration")
|
|
| 993 |
+ } |
|
| 994 |
+ |
|
| 995 |
+ // Also empty, becasue only one network with empty name is allowed |
|
| 996 |
+ if c.BridgeName == o.BridgeName {
|
|
| 997 |
+ return fmt.Errorf("networks have same bridge name")
|
|
| 998 |
+ } |
|
| 999 |
+ |
|
| 1000 |
+ // They must be in different subnets |
|
| 1001 |
+ if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) && |
|
| 1002 |
+ (c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
|
|
| 1003 |
+ return fmt.Errorf("networks have overlapping IPv4")
|
|
| 1004 |
+ } |
|
| 1005 |
+ |
|
| 1006 |
+ // They must be in different v6 subnets |
|
| 1007 |
+ if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) && |
|
| 1008 |
+ (c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
|
|
| 1009 |
+ return fmt.Errorf("networks have overlapping IPv6")
|
|
| 1010 |
+ } |
|
| 1011 |
+ |
|
| 1012 |
+ return nil |
|
| 1013 |
+} |
|
| 1014 |
+ |
|
| 1015 |
+func (c *networkConfiguration) fromLabels(labels map[string]string) error {
|
|
| 1016 |
+ var err error |
|
| 1017 |
+ for label, value := range labels {
|
|
| 1018 |
+ switch label {
|
|
| 1019 |
+ case BridgeName: |
|
| 1020 |
+ c.BridgeName = value |
|
| 1021 |
+ case netlabel.DriverMTU: |
|
| 1022 |
+ if c.Mtu, err = strconv.Atoi(value); err != nil {
|
|
| 1023 |
+ return parseErr(label, value, err.Error()) |
|
| 1024 |
+ } |
|
| 1025 |
+ case netlabel.EnableIPv6: |
|
| 1026 |
+ if c.EnableIPv6, err = strconv.ParseBool(value); err != nil {
|
|
| 1027 |
+ return parseErr(label, value, err.Error()) |
|
| 1028 |
+ } |
|
| 1029 |
+ case EnableIPMasquerade: |
|
| 1030 |
+ if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil {
|
|
| 1031 |
+ return parseErr(label, value, err.Error()) |
|
| 1032 |
+ } |
|
| 1033 |
+ case EnableICC: |
|
| 1034 |
+ if c.EnableICC, err = strconv.ParseBool(value); err != nil {
|
|
| 1035 |
+ return parseErr(label, value, err.Error()) |
|
| 1036 |
+ } |
|
| 1037 |
+ case DefaultBridge: |
|
| 1038 |
+ if c.DefaultBridge, err = strconv.ParseBool(value); err != nil {
|
|
| 1039 |
+ return parseErr(label, value, err.Error()) |
|
| 1040 |
+ } |
|
| 1041 |
+ case DefaultBindingIP: |
|
| 1042 |
+ if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil {
|
|
| 1043 |
+ return parseErr(label, value, "nil ip") |
|
| 1044 |
+ } |
|
| 1045 |
+ } |
|
| 1046 |
+ } |
|
| 1047 |
+ |
|
| 1048 |
+ return nil |
|
| 1049 |
+} |
|
| 1050 |
+ |
|
| 1051 |
+func parseErr(label, value, errString string) error {
|
|
| 1052 |
+ return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString)
|
|
| 1053 |
+} |
|
| 1054 |
+ |
|
| 1055 |
+func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) {
|
|
| 1056 |
+ var ( |
|
| 1057 |
+ err error |
|
| 1058 |
+ config *networkConfiguration |
|
| 1059 |
+ ) |
|
| 1060 |
+ |
|
| 1061 |
+ switch opt := data.(type) {
|
|
| 1062 |
+ case *networkConfiguration: |
|
| 1063 |
+ config = opt |
|
| 1064 |
+ case map[string]string: |
|
| 1065 |
+ config = &networkConfiguration{
|
|
| 1066 |
+ EnableICC: true, |
|
| 1067 |
+ EnableIPMasquerade: true, |
|
| 1068 |
+ } |
|
| 1069 |
+ err = config.fromLabels(opt) |
|
| 1070 |
+ case options.Generic: |
|
| 1071 |
+ var opaqueConfig interface{}
|
|
| 1072 |
+ if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil {
|
|
| 1073 |
+ config = opaqueConfig.(*networkConfiguration) |
|
| 1074 |
+ } |
|
| 1075 |
+ default: |
|
| 1076 |
+ err = types.BadRequestErrorf("do not recognize network configuration format: %T", opt)
|
|
| 1077 |
+ } |
|
| 1078 |
+ |
|
| 1079 |
+ return config, err |
|
| 1080 |
+} |
|
| 1081 |
+ |
|
| 1082 |
+func parseNetworkOptions(d *driver, id string, option options.Generic) (*networkConfiguration, error) {
|
|
| 1083 |
+ var ( |
|
| 1084 |
+ err error |
|
| 1085 |
+ config = &networkConfiguration{}
|
|
| 1086 |
+ ) |
|
| 1087 |
+ |
|
| 1088 |
+ // Parse generic label first, config will be re-assigned |
|
| 1089 |
+ if genData, ok := option[netlabel.GenericData]; ok && genData != nil {
|
|
| 1090 |
+ if config, err = parseNetworkGenericOptions(genData); err != nil {
|
|
| 1091 |
+ return nil, err |
|
| 1092 |
+ } |
|
| 1093 |
+ } |
|
| 1094 |
+ |
|
| 1095 |
+ // Process well-known labels next |
|
| 1096 |
+ if val, ok := option[netlabel.EnableIPv6]; ok {
|
|
| 1097 |
+ config.EnableIPv6 = val.(bool) |
|
| 1098 |
+ } |
|
| 1099 |
+ |
|
| 1100 |
+ if val, ok := option[netlabel.Internal]; ok {
|
|
| 1101 |
+ if internal, ok := val.(bool); ok && internal {
|
|
| 1102 |
+ config.Internal = true |
|
| 1103 |
+ } |
|
| 1104 |
+ } |
|
| 1105 |
+ |
|
| 1106 |
+ // Finally validate the configuration |
|
| 1107 |
+ if err = config.Validate(); err != nil {
|
|
| 1108 |
+ return nil, err |
|
| 1109 |
+ } |
|
| 1110 |
+ |
|
| 1111 |
+ if config.BridgeName == "" && config.DefaultBridge == false {
|
|
| 1112 |
+ config.BridgeName = "br_" + id[:12] + "_0" |
|
| 1113 |
+ } |
|
| 1114 |
+ |
|
| 1115 |
+ lastChar := config.BridgeName[len(config.BridgeName)-1:] |
|
| 1116 |
+ if _, err = strconv.Atoi(lastChar); err != nil {
|
|
| 1117 |
+ config.BridgeNameInternal = config.BridgeName + "_0" |
|
| 1118 |
+ } else {
|
|
| 1119 |
+ config.BridgeNameInternal = config.BridgeName |
|
| 1120 |
+ } |
|
| 1121 |
+ |
|
| 1122 |
+ config.ID = id |
|
| 1123 |
+ return config, nil |
|
| 1124 |
+} |
|
| 1125 |
+ |
|
| 1126 |
+func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
|
|
| 1127 |
+ if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 {
|
|
| 1128 |
+ return types.ForbiddenErrorf("bridge driver doesnt support multiple subnets")
|
|
| 1129 |
+ } |
|
| 1130 |
+ |
|
| 1131 |
+ if len(ipamV4Data) == 0 {
|
|
| 1132 |
+ return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id)
|
|
| 1133 |
+ } |
|
| 1134 |
+ |
|
| 1135 |
+ if ipamV4Data[0].Gateway != nil {
|
|
| 1136 |
+ c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway) |
|
| 1137 |
+ } |
|
| 1138 |
+ |
|
| 1139 |
+ if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok {
|
|
| 1140 |
+ c.DefaultGatewayIPv4 = gw.IP |
|
| 1141 |
+ } |
|
| 1142 |
+ |
|
| 1143 |
+ if len(ipamV6Data) > 0 {
|
|
| 1144 |
+ c.AddressIPv6 = ipamV6Data[0].Pool |
|
| 1145 |
+ |
|
| 1146 |
+ if ipamV6Data[0].Gateway != nil {
|
|
| 1147 |
+ c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway) |
|
| 1148 |
+ } |
|
| 1149 |
+ |
|
| 1150 |
+ if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok {
|
|
| 1151 |
+ c.DefaultGatewayIPv6 = gw.IP |
|
| 1152 |
+ } |
|
| 1153 |
+ } |
|
| 1154 |
+ |
|
| 1155 |
+ return nil |
|
| 1156 |
+} |
|
| 1157 |
+ |
|
| 1158 |
+func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
|
|
| 1159 |
+ n.Lock() |
|
| 1160 |
+ defer n.Unlock() |
|
| 1161 |
+ |
|
| 1162 |
+ if eid == "" {
|
|
| 1163 |
+ return nil, InvalidEndpointIDError(eid) |
|
| 1164 |
+ } |
|
| 1165 |
+ |
|
| 1166 |
+ if ep, ok := n.endpoints[eid]; ok {
|
|
| 1167 |
+ return ep, nil |
|
| 1168 |
+ } |
|
| 1169 |
+ |
|
| 1170 |
+ return nil, nil |
|
| 1171 |
+} |
|
| 1172 |
+ |
|
| 1173 |
+func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) {
|
|
| 1174 |
+ if epOptions == nil {
|
|
| 1175 |
+ return nil, nil |
|
| 1176 |
+ } |
|
| 1177 |
+ |
|
| 1178 |
+ ec := &endpointConfiguration{}
|
|
| 1179 |
+ |
|
| 1180 |
+ if opt, ok := epOptions[netlabel.MacAddress]; ok {
|
|
| 1181 |
+ if mac, ok := opt.(net.HardwareAddr); ok {
|
|
| 1182 |
+ ec.MacAddress = mac |
|
| 1183 |
+ } else {
|
|
| 1184 |
+ return nil, &ErrInvalidEndpointConfig{}
|
|
| 1185 |
+ } |
|
| 1186 |
+ } |
|
| 1187 |
+ |
|
| 1188 |
+ if opt, ok := epOptions[netlabel.PortMap]; ok {
|
|
| 1189 |
+ if bs, ok := opt.([]types.PortBinding); ok {
|
|
| 1190 |
+ ec.PortBindings = bs |
|
| 1191 |
+ } else {
|
|
| 1192 |
+ return nil, &ErrInvalidEndpointConfig{}
|
|
| 1193 |
+ } |
|
| 1194 |
+ } |
|
| 1195 |
+ |
|
| 1196 |
+ if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
|
|
| 1197 |
+ if ports, ok := opt.([]types.TransportPort); ok {
|
|
| 1198 |
+ ec.ExposedPorts = ports |
|
| 1199 |
+ } else {
|
|
| 1200 |
+ return nil, &ErrInvalidEndpointConfig{}
|
|
| 1201 |
+ } |
|
| 1202 |
+ } |
|
| 1203 |
+ |
|
| 1204 |
+ return ec, nil |
|
| 1205 |
+} |
|
| 1206 |
+ |
|
| 1207 |
+func parseContainerOptions(cOptions map[string]interface{}) (*containerConfiguration, error) {
|
|
| 1208 |
+ if cOptions == nil {
|
|
| 1209 |
+ return nil, nil |
|
| 1210 |
+ } |
|
| 1211 |
+ genericData := cOptions[netlabel.GenericData] |
|
| 1212 |
+ if genericData == nil {
|
|
| 1213 |
+ return nil, nil |
|
| 1214 |
+ } |
|
| 1215 |
+ switch opt := genericData.(type) {
|
|
| 1216 |
+ case options.Generic: |
|
| 1217 |
+ opaqueConfig, err := options.GenerateFromModel(opt, &containerConfiguration{})
|
|
| 1218 |
+ if err != nil {
|
|
| 1219 |
+ return nil, err |
|
| 1220 |
+ } |
|
| 1221 |
+ return opaqueConfig.(*containerConfiguration), nil |
|
| 1222 |
+ case *containerConfiguration: |
|
| 1223 |
+ return opt, nil |
|
| 1224 |
+ default: |
|
| 1225 |
+ return nil, nil |
|
| 1226 |
+ } |
|
| 1227 |
+} |
|
| 1228 |
+ |
|
| 1229 |
+func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) {
|
|
| 1230 |
+ if cOptions == nil {
|
|
| 1231 |
+ return nil, nil |
|
| 1232 |
+ } |
|
| 1233 |
+ |
|
| 1234 |
+ cc := &connectivityConfiguration{}
|
|
| 1235 |
+ |
|
| 1236 |
+ if opt, ok := cOptions[netlabel.PortMap]; ok {
|
|
| 1237 |
+ if pb, ok := opt.([]types.PortBinding); ok {
|
|
| 1238 |
+ cc.PortBindings = pb |
|
| 1239 |
+ } else {
|
|
| 1240 |
+ return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt)
|
|
| 1241 |
+ } |
|
| 1242 |
+ } |
|
| 1243 |
+ |
|
| 1244 |
+ if opt, ok := cOptions[netlabel.ExposedPorts]; ok {
|
|
| 1245 |
+ if ports, ok := opt.([]types.TransportPort); ok {
|
|
| 1246 |
+ cc.ExposedPorts = ports |
|
| 1247 |
+ } else {
|
|
| 1248 |
+ return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt)
|
|
| 1249 |
+ } |
|
| 1250 |
+ } |
|
| 1251 |
+ |
|
| 1252 |
+ return cc, nil |
|
| 1253 |
+} |
| 0 | 1254 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,384 @@ |
| 0 |
+// +build solaris |
|
| 1 |
+ |
|
| 2 |
+package bridge |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "encoding/json" |
|
| 6 |
+ "fmt" |
|
| 7 |
+ "net" |
|
| 8 |
+ |
|
| 9 |
+ "github.com/Sirupsen/logrus" |
|
| 10 |
+ "github.com/docker/libnetwork/datastore" |
|
| 11 |
+ "github.com/docker/libnetwork/discoverapi" |
|
| 12 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 13 |
+ "github.com/docker/libnetwork/types" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+const ( |
|
| 17 |
+ // network config prefix was not specific enough. |
|
| 18 |
+ // To be backward compatible, need custom endpoint |
|
| 19 |
+ // prefix with different root |
|
| 20 |
+ bridgePrefix = "bridge" |
|
| 21 |
+ bridgeEndpointPrefix = "bridge-endpoint" |
|
| 22 |
+) |
|
| 23 |
+ |
|
| 24 |
+func (d *driver) initStore(option map[string]interface{}) error {
|
|
| 25 |
+ if data, ok := option[netlabel.LocalKVClient]; ok {
|
|
| 26 |
+ var err error |
|
| 27 |
+ dsc, ok := data.(discoverapi.DatastoreConfigData) |
|
| 28 |
+ if !ok {
|
|
| 29 |
+ return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
|
|
| 30 |
+ } |
|
| 31 |
+ d.store, err = datastore.NewDataStoreFromConfig(dsc) |
|
| 32 |
+ if err != nil {
|
|
| 33 |
+ return types.InternalErrorf("bridge driver failed to initialize data store: %v", err)
|
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ err = d.populateNetworks() |
|
| 37 |
+ if err != nil {
|
|
| 38 |
+ return err |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ err = d.populateEndpoints() |
|
| 42 |
+ if err != nil {
|
|
| 43 |
+ return err |
|
| 44 |
+ } |
|
| 45 |
+ } |
|
| 46 |
+ |
|
| 47 |
+ return nil |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+func (d *driver) populateNetworks() error {
|
|
| 51 |
+ kvol, err := d.store.List(datastore.Key(bridgePrefix), &networkConfiguration{})
|
|
| 52 |
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
| 53 |
+ return fmt.Errorf("failed to get bridge network configurations from store: %v", err)
|
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 56 |
+ // It's normal for network configuration state to be empty. Just return. |
|
| 57 |
+ if err == datastore.ErrKeyNotFound {
|
|
| 58 |
+ return nil |
|
| 59 |
+ } |
|
| 60 |
+ |
|
| 61 |
+ for _, kvo := range kvol {
|
|
| 62 |
+ ncfg := kvo.(*networkConfiguration) |
|
| 63 |
+ if err = d.createNetwork(ncfg); err != nil {
|
|
| 64 |
+ logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err)
|
|
| 65 |
+ } |
|
| 66 |
+ logrus.Debugf("Network (%s) restored", ncfg.ID[0:7])
|
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ return nil |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+func (d *driver) populateEndpoints() error {
|
|
| 73 |
+ kvol, err := d.store.List(datastore.Key(bridgeEndpointPrefix), &bridgeEndpoint{})
|
|
| 74 |
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
| 75 |
+ return fmt.Errorf("failed to get bridge endpoints from store: %v", err)
|
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ if err == datastore.ErrKeyNotFound {
|
|
| 79 |
+ return nil |
|
| 80 |
+ } |
|
| 81 |
+ |
|
| 82 |
+ for _, kvo := range kvol {
|
|
| 83 |
+ ep := kvo.(*bridgeEndpoint) |
|
| 84 |
+ n, ok := d.networks[ep.nid] |
|
| 85 |
+ if !ok {
|
|
| 86 |
+ logrus.Debugf("Network (%s) not found for restored bridge endpoint (%s)", ep.nid[0:7], ep.id[0:7])
|
|
| 87 |
+ logrus.Debugf("Deleting stale bridge endpoint (%s) from store", ep.nid[0:7])
|
|
| 88 |
+ if err := d.storeDelete(ep); err != nil {
|
|
| 89 |
+ logrus.Debugf("Failed to delete stale bridge endpoint (%s) from store", ep.nid[0:7])
|
|
| 90 |
+ } |
|
| 91 |
+ continue |
|
| 92 |
+ } |
|
| 93 |
+ n.endpoints[ep.id] = ep |
|
| 94 |
+ n.restorePortAllocations(ep) |
|
| 95 |
+ logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7])
|
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 98 |
+ return nil |
|
| 99 |
+} |
|
| 100 |
+ |
|
| 101 |
+func (d *driver) storeUpdate(kvObject datastore.KVObject) error {
|
|
| 102 |
+ if d.store == nil {
|
|
| 103 |
+ logrus.Warnf("bridge store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...))
|
|
| 104 |
+ return nil |
|
| 105 |
+ } |
|
| 106 |
+ |
|
| 107 |
+ if err := d.store.PutObjectAtomic(kvObject); err != nil {
|
|
| 108 |
+ return fmt.Errorf("failed to update bridge store for object type %T: %v", kvObject, err)
|
|
| 109 |
+ } |
|
| 110 |
+ |
|
| 111 |
+ return nil |
|
| 112 |
+} |
|
| 113 |
+ |
|
| 114 |
+func (d *driver) storeDelete(kvObject datastore.KVObject) error {
|
|
| 115 |
+ if d.store == nil {
|
|
| 116 |
+ logrus.Debugf("bridge store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...))
|
|
| 117 |
+ return nil |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+retry: |
|
| 121 |
+ if err := d.store.DeleteObjectAtomic(kvObject); err != nil {
|
|
| 122 |
+ if err == datastore.ErrKeyModified {
|
|
| 123 |
+ if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
|
|
| 124 |
+ return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
|
|
| 125 |
+ } |
|
| 126 |
+ goto retry |
|
| 127 |
+ } |
|
| 128 |
+ return err |
|
| 129 |
+ } |
|
| 130 |
+ |
|
| 131 |
+ return nil |
|
| 132 |
+} |
|
| 133 |
+ |
|
| 134 |
+func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) {
|
|
| 135 |
+ nMap := make(map[string]interface{})
|
|
| 136 |
+ nMap["ID"] = ncfg.ID |
|
| 137 |
+ nMap["BridgeName"] = ncfg.BridgeName |
|
| 138 |
+ nMap["BridgeNameInternal"] = ncfg.BridgeNameInternal |
|
| 139 |
+ nMap["EnableIPv6"] = ncfg.EnableIPv6 |
|
| 140 |
+ nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade |
|
| 141 |
+ nMap["EnableICC"] = ncfg.EnableICC |
|
| 142 |
+ nMap["Mtu"] = ncfg.Mtu |
|
| 143 |
+ nMap["Internal"] = ncfg.Internal |
|
| 144 |
+ nMap["DefaultBridge"] = ncfg.DefaultBridge |
|
| 145 |
+ nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String() |
|
| 146 |
+ nMap["DefaultBindingIntf"] = ncfg.DefaultBindingIntf |
|
| 147 |
+ nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String() |
|
| 148 |
+ nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String() |
|
| 149 |
+ |
|
| 150 |
+ if ncfg.AddressIPv4 != nil {
|
|
| 151 |
+ nMap["AddressIPv4"] = ncfg.AddressIPv4.String() |
|
| 152 |
+ } |
|
| 153 |
+ |
|
| 154 |
+ if ncfg.AddressIPv6 != nil {
|
|
| 155 |
+ nMap["AddressIPv6"] = ncfg.AddressIPv6.String() |
|
| 156 |
+ } |
|
| 157 |
+ |
|
| 158 |
+ return json.Marshal(nMap) |
|
| 159 |
+} |
|
| 160 |
+ |
|
| 161 |
+func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error {
|
|
| 162 |
+ var ( |
|
| 163 |
+ err error |
|
| 164 |
+ nMap map[string]interface{}
|
|
| 165 |
+ ) |
|
| 166 |
+ |
|
| 167 |
+ if err = json.Unmarshal(b, &nMap); err != nil {
|
|
| 168 |
+ return err |
|
| 169 |
+ } |
|
| 170 |
+ |
|
| 171 |
+ if v, ok := nMap["AddressIPv4"]; ok {
|
|
| 172 |
+ if ncfg.AddressIPv4, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 173 |
+ return types.InternalErrorf("failed to decode bridge network address IPv4 after json unmarshal: %s", v.(string))
|
|
| 174 |
+ } |
|
| 175 |
+ } |
|
| 176 |
+ |
|
| 177 |
+ if v, ok := nMap["AddressIPv6"]; ok {
|
|
| 178 |
+ if ncfg.AddressIPv6, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 179 |
+ return types.InternalErrorf("failed to decode bridge network address IPv6 after json unmarshal: %s", v.(string))
|
|
| 180 |
+ } |
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ ncfg.DefaultBridge = nMap["DefaultBridge"].(bool) |
|
| 184 |
+ ncfg.DefaultBindingIP = net.ParseIP(nMap["DefaultBindingIP"].(string)) |
|
| 185 |
+ ncfg.DefaultBindingIntf = nMap["DefaultBindingIntf"].(string) |
|
| 186 |
+ ncfg.DefaultGatewayIPv4 = net.ParseIP(nMap["DefaultGatewayIPv4"].(string)) |
|
| 187 |
+ ncfg.DefaultGatewayIPv6 = net.ParseIP(nMap["DefaultGatewayIPv6"].(string)) |
|
| 188 |
+ ncfg.ID = nMap["ID"].(string) |
|
| 189 |
+ ncfg.BridgeName = nMap["BridgeName"].(string) |
|
| 190 |
+ ncfg.BridgeNameInternal = nMap["BridgeNameInternal"].(string) |
|
| 191 |
+ ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool) |
|
| 192 |
+ ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool) |
|
| 193 |
+ ncfg.EnableICC = nMap["EnableICC"].(bool) |
|
| 194 |
+ ncfg.Mtu = int(nMap["Mtu"].(float64)) |
|
| 195 |
+ if v, ok := nMap["Internal"]; ok {
|
|
| 196 |
+ ncfg.Internal = v.(bool) |
|
| 197 |
+ } |
|
| 198 |
+ |
|
| 199 |
+ return nil |
|
| 200 |
+} |
|
| 201 |
+ |
|
| 202 |
+func (ncfg *networkConfiguration) Key() []string {
|
|
| 203 |
+ return []string{bridgePrefix, ncfg.ID}
|
|
| 204 |
+} |
|
| 205 |
+ |
|
| 206 |
+func (ncfg *networkConfiguration) KeyPrefix() []string {
|
|
| 207 |
+ return []string{bridgePrefix}
|
|
| 208 |
+} |
|
| 209 |
+ |
|
| 210 |
+func (ncfg *networkConfiguration) Value() []byte {
|
|
| 211 |
+ b, err := json.Marshal(ncfg) |
|
| 212 |
+ if err != nil {
|
|
| 213 |
+ return nil |
|
| 214 |
+ } |
|
| 215 |
+ return b |
|
| 216 |
+} |
|
| 217 |
+ |
|
| 218 |
+func (ncfg *networkConfiguration) SetValue(value []byte) error {
|
|
| 219 |
+ return json.Unmarshal(value, ncfg) |
|
| 220 |
+} |
|
| 221 |
+ |
|
| 222 |
+func (ncfg *networkConfiguration) Index() uint64 {
|
|
| 223 |
+ return ncfg.dbIndex |
|
| 224 |
+} |
|
| 225 |
+ |
|
| 226 |
+func (ncfg *networkConfiguration) SetIndex(index uint64) {
|
|
| 227 |
+ ncfg.dbIndex = index |
|
| 228 |
+ ncfg.dbExists = true |
|
| 229 |
+} |
|
| 230 |
+ |
|
| 231 |
+func (ncfg *networkConfiguration) Exists() bool {
|
|
| 232 |
+ return ncfg.dbExists |
|
| 233 |
+} |
|
| 234 |
+ |
|
| 235 |
+func (ncfg *networkConfiguration) Skip() bool {
|
|
| 236 |
+ return false |
|
| 237 |
+} |
|
| 238 |
+ |
|
| 239 |
+func (ncfg *networkConfiguration) New() datastore.KVObject {
|
|
| 240 |
+ return &networkConfiguration{}
|
|
| 241 |
+} |
|
| 242 |
+ |
|
| 243 |
+func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error {
|
|
| 244 |
+ dstNcfg := o.(*networkConfiguration) |
|
| 245 |
+ *dstNcfg = *ncfg |
|
| 246 |
+ return nil |
|
| 247 |
+} |
|
| 248 |
+ |
|
| 249 |
+func (ncfg *networkConfiguration) DataScope() string {
|
|
| 250 |
+ return datastore.LocalScope |
|
| 251 |
+} |
|
| 252 |
+ |
|
| 253 |
+func (ep *bridgeEndpoint) MarshalJSON() ([]byte, error) {
|
|
| 254 |
+ epMap := make(map[string]interface{})
|
|
| 255 |
+ epMap["id"] = ep.id |
|
| 256 |
+ epMap["nid"] = ep.nid |
|
| 257 |
+ epMap["SrcName"] = ep.srcName |
|
| 258 |
+ epMap["MacAddress"] = ep.macAddress.String() |
|
| 259 |
+ epMap["Addr"] = ep.addr.String() |
|
| 260 |
+ if ep.addrv6 != nil {
|
|
| 261 |
+ epMap["Addrv6"] = ep.addrv6.String() |
|
| 262 |
+ } |
|
| 263 |
+ epMap["Config"] = ep.config |
|
| 264 |
+ epMap["ContainerConfig"] = ep.containerConfig |
|
| 265 |
+ epMap["ExternalConnConfig"] = ep.extConnConfig |
|
| 266 |
+ epMap["PortMapping"] = ep.portMapping |
|
| 267 |
+ |
|
| 268 |
+ return json.Marshal(epMap) |
|
| 269 |
+} |
|
| 270 |
+ |
|
| 271 |
+func (ep *bridgeEndpoint) UnmarshalJSON(b []byte) error {
|
|
| 272 |
+ var ( |
|
| 273 |
+ err error |
|
| 274 |
+ epMap map[string]interface{}
|
|
| 275 |
+ ) |
|
| 276 |
+ |
|
| 277 |
+ if err = json.Unmarshal(b, &epMap); err != nil {
|
|
| 278 |
+ return fmt.Errorf("Failed to unmarshal to bridge endpoint: %v", err)
|
|
| 279 |
+ } |
|
| 280 |
+ |
|
| 281 |
+ if v, ok := epMap["MacAddress"]; ok {
|
|
| 282 |
+ if ep.macAddress, err = net.ParseMAC(v.(string)); err != nil {
|
|
| 283 |
+ return types.InternalErrorf("failed to decode bridge endpoint MAC address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 284 |
+ } |
|
| 285 |
+ } |
|
| 286 |
+ if v, ok := epMap["Addr"]; ok {
|
|
| 287 |
+ if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 288 |
+ return types.InternalErrorf("failed to decode bridge endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 289 |
+ } |
|
| 290 |
+ } |
|
| 291 |
+ if v, ok := epMap["Addrv6"]; ok {
|
|
| 292 |
+ if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 293 |
+ return types.InternalErrorf("failed to decode bridge endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 294 |
+ } |
|
| 295 |
+ } |
|
| 296 |
+ ep.id = epMap["id"].(string) |
|
| 297 |
+ ep.nid = epMap["nid"].(string) |
|
| 298 |
+ ep.srcName = epMap["SrcName"].(string) |
|
| 299 |
+ d, _ := json.Marshal(epMap["Config"]) |
|
| 300 |
+ if err := json.Unmarshal(d, &ep.config); err != nil {
|
|
| 301 |
+ logrus.Warnf("Failed to decode endpoint config %v", err)
|
|
| 302 |
+ } |
|
| 303 |
+ d, _ = json.Marshal(epMap["ContainerConfig"]) |
|
| 304 |
+ if err := json.Unmarshal(d, &ep.containerConfig); err != nil {
|
|
| 305 |
+ logrus.Warnf("Failed to decode endpoint container config %v", err)
|
|
| 306 |
+ } |
|
| 307 |
+ d, _ = json.Marshal(epMap["ExternalConnConfig"]) |
|
| 308 |
+ if err := json.Unmarshal(d, &ep.extConnConfig); err != nil {
|
|
| 309 |
+ logrus.Warnf("Failed to decode endpoint external connectivity configuration %v", err)
|
|
| 310 |
+ } |
|
| 311 |
+ d, _ = json.Marshal(epMap["PortMapping"]) |
|
| 312 |
+ if err := json.Unmarshal(d, &ep.portMapping); err != nil {
|
|
| 313 |
+ logrus.Warnf("Failed to decode endpoint port mapping %v", err)
|
|
| 314 |
+ } |
|
| 315 |
+ |
|
| 316 |
+ return nil |
|
| 317 |
+} |
|
| 318 |
+ |
|
| 319 |
+func (ep *bridgeEndpoint) Key() []string {
|
|
| 320 |
+ return []string{bridgeEndpointPrefix, ep.id}
|
|
| 321 |
+} |
|
| 322 |
+ |
|
| 323 |
+func (ep *bridgeEndpoint) KeyPrefix() []string {
|
|
| 324 |
+ return []string{bridgeEndpointPrefix}
|
|
| 325 |
+} |
|
| 326 |
+ |
|
| 327 |
+func (ep *bridgeEndpoint) Value() []byte {
|
|
| 328 |
+ b, err := json.Marshal(ep) |
|
| 329 |
+ if err != nil {
|
|
| 330 |
+ return nil |
|
| 331 |
+ } |
|
| 332 |
+ return b |
|
| 333 |
+} |
|
| 334 |
+ |
|
| 335 |
+func (ep *bridgeEndpoint) SetValue(value []byte) error {
|
|
| 336 |
+ return json.Unmarshal(value, ep) |
|
| 337 |
+} |
|
| 338 |
+ |
|
| 339 |
+func (ep *bridgeEndpoint) Index() uint64 {
|
|
| 340 |
+ return ep.dbIndex |
|
| 341 |
+} |
|
| 342 |
+ |
|
| 343 |
+func (ep *bridgeEndpoint) SetIndex(index uint64) {
|
|
| 344 |
+ ep.dbIndex = index |
|
| 345 |
+ ep.dbExists = true |
|
| 346 |
+} |
|
| 347 |
+ |
|
| 348 |
+func (ep *bridgeEndpoint) Exists() bool {
|
|
| 349 |
+ return ep.dbExists |
|
| 350 |
+} |
|
| 351 |
+ |
|
| 352 |
+func (ep *bridgeEndpoint) Skip() bool {
|
|
| 353 |
+ return false |
|
| 354 |
+} |
|
| 355 |
+ |
|
| 356 |
+func (ep *bridgeEndpoint) New() datastore.KVObject {
|
|
| 357 |
+ return &bridgeEndpoint{}
|
|
| 358 |
+} |
|
| 359 |
+ |
|
| 360 |
+func (ep *bridgeEndpoint) CopyTo(o datastore.KVObject) error {
|
|
| 361 |
+ dstEp := o.(*bridgeEndpoint) |
|
| 362 |
+ *dstEp = *ep |
|
| 363 |
+ return nil |
|
| 364 |
+} |
|
| 365 |
+ |
|
| 366 |
+func (ep *bridgeEndpoint) DataScope() string {
|
|
| 367 |
+ return datastore.LocalScope |
|
| 368 |
+} |
|
| 369 |
+ |
|
| 370 |
+func (n *bridgeNetwork) restorePortAllocations(ep *bridgeEndpoint) {
|
|
| 371 |
+ if ep.extConnConfig == nil || |
|
| 372 |
+ ep.extConnConfig.ExposedPorts == nil || |
|
| 373 |
+ ep.extConnConfig.PortBindings == nil {
|
|
| 374 |
+ return |
|
| 375 |
+ } |
|
| 376 |
+ tmp := ep.extConnConfig.PortBindings |
|
| 377 |
+ ep.extConnConfig.PortBindings = ep.portMapping |
|
| 378 |
+ _, err := n.allocatePorts(ep, n.config.DefaultBindingIntf, n.config.DefaultBindingIP, n.driver.config.EnableUserlandProxy) |
|
| 379 |
+ if err != nil {
|
|
| 380 |
+ logrus.Warnf("Failed to reserve existing port mapping for endpoint %s:%v", ep.id[0:7], err)
|
|
| 381 |
+ } |
|
| 382 |
+ ep.extConnConfig.PortBindings = tmp |
|
| 383 |
+} |
| 0 | 384 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,675 @@ |
| 0 |
+// +build solaris |
|
| 1 |
+ |
|
| 2 |
+package bridge |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "bytes" |
|
| 6 |
+ "encoding/json" |
|
| 7 |
+ "net" |
|
| 8 |
+ "testing" |
|
| 9 |
+ |
|
| 10 |
+ "github.com/docker/libnetwork/driverapi" |
|
| 11 |
+ "github.com/docker/libnetwork/ipamutils" |
|
| 12 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 13 |
+ "github.com/docker/libnetwork/netutils" |
|
| 14 |
+ "github.com/docker/libnetwork/testutils" |
|
| 15 |
+ "github.com/docker/libnetwork/types" |
|
| 16 |
+) |
|
| 17 |
+ |
|
| 18 |
+func init() {
|
|
| 19 |
+ ipamutils.InitNetworks() |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+func TestEndpointMarshalling(t *testing.T) {
|
|
| 23 |
+ ip1, _ := types.ParseCIDR("172.22.0.9/16")
|
|
| 24 |
+ ip2, _ := types.ParseCIDR("2001:db8::9")
|
|
| 25 |
+ mac, _ := net.ParseMAC("ac:bd:24:57:66:77")
|
|
| 26 |
+ e := &bridgeEndpoint{
|
|
| 27 |
+ id: "d2c015a1fe5930650cbcd50493efba0500bcebd8ee1f4401a16319f8a567de33", |
|
| 28 |
+ nid: "ee33fbb43c323f1920b6b35a0101552ac22ede960d0e5245e9738bccc68b2415", |
|
| 29 |
+ addr: ip1, |
|
| 30 |
+ addrv6: ip2, |
|
| 31 |
+ macAddress: mac, |
|
| 32 |
+ srcName: "veth123456", |
|
| 33 |
+ config: &endpointConfiguration{MacAddress: mac},
|
|
| 34 |
+ containerConfig: &containerConfiguration{
|
|
| 35 |
+ ParentEndpoints: []string{"one", "due", "three"},
|
|
| 36 |
+ ChildEndpoints: []string{"four", "five", "six"},
|
|
| 37 |
+ }, |
|
| 38 |
+ extConnConfig: &connectivityConfiguration{
|
|
| 39 |
+ ExposedPorts: []types.TransportPort{
|
|
| 40 |
+ {
|
|
| 41 |
+ Proto: 6, |
|
| 42 |
+ Port: uint16(18), |
|
| 43 |
+ }, |
|
| 44 |
+ }, |
|
| 45 |
+ PortBindings: []types.PortBinding{
|
|
| 46 |
+ {
|
|
| 47 |
+ Proto: 6, |
|
| 48 |
+ IP: net.ParseIP("17210.33.9.56"),
|
|
| 49 |
+ Port: uint16(18), |
|
| 50 |
+ HostPort: uint16(3000), |
|
| 51 |
+ HostPortEnd: uint16(14000), |
|
| 52 |
+ }, |
|
| 53 |
+ }, |
|
| 54 |
+ }, |
|
| 55 |
+ portMapping: []types.PortBinding{
|
|
| 56 |
+ {
|
|
| 57 |
+ Proto: 17, |
|
| 58 |
+ IP: net.ParseIP("172.33.9.56"),
|
|
| 59 |
+ Port: uint16(99), |
|
| 60 |
+ HostIP: net.ParseIP("10.10.100.2"),
|
|
| 61 |
+ HostPort: uint16(9900), |
|
| 62 |
+ HostPortEnd: uint16(10000), |
|
| 63 |
+ }, |
|
| 64 |
+ {
|
|
| 65 |
+ Proto: 6, |
|
| 66 |
+ IP: net.ParseIP("171.33.9.56"),
|
|
| 67 |
+ Port: uint16(55), |
|
| 68 |
+ HostIP: net.ParseIP("10.11.100.2"),
|
|
| 69 |
+ HostPort: uint16(5500), |
|
| 70 |
+ HostPortEnd: uint16(55000), |
|
| 71 |
+ }, |
|
| 72 |
+ }, |
|
| 73 |
+ } |
|
| 74 |
+ |
|
| 75 |
+ b, err := json.Marshal(e) |
|
| 76 |
+ if err != nil {
|
|
| 77 |
+ t.Fatal(err) |
|
| 78 |
+ } |
|
| 79 |
+ |
|
| 80 |
+ ee := &bridgeEndpoint{}
|
|
| 81 |
+ err = json.Unmarshal(b, ee) |
|
| 82 |
+ if err != nil {
|
|
| 83 |
+ t.Fatal(err) |
|
| 84 |
+ } |
|
| 85 |
+ |
|
| 86 |
+ if e.id != ee.id || e.nid != ee.nid || e.srcName != ee.srcName || !bytes.Equal(e.macAddress, ee.macAddress) || |
|
| 87 |
+ !types.CompareIPNet(e.addr, ee.addr) || !types.CompareIPNet(e.addrv6, ee.addrv6) || |
|
| 88 |
+ !compareEpConfig(e.config, ee.config) || |
|
| 89 |
+ !compareContainerConfig(e.containerConfig, ee.containerConfig) || |
|
| 90 |
+ !compareConnConfig(e.extConnConfig, ee.extConnConfig) || |
|
| 91 |
+ !compareBindings(e.portMapping, ee.portMapping) {
|
|
| 92 |
+ t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v", e, ee)
|
|
| 93 |
+ } |
|
| 94 |
+} |
|
| 95 |
+ |
|
| 96 |
+func compareEpConfig(a, b *endpointConfiguration) bool {
|
|
| 97 |
+ if a == b {
|
|
| 98 |
+ return true |
|
| 99 |
+ } |
|
| 100 |
+ if a == nil || b == nil {
|
|
| 101 |
+ return false |
|
| 102 |
+ } |
|
| 103 |
+ return bytes.Equal(a.MacAddress, b.MacAddress) |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+func compareContainerConfig(a, b *containerConfiguration) bool {
|
|
| 107 |
+ if a == b {
|
|
| 108 |
+ return true |
|
| 109 |
+ } |
|
| 110 |
+ if a == nil || b == nil {
|
|
| 111 |
+ return false |
|
| 112 |
+ } |
|
| 113 |
+ if len(a.ParentEndpoints) != len(b.ParentEndpoints) || |
|
| 114 |
+ len(a.ChildEndpoints) != len(b.ChildEndpoints) {
|
|
| 115 |
+ return false |
|
| 116 |
+ } |
|
| 117 |
+ for i := 0; i < len(a.ParentEndpoints); i++ {
|
|
| 118 |
+ if a.ParentEndpoints[i] != b.ParentEndpoints[i] {
|
|
| 119 |
+ return false |
|
| 120 |
+ } |
|
| 121 |
+ } |
|
| 122 |
+ for i := 0; i < len(a.ChildEndpoints); i++ {
|
|
| 123 |
+ if a.ChildEndpoints[i] != b.ChildEndpoints[i] {
|
|
| 124 |
+ return false |
|
| 125 |
+ } |
|
| 126 |
+ } |
|
| 127 |
+ return true |
|
| 128 |
+} |
|
| 129 |
+ |
|
| 130 |
+func compareConnConfig(a, b *connectivityConfiguration) bool {
|
|
| 131 |
+ if a == b {
|
|
| 132 |
+ return true |
|
| 133 |
+ } |
|
| 134 |
+ if a == nil || b == nil {
|
|
| 135 |
+ return false |
|
| 136 |
+ } |
|
| 137 |
+ if len(a.ExposedPorts) != len(b.ExposedPorts) || |
|
| 138 |
+ len(a.PortBindings) != len(b.PortBindings) {
|
|
| 139 |
+ return false |
|
| 140 |
+ } |
|
| 141 |
+ for i := 0; i < len(a.ExposedPorts); i++ {
|
|
| 142 |
+ if !a.ExposedPorts[i].Equal(&b.ExposedPorts[i]) {
|
|
| 143 |
+ return false |
|
| 144 |
+ } |
|
| 145 |
+ } |
|
| 146 |
+ for i := 0; i < len(a.PortBindings); i++ {
|
|
| 147 |
+ if !a.PortBindings[i].Equal(&b.PortBindings[i]) {
|
|
| 148 |
+ return false |
|
| 149 |
+ } |
|
| 150 |
+ } |
|
| 151 |
+ return true |
|
| 152 |
+} |
|
| 153 |
+ |
|
| 154 |
+func compareBindings(a, b []types.PortBinding) bool {
|
|
| 155 |
+ if len(a) != len(b) {
|
|
| 156 |
+ return false |
|
| 157 |
+ } |
|
| 158 |
+ for i := 0; i < len(a); i++ {
|
|
| 159 |
+ if !a[i].Equal(&b[i]) {
|
|
| 160 |
+ return false |
|
| 161 |
+ } |
|
| 162 |
+ } |
|
| 163 |
+ return true |
|
| 164 |
+} |
|
| 165 |
+ |
|
| 166 |
+func getIPv4Data(t *testing.T) []driverapi.IPAMData {
|
|
| 167 |
+ ipd := driverapi.IPAMData{AddressSpace: "full"}
|
|
| 168 |
+ nw, _, err := netutils.ElectInterfaceAddresses("")
|
|
| 169 |
+ if err != nil {
|
|
| 170 |
+ t.Fatal(err) |
|
| 171 |
+ } |
|
| 172 |
+ ipd.Pool = nw |
|
| 173 |
+ // Set network gateway to X.X.X.1 |
|
| 174 |
+ ipd.Gateway = types.GetIPNetCopy(nw) |
|
| 175 |
+ ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1 |
|
| 176 |
+ return []driverapi.IPAMData{ipd}
|
|
| 177 |
+} |
|
| 178 |
+ |
|
| 179 |
+func TestCreateFullOptions(t *testing.T) {
|
|
| 180 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 181 |
+ d := newDriver() |
|
| 182 |
+ |
|
| 183 |
+ config := &configuration{
|
|
| 184 |
+ EnableIPForwarding: true, |
|
| 185 |
+ EnableIPTables: true, |
|
| 186 |
+ } |
|
| 187 |
+ |
|
| 188 |
+ // Test this scenario: Default gw address does not belong to |
|
| 189 |
+ // container network and it's greater than bridge address |
|
| 190 |
+ cnw, _ := types.ParseCIDR("172.16.122.0/24")
|
|
| 191 |
+ bnw, _ := types.ParseCIDR("172.16.0.0/24")
|
|
| 192 |
+ br, _ := types.ParseCIDR("172.16.0.1/16")
|
|
| 193 |
+ defgw, _ := types.ParseCIDR("172.16.0.100/16")
|
|
| 194 |
+ |
|
| 195 |
+ genericOption := make(map[string]interface{})
|
|
| 196 |
+ genericOption[netlabel.GenericData] = config |
|
| 197 |
+ |
|
| 198 |
+ if err := d.configure(genericOption); err != nil {
|
|
| 199 |
+ t.Fatalf("Failed to setup driver config: %v", err)
|
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 202 |
+ netOption := make(map[string]interface{})
|
|
| 203 |
+ netOption[netlabel.EnableIPv6] = true |
|
| 204 |
+ netOption[netlabel.GenericData] = &networkConfiguration{
|
|
| 205 |
+ BridgeName: DefaultBridgeName, |
|
| 206 |
+ } |
|
| 207 |
+ |
|
| 208 |
+ ipdList := []driverapi.IPAMData{
|
|
| 209 |
+ {
|
|
| 210 |
+ Pool: bnw, |
|
| 211 |
+ Gateway: br, |
|
| 212 |
+ AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
|
|
| 213 |
+ }, |
|
| 214 |
+ } |
|
| 215 |
+ err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
|
|
| 216 |
+ if err != nil {
|
|
| 217 |
+ t.Fatalf("Failed to create bridge: %v", err)
|
|
| 218 |
+ } |
|
| 219 |
+ |
|
| 220 |
+ // Verify the IP address allocated for the endpoint belongs to the container network |
|
| 221 |
+ epOptions := make(map[string]interface{})
|
|
| 222 |
+ te := newTestEndpoint(cnw, 10) |
|
| 223 |
+ err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
|
|
| 224 |
+ if err != nil {
|
|
| 225 |
+ t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
|
| 226 |
+ } |
|
| 227 |
+ |
|
| 228 |
+ if !cnw.Contains(te.Interface().Address().IP) {
|
|
| 229 |
+ t.Fatalf("endpoint got assigned address outside of container network(%s): %s", cnw.String(), te.Interface().Address())
|
|
| 230 |
+ } |
|
| 231 |
+} |
|
| 232 |
+ |
|
| 233 |
+func TestCreateNoConfig(t *testing.T) {
|
|
| 234 |
+ if !testutils.IsRunningInContainer() {
|
|
| 235 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 236 |
+ } |
|
| 237 |
+ d := newDriver() |
|
| 238 |
+ |
|
| 239 |
+ netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
|
| 240 |
+ genericOption := make(map[string]interface{})
|
|
| 241 |
+ genericOption[netlabel.GenericData] = netconfig |
|
| 242 |
+ |
|
| 243 |
+ if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
|
|
| 244 |
+ t.Fatalf("Failed to create bridge: %v", err)
|
|
| 245 |
+ } |
|
| 246 |
+} |
|
| 247 |
+ |
|
| 248 |
+func TestCreateFullOptionsLabels(t *testing.T) {
|
|
| 249 |
+ if !testutils.IsRunningInContainer() {
|
|
| 250 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 251 |
+ } |
|
| 252 |
+ d := newDriver() |
|
| 253 |
+ |
|
| 254 |
+ config := &configuration{
|
|
| 255 |
+ EnableIPForwarding: true, |
|
| 256 |
+ } |
|
| 257 |
+ genericOption := make(map[string]interface{})
|
|
| 258 |
+ genericOption[netlabel.GenericData] = config |
|
| 259 |
+ |
|
| 260 |
+ if err := d.configure(genericOption); err != nil {
|
|
| 261 |
+ t.Fatalf("Failed to setup driver config: %v", err)
|
|
| 262 |
+ } |
|
| 263 |
+ |
|
| 264 |
+ bndIPs := "127.0.0.1" |
|
| 265 |
+ nwV6s := "2001:db8:2600:2700:2800::/80" |
|
| 266 |
+ gwV6s := "2001:db8:2600:2700:2800::25/80" |
|
| 267 |
+ nwV6, _ := types.ParseCIDR(nwV6s) |
|
| 268 |
+ gwV6, _ := types.ParseCIDR(gwV6s) |
|
| 269 |
+ |
|
| 270 |
+ labels := map[string]string{
|
|
| 271 |
+ BridgeName: DefaultBridgeName, |
|
| 272 |
+ DefaultBridge: "true", |
|
| 273 |
+ EnableICC: "true", |
|
| 274 |
+ EnableIPMasquerade: "true", |
|
| 275 |
+ DefaultBindingIP: bndIPs, |
|
| 276 |
+ } |
|
| 277 |
+ |
|
| 278 |
+ netOption := make(map[string]interface{})
|
|
| 279 |
+ netOption[netlabel.EnableIPv6] = true |
|
| 280 |
+ netOption[netlabel.GenericData] = labels |
|
| 281 |
+ |
|
| 282 |
+ ipdList := getIPv4Data(t) |
|
| 283 |
+ ipd6List := []driverapi.IPAMData{
|
|
| 284 |
+ {
|
|
| 285 |
+ Pool: nwV6, |
|
| 286 |
+ AuxAddresses: map[string]*net.IPNet{
|
|
| 287 |
+ DefaultGatewayV6AuxKey: gwV6, |
|
| 288 |
+ }, |
|
| 289 |
+ }, |
|
| 290 |
+ } |
|
| 291 |
+ |
|
| 292 |
+ err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List)
|
|
| 293 |
+ if err != nil {
|
|
| 294 |
+ t.Fatalf("Failed to create bridge: %v", err)
|
|
| 295 |
+ } |
|
| 296 |
+ |
|
| 297 |
+ nw, ok := d.networks["dummy"] |
|
| 298 |
+ if !ok {
|
|
| 299 |
+ t.Fatalf("Cannot find dummy network in bridge driver")
|
|
| 300 |
+ } |
|
| 301 |
+ |
|
| 302 |
+ if nw.config.BridgeName != DefaultBridgeName {
|
|
| 303 |
+ t.Fatalf("incongruent name in bridge network")
|
|
| 304 |
+ } |
|
| 305 |
+ |
|
| 306 |
+ if !nw.config.EnableIPv6 {
|
|
| 307 |
+ t.Fatalf("incongruent EnableIPv6 in bridge network")
|
|
| 308 |
+ } |
|
| 309 |
+ |
|
| 310 |
+ if !nw.config.EnableICC {
|
|
| 311 |
+ t.Fatalf("incongruent EnableICC in bridge network")
|
|
| 312 |
+ } |
|
| 313 |
+ |
|
| 314 |
+ if !nw.config.EnableIPMasquerade {
|
|
| 315 |
+ t.Fatalf("incongruent EnableIPMasquerade in bridge network")
|
|
| 316 |
+ } |
|
| 317 |
+ |
|
| 318 |
+ bndIP := net.ParseIP(bndIPs) |
|
| 319 |
+ if !bndIP.Equal(nw.config.DefaultBindingIP) {
|
|
| 320 |
+ t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP)
|
|
| 321 |
+ } |
|
| 322 |
+ |
|
| 323 |
+ if !types.CompareIPNet(nw.config.AddressIPv6, nwV6) {
|
|
| 324 |
+ t.Fatalf("Unexpected: %v", nw.config.AddressIPv6)
|
|
| 325 |
+ } |
|
| 326 |
+ |
|
| 327 |
+ if !gwV6.IP.Equal(nw.config.DefaultGatewayIPv6) {
|
|
| 328 |
+ t.Fatalf("Unexpected: %v", nw.config.DefaultGatewayIPv6)
|
|
| 329 |
+ } |
|
| 330 |
+ |
|
| 331 |
+ // In short here we are testing --fixed-cidr-v6 daemon option |
|
| 332 |
+ // plus --mac-address run option |
|
| 333 |
+ mac, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff")
|
|
| 334 |
+ epOptions := map[string]interface{}{netlabel.MacAddress: mac}
|
|
| 335 |
+ te := newTestEndpoint(ipdList[0].Pool, 20) |
|
| 336 |
+ err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
|
|
| 337 |
+ if err != nil {
|
|
| 338 |
+ t.Fatal(err) |
|
| 339 |
+ } |
|
| 340 |
+} |
|
| 341 |
+ |
|
| 342 |
+func TestCreate(t *testing.T) {
|
|
| 343 |
+ if !testutils.IsRunningInContainer() {
|
|
| 344 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 345 |
+ } |
|
| 346 |
+ |
|
| 347 |
+ d := newDriver() |
|
| 348 |
+ |
|
| 349 |
+ if err := d.configure(nil); err != nil {
|
|
| 350 |
+ t.Fatalf("Failed to setup driver config: %v", err)
|
|
| 351 |
+ } |
|
| 352 |
+ |
|
| 353 |
+ netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
|
| 354 |
+ genericOption := make(map[string]interface{})
|
|
| 355 |
+ genericOption[netlabel.GenericData] = netconfig |
|
| 356 |
+ |
|
| 357 |
+ if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
|
|
| 358 |
+ t.Fatalf("Failed to create bridge: %v", err)
|
|
| 359 |
+ } |
|
| 360 |
+ |
|
| 361 |
+ err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil)
|
|
| 362 |
+ if err == nil {
|
|
| 363 |
+ t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
|
|
| 364 |
+ } |
|
| 365 |
+ if _, ok := err.(types.ForbiddenError); !ok {
|
|
| 366 |
+ t.Fatalf("Creation of second network with default name failed with unexpected error type")
|
|
| 367 |
+ } |
|
| 368 |
+} |
|
| 369 |
+ |
|
| 370 |
+func TestCreateFail(t *testing.T) {
|
|
| 371 |
+ if !testutils.IsRunningInContainer() {
|
|
| 372 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 373 |
+ } |
|
| 374 |
+ |
|
| 375 |
+ d := newDriver() |
|
| 376 |
+ |
|
| 377 |
+ if err := d.configure(nil); err != nil {
|
|
| 378 |
+ t.Fatalf("Failed to setup driver config: %v", err)
|
|
| 379 |
+ } |
|
| 380 |
+ |
|
| 381 |
+ netconfig := &networkConfiguration{BridgeName: "dummy0", DefaultBridge: true}
|
|
| 382 |
+ genericOption := make(map[string]interface{})
|
|
| 383 |
+ genericOption[netlabel.GenericData] = netconfig |
|
| 384 |
+ |
|
| 385 |
+ if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err == nil {
|
|
| 386 |
+ t.Fatal("Bridge creation was expected to fail")
|
|
| 387 |
+ } |
|
| 388 |
+} |
|
| 389 |
+ |
|
| 390 |
+type testInterface struct {
|
|
| 391 |
+ mac net.HardwareAddr |
|
| 392 |
+ addr *net.IPNet |
|
| 393 |
+ addrv6 *net.IPNet |
|
| 394 |
+ srcName string |
|
| 395 |
+ dstName string |
|
| 396 |
+} |
|
| 397 |
+ |
|
| 398 |
+type testEndpoint struct {
|
|
| 399 |
+ iface *testInterface |
|
| 400 |
+ gw net.IP |
|
| 401 |
+ gw6 net.IP |
|
| 402 |
+ hostsPath string |
|
| 403 |
+ resolvConfPath string |
|
| 404 |
+ routes []types.StaticRoute |
|
| 405 |
+} |
|
| 406 |
+ |
|
| 407 |
+func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint {
|
|
| 408 |
+ addr := types.GetIPNetCopy(nw) |
|
| 409 |
+ addr.IP[len(addr.IP)-1] = ordinal |
|
| 410 |
+ return &testEndpoint{iface: &testInterface{addr: addr}}
|
|
| 411 |
+} |
|
| 412 |
+ |
|
| 413 |
+func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
|
|
| 414 |
+ if te.iface != nil {
|
|
| 415 |
+ return te.iface |
|
| 416 |
+ } |
|
| 417 |
+ |
|
| 418 |
+ return nil |
|
| 419 |
+} |
|
| 420 |
+ |
|
| 421 |
+func (i *testInterface) MacAddress() net.HardwareAddr {
|
|
| 422 |
+ return i.mac |
|
| 423 |
+} |
|
| 424 |
+ |
|
| 425 |
+func (i *testInterface) Address() *net.IPNet {
|
|
| 426 |
+ return i.addr |
|
| 427 |
+} |
|
| 428 |
+ |
|
| 429 |
+func (i *testInterface) AddressIPv6() *net.IPNet {
|
|
| 430 |
+ return i.addrv6 |
|
| 431 |
+} |
|
| 432 |
+ |
|
| 433 |
+func (i *testInterface) SetMacAddress(mac net.HardwareAddr) error {
|
|
| 434 |
+ if i.mac != nil {
|
|
| 435 |
+ return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", i.mac, mac)
|
|
| 436 |
+ } |
|
| 437 |
+ if mac == nil {
|
|
| 438 |
+ return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
|
|
| 439 |
+ } |
|
| 440 |
+ i.mac = types.GetMacCopy(mac) |
|
| 441 |
+ return nil |
|
| 442 |
+} |
|
| 443 |
+ |
|
| 444 |
+func (i *testInterface) SetIPAddress(address *net.IPNet) error {
|
|
| 445 |
+ if address.IP == nil {
|
|
| 446 |
+ return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
|
|
| 447 |
+ } |
|
| 448 |
+ if address.IP.To4() == nil {
|
|
| 449 |
+ return setAddress(&i.addrv6, address) |
|
| 450 |
+ } |
|
| 451 |
+ return setAddress(&i.addr, address) |
|
| 452 |
+} |
|
| 453 |
+ |
|
| 454 |
+func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
|
|
| 455 |
+ if *ifaceAddr != nil {
|
|
| 456 |
+ return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
|
|
| 457 |
+ } |
|
| 458 |
+ *ifaceAddr = types.GetIPNetCopy(address) |
|
| 459 |
+ return nil |
|
| 460 |
+} |
|
| 461 |
+ |
|
| 462 |
+func (i *testInterface) SetNames(srcName string, dstName string) error {
|
|
| 463 |
+ i.srcName = srcName |
|
| 464 |
+ i.dstName = dstName |
|
| 465 |
+ return nil |
|
| 466 |
+} |
|
| 467 |
+ |
|
| 468 |
+func (te *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
|
|
| 469 |
+ if te.iface != nil {
|
|
| 470 |
+ return te.iface |
|
| 471 |
+ } |
|
| 472 |
+ |
|
| 473 |
+ return nil |
|
| 474 |
+} |
|
| 475 |
+ |
|
| 476 |
+func (te *testEndpoint) SetGateway(gw net.IP) error {
|
|
| 477 |
+ te.gw = gw |
|
| 478 |
+ return nil |
|
| 479 |
+} |
|
| 480 |
+ |
|
| 481 |
+func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error {
|
|
| 482 |
+ te.gw6 = gw6 |
|
| 483 |
+ return nil |
|
| 484 |
+} |
|
| 485 |
+ |
|
| 486 |
+func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
|
|
| 487 |
+ te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop})
|
|
| 488 |
+ return nil |
|
| 489 |
+} |
|
| 490 |
+ |
|
| 491 |
+func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
|
|
| 492 |
+ return nil |
|
| 493 |
+} |
|
| 494 |
+ |
|
| 495 |
+func (te *testEndpoint) DisableGatewayService() {}
|
|
| 496 |
+ |
|
| 497 |
+func TestQueryEndpointInfo(t *testing.T) {
|
|
| 498 |
+ testQueryEndpointInfo(t, true) |
|
| 499 |
+} |
|
| 500 |
+ |
|
| 501 |
+func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
|
|
| 502 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 503 |
+ |
|
| 504 |
+ d := newDriver() |
|
| 505 |
+ |
|
| 506 |
+ config := &configuration{
|
|
| 507 |
+ EnableIPTables: true, |
|
| 508 |
+ EnableUserlandProxy: ulPxyEnabled, |
|
| 509 |
+ } |
|
| 510 |
+ genericOption := make(map[string]interface{})
|
|
| 511 |
+ genericOption[netlabel.GenericData] = config |
|
| 512 |
+ |
|
| 513 |
+ if err := d.configure(genericOption); err != nil {
|
|
| 514 |
+ t.Fatalf("Failed to setup driver config: %v", err)
|
|
| 515 |
+ } |
|
| 516 |
+ |
|
| 517 |
+ netconfig := &networkConfiguration{
|
|
| 518 |
+ BridgeName: DefaultBridgeName, |
|
| 519 |
+ EnableICC: false, |
|
| 520 |
+ } |
|
| 521 |
+ genericOption = make(map[string]interface{})
|
|
| 522 |
+ genericOption[netlabel.GenericData] = netconfig |
|
| 523 |
+ |
|
| 524 |
+ ipdList := getIPv4Data(t) |
|
| 525 |
+ err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
|
|
| 526 |
+ if err != nil {
|
|
| 527 |
+ t.Fatalf("Failed to create bridge: %v", err)
|
|
| 528 |
+ } |
|
| 529 |
+ |
|
| 530 |
+ sbOptions := make(map[string]interface{})
|
|
| 531 |
+ sbOptions[netlabel.PortMap] = getPortMapping() |
|
| 532 |
+ |
|
| 533 |
+ te := newTestEndpoint(ipdList[0].Pool, 11) |
|
| 534 |
+ err = d.CreateEndpoint("net1", "ep1", te.Interface(), nil)
|
|
| 535 |
+ if err != nil {
|
|
| 536 |
+ t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
|
| 537 |
+ } |
|
| 538 |
+ |
|
| 539 |
+ err = d.Join("net1", "ep1", "sbox", te, sbOptions)
|
|
| 540 |
+ if err != nil {
|
|
| 541 |
+ t.Fatalf("Failed to join the endpoint: %v", err)
|
|
| 542 |
+ } |
|
| 543 |
+ |
|
| 544 |
+ err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions)
|
|
| 545 |
+ if err != nil {
|
|
| 546 |
+ t.Fatalf("Failed to program external connectivity: %v", err)
|
|
| 547 |
+ } |
|
| 548 |
+ |
|
| 549 |
+ network, ok := d.networks["net1"] |
|
| 550 |
+ if !ok {
|
|
| 551 |
+ t.Fatalf("Cannot find network %s inside driver", "net1")
|
|
| 552 |
+ } |
|
| 553 |
+ ep, _ := network.endpoints["ep1"] |
|
| 554 |
+ data, err := d.EndpointOperInfo(network.id, ep.id) |
|
| 555 |
+ if err != nil {
|
|
| 556 |
+ t.Fatalf("Failed to ask for endpoint operational data: %v", err)
|
|
| 557 |
+ } |
|
| 558 |
+ pmd, ok := data[netlabel.PortMap] |
|
| 559 |
+ if !ok {
|
|
| 560 |
+ t.Fatalf("Endpoint operational data does not contain port mapping data")
|
|
| 561 |
+ } |
|
| 562 |
+ pm, ok := pmd.([]types.PortBinding) |
|
| 563 |
+ if !ok {
|
|
| 564 |
+ t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
|
| 565 |
+ } |
|
| 566 |
+ if len(ep.portMapping) != len(pm) {
|
|
| 567 |
+ t.Fatalf("Incomplete data for port mapping in endpoint operational data")
|
|
| 568 |
+ } |
|
| 569 |
+ for i, pb := range ep.portMapping {
|
|
| 570 |
+ if !pb.Equal(&pm[i]) {
|
|
| 571 |
+ t.Fatalf("Unexpected data for port mapping in endpoint operational data")
|
|
| 572 |
+ } |
|
| 573 |
+ } |
|
| 574 |
+ |
|
| 575 |
+ err = d.RevokeExternalConnectivity("net1", "ep1")
|
|
| 576 |
+ if err != nil {
|
|
| 577 |
+ t.Fatal(err) |
|
| 578 |
+ } |
|
| 579 |
+ |
|
| 580 |
+ // release host mapped ports |
|
| 581 |
+ err = d.Leave("net1", "ep1")
|
|
| 582 |
+ if err != nil {
|
|
| 583 |
+ t.Fatal(err) |
|
| 584 |
+ } |
|
| 585 |
+} |
|
| 586 |
+ |
|
| 587 |
+func getExposedPorts() []types.TransportPort {
|
|
| 588 |
+ return []types.TransportPort{
|
|
| 589 |
+ {Proto: types.TCP, Port: uint16(5000)},
|
|
| 590 |
+ {Proto: types.UDP, Port: uint16(400)},
|
|
| 591 |
+ {Proto: types.TCP, Port: uint16(600)},
|
|
| 592 |
+ } |
|
| 593 |
+} |
|
| 594 |
+ |
|
| 595 |
+func getPortMapping() []types.PortBinding {
|
|
| 596 |
+ return []types.PortBinding{
|
|
| 597 |
+ {Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
|
| 598 |
+ {Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
|
| 599 |
+ {Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
|
| 600 |
+ } |
|
| 601 |
+} |
|
| 602 |
+ |
|
| 603 |
+func TestValidateConfig(t *testing.T) {
|
|
| 604 |
+ if !testutils.IsRunningInContainer() {
|
|
| 605 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 606 |
+ } |
|
| 607 |
+ |
|
| 608 |
+ // Test mtu |
|
| 609 |
+ c := networkConfiguration{Mtu: -2}
|
|
| 610 |
+ err := c.Validate() |
|
| 611 |
+ if err == nil {
|
|
| 612 |
+ t.Fatalf("Failed to detect invalid MTU number")
|
|
| 613 |
+ } |
|
| 614 |
+ |
|
| 615 |
+ c.Mtu = 9000 |
|
| 616 |
+ err = c.Validate() |
|
| 617 |
+ if err != nil {
|
|
| 618 |
+ t.Fatalf("unexpected validation error on MTU number")
|
|
| 619 |
+ } |
|
| 620 |
+ |
|
| 621 |
+ // Bridge network |
|
| 622 |
+ _, network, _ := net.ParseCIDR("172.28.0.0/16")
|
|
| 623 |
+ c = networkConfiguration{
|
|
| 624 |
+ AddressIPv4: network, |
|
| 625 |
+ } |
|
| 626 |
+ |
|
| 627 |
+ err = c.Validate() |
|
| 628 |
+ if err != nil {
|
|
| 629 |
+ t.Fatal(err) |
|
| 630 |
+ } |
|
| 631 |
+ |
|
| 632 |
+ // Test v4 gw |
|
| 633 |
+ c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
|
|
| 634 |
+ err = c.Validate() |
|
| 635 |
+ if err == nil {
|
|
| 636 |
+ t.Fatalf("Failed to detect invalid default gateway")
|
|
| 637 |
+ } |
|
| 638 |
+ |
|
| 639 |
+ c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234")
|
|
| 640 |
+ err = c.Validate() |
|
| 641 |
+ if err != nil {
|
|
| 642 |
+ t.Fatalf("Unexpected validation error on default gateway")
|
|
| 643 |
+ } |
|
| 644 |
+ |
|
| 645 |
+ // Test v6 gw |
|
| 646 |
+ _, v6nw, _ := net.ParseCIDR("2001:db8:ae:b004::/64")
|
|
| 647 |
+ c = networkConfiguration{
|
|
| 648 |
+ EnableIPv6: true, |
|
| 649 |
+ AddressIPv6: v6nw, |
|
| 650 |
+ DefaultGatewayIPv6: net.ParseIP("2001:db8:ac:b004::bad:a55"),
|
|
| 651 |
+ } |
|
| 652 |
+ err = c.Validate() |
|
| 653 |
+ if err == nil {
|
|
| 654 |
+ t.Fatalf("Failed to detect invalid v6 default gateway")
|
|
| 655 |
+ } |
|
| 656 |
+ |
|
| 657 |
+ c.DefaultGatewayIPv6 = net.ParseIP("2001:db8:ae:b004::bad:a55")
|
|
| 658 |
+ err = c.Validate() |
|
| 659 |
+ if err != nil {
|
|
| 660 |
+ t.Fatalf("Unexpected validation error on v6 default gateway")
|
|
| 661 |
+ } |
|
| 662 |
+ |
|
| 663 |
+ c.AddressIPv6 = nil |
|
| 664 |
+ err = c.Validate() |
|
| 665 |
+ if err == nil {
|
|
| 666 |
+ t.Fatalf("Failed to detect invalid v6 default gateway")
|
|
| 667 |
+ } |
|
| 668 |
+ |
|
| 669 |
+ c.AddressIPv6 = nil |
|
| 670 |
+ err = c.Validate() |
|
| 671 |
+ if err == nil {
|
|
| 672 |
+ t.Fatalf("Failed to detect invalid v6 default gateway")
|
|
| 673 |
+ } |
|
| 674 |
+} |
| 0 | 675 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,119 @@ |
| 0 |
+package bridge |
|
| 1 |
+ |
|
| 2 |
+import "fmt" |
|
| 3 |
+ |
|
| 4 |
+// ErrInvalidEndpointConfig error is returned when an endpoint create is attempted with an invalid endpoint configuration. |
|
| 5 |
+type ErrInvalidEndpointConfig struct{}
|
|
| 6 |
+ |
|
| 7 |
+func (eiec *ErrInvalidEndpointConfig) Error() string {
|
|
| 8 |
+ return "trying to create an endpoint with an invalid endpoint configuration" |
|
| 9 |
+} |
|
| 10 |
+ |
|
| 11 |
+// BadRequest denotes the type of this error |
|
| 12 |
+func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
|
|
| 13 |
+ |
|
| 14 |
+// ErrNoIPAddr error is returned when bridge has no IPv4 address configured. |
|
| 15 |
+type ErrNoIPAddr struct{}
|
|
| 16 |
+ |
|
| 17 |
+func (enip *ErrNoIPAddr) Error() string {
|
|
| 18 |
+ return "bridge has no IPv4 address configured" |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+// InternalError denotes the type of this error |
|
| 22 |
+func (enip *ErrNoIPAddr) InternalError() {}
|
|
| 23 |
+ |
|
| 24 |
+// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid. |
|
| 25 |
+type ErrInvalidGateway struct{}
|
|
| 26 |
+ |
|
| 27 |
+func (eig *ErrInvalidGateway) Error() string {
|
|
| 28 |
+ return "default gateway ip must be part of the network" |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+// BadRequest denotes the type of this error |
|
| 32 |
+func (eig *ErrInvalidGateway) BadRequest() {}
|
|
| 33 |
+ |
|
| 34 |
+// ErrInvalidMtu is returned when the user provided MTU is not valid. |
|
| 35 |
+type ErrInvalidMtu int |
|
| 36 |
+ |
|
| 37 |
+func (eim ErrInvalidMtu) Error() string {
|
|
| 38 |
+ return fmt.Sprintf("invalid MTU number: %d", int(eim))
|
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+// BadRequest denotes the type of this error |
|
| 42 |
+func (eim ErrInvalidMtu) BadRequest() {}
|
|
| 43 |
+ |
|
| 44 |
+// ErrUnsupportedAddressType is returned when the specified address type is not supported. |
|
| 45 |
+type ErrUnsupportedAddressType string |
|
| 46 |
+ |
|
| 47 |
+func (uat ErrUnsupportedAddressType) Error() string {
|
|
| 48 |
+ return fmt.Sprintf("unsupported address type: %s", string(uat))
|
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+// BadRequest denotes the type of this error |
|
| 52 |
+func (uat ErrUnsupportedAddressType) BadRequest() {}
|
|
| 53 |
+ |
|
| 54 |
+// ActiveEndpointsError is returned when there are |
|
| 55 |
+// still active endpoints in the network being deleted. |
|
| 56 |
+type ActiveEndpointsError string |
|
| 57 |
+ |
|
| 58 |
+func (aee ActiveEndpointsError) Error() string {
|
|
| 59 |
+ return fmt.Sprintf("network %s has active endpoint", string(aee))
|
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+// Forbidden denotes the type of this error |
|
| 63 |
+func (aee ActiveEndpointsError) Forbidden() {}
|
|
| 64 |
+ |
|
| 65 |
+// InvalidNetworkIDError is returned when the passed |
|
| 66 |
+// network id for an existing network is not a known id. |
|
| 67 |
+type InvalidNetworkIDError string |
|
| 68 |
+ |
|
| 69 |
+func (inie InvalidNetworkIDError) Error() string {
|
|
| 70 |
+ return fmt.Sprintf("invalid network id %s", string(inie))
|
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+// NotFound denotes the type of this error |
|
| 74 |
+func (inie InvalidNetworkIDError) NotFound() {}
|
|
| 75 |
+ |
|
| 76 |
+// InvalidEndpointIDError is returned when the passed |
|
| 77 |
+// endpoint id is not valid. |
|
| 78 |
+type InvalidEndpointIDError string |
|
| 79 |
+ |
|
| 80 |
+func (ieie InvalidEndpointIDError) Error() string {
|
|
| 81 |
+ return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
|
|
| 82 |
+} |
|
| 83 |
+ |
|
| 84 |
+// BadRequest denotes the type of this error |
|
| 85 |
+func (ieie InvalidEndpointIDError) BadRequest() {}
|
|
| 86 |
+ |
|
| 87 |
+// EndpointNotFoundError is returned when the no endpoint |
|
| 88 |
+// with the passed endpoint id is found. |
|
| 89 |
+type EndpointNotFoundError string |
|
| 90 |
+ |
|
| 91 |
+func (enfe EndpointNotFoundError) Error() string {
|
|
| 92 |
+ return fmt.Sprintf("endpoint not found: %s", string(enfe))
|
|
| 93 |
+} |
|
| 94 |
+ |
|
| 95 |
+// NotFound denotes the type of this error |
|
| 96 |
+func (enfe EndpointNotFoundError) NotFound() {}
|
|
| 97 |
+ |
|
| 98 |
+// NonDefaultBridgeExistError is returned when a non-default |
|
| 99 |
+// bridge config is passed but it does not already exist. |
|
| 100 |
+type NonDefaultBridgeExistError string |
|
| 101 |
+ |
|
| 102 |
+func (ndbee NonDefaultBridgeExistError) Error() string {
|
|
| 103 |
+ return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
|
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+// Forbidden denotes the type of this error |
|
| 107 |
+func (ndbee NonDefaultBridgeExistError) Forbidden() {}
|
|
| 108 |
+ |
|
| 109 |
+// NonDefaultBridgeNeedsIPError is returned when a non-default |
|
| 110 |
+// bridge config is passed but it has no ip configured |
|
| 111 |
+type NonDefaultBridgeNeedsIPError string |
|
| 112 |
+ |
|
| 113 |
+func (ndbee NonDefaultBridgeNeedsIPError) Error() string {
|
|
| 114 |
+ return fmt.Sprintf("bridge device with non default name %s must have a valid IP address", string(ndbee))
|
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+// Forbidden denotes the type of this error |
|
| 118 |
+func (ndbee NonDefaultBridgeNeedsIPError) Forbidden() {}
|
| 0 | 119 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,225 @@ |
| 0 |
+// +build solaris |
|
| 1 |
+ |
|
| 2 |
+package bridge |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "bytes" |
|
| 6 |
+ "errors" |
|
| 7 |
+ "fmt" |
|
| 8 |
+ "net" |
|
| 9 |
+ "os" |
|
| 10 |
+ "os/exec" |
|
| 11 |
+ |
|
| 12 |
+ "github.com/Sirupsen/logrus" |
|
| 13 |
+ "github.com/docker/libnetwork/types" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+var ( |
|
| 17 |
+ defaultBindingIP = net.IPv4(0, 0, 0, 0) |
|
| 18 |
+) |
|
| 19 |
+ |
|
| 20 |
+const ( |
|
| 21 |
+ maxAllocatePortAttempts = 10 |
|
| 22 |
+) |
|
| 23 |
+ |
|
| 24 |
+func addPFRules(epid, bindIntf string, bs []types.PortBinding) {
|
|
| 25 |
+ var id string |
|
| 26 |
+ |
|
| 27 |
+ if len(epid) > 12 {
|
|
| 28 |
+ id = epid[:12] |
|
| 29 |
+ } else {
|
|
| 30 |
+ id = epid |
|
| 31 |
+ } |
|
| 32 |
+ |
|
| 33 |
+ fname := "/var/lib/docker/network/files/pf." + id |
|
| 34 |
+ |
|
| 35 |
+ f, err := os.OpenFile(fname, |
|
| 36 |
+ os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) |
|
| 37 |
+ if err != nil {
|
|
| 38 |
+ logrus.Warnf("cannot open temp pf file")
|
|
| 39 |
+ return |
|
| 40 |
+ } |
|
| 41 |
+ for _, b := range bs {
|
|
| 42 |
+ r := fmt.Sprintf( |
|
| 43 |
+ "pass in on %s proto %s from any to (%s) "+ |
|
| 44 |
+ "port %d rdr-to %s port %d\n", bindIntf, |
|
| 45 |
+ b.Proto.String(), bindIntf, b.HostPort, |
|
| 46 |
+ b.IP.String(), b.Port) |
|
| 47 |
+ _, err = f.WriteString(r) |
|
| 48 |
+ if err != nil {
|
|
| 49 |
+ logrus.Warnf("cannot write firewall rules to %s: %v", fname, err)
|
|
| 50 |
+ } |
|
| 51 |
+ } |
|
| 52 |
+ f.Close() |
|
| 53 |
+ |
|
| 54 |
+ anchor := fmt.Sprintf("_auto/docker/ep%s", id)
|
|
| 55 |
+ err = exec.Command("/usr/sbin/pfctl", "-a", anchor, "-f", fname).Run()
|
|
| 56 |
+ if err != nil {
|
|
| 57 |
+ logrus.Warnf("failed to add firewall rules: %v", err)
|
|
| 58 |
+ } |
|
| 59 |
+ os.Remove(fname) |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+func removePFRules(epid string) {
|
|
| 63 |
+ var id string |
|
| 64 |
+ |
|
| 65 |
+ if len(epid) > 12 {
|
|
| 66 |
+ id = epid[:12] |
|
| 67 |
+ } else {
|
|
| 68 |
+ id = epid |
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ anchor := fmt.Sprintf("_auto/docker/ep%s", id)
|
|
| 72 |
+ err := exec.Command("/usr/sbin/pfctl", "-a", anchor, "-F", "all").Run()
|
|
| 73 |
+ if err != nil {
|
|
| 74 |
+ logrus.Warnf("failed to remove firewall rules: %v", err)
|
|
| 75 |
+ } |
|
| 76 |
+} |
|
| 77 |
+ |
|
| 78 |
+func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, bindIntf string, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
|
| 79 |
+ if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
|
|
| 80 |
+ return nil, nil |
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ defHostIP := defaultBindingIP |
|
| 84 |
+ if reqDefBindIP != nil {
|
|
| 85 |
+ defHostIP = reqDefBindIP |
|
| 86 |
+ } |
|
| 87 |
+ |
|
| 88 |
+ bs, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, bindIntf, ep.addr.IP, defHostIP, ulPxyEnabled) |
|
| 89 |
+ if err != nil {
|
|
| 90 |
+ return nil, err |
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 93 |
+ // Add PF rules for port bindings, if any |
|
| 94 |
+ if len(bs) > 0 {
|
|
| 95 |
+ addPFRules(ep.id, bindIntf, bs) |
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 98 |
+ return bs, err |
|
| 99 |
+} |
|
| 100 |
+ |
|
| 101 |
+func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, bindIntf string, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
|
| 102 |
+ bs := make([]types.PortBinding, 0, len(bindings)) |
|
| 103 |
+ for _, c := range bindings {
|
|
| 104 |
+ b := c.GetCopy() |
|
| 105 |
+ if err := n.allocatePort(&b, containerIP, defHostIP); err != nil {
|
|
| 106 |
+ // On allocation failure,release previously |
|
| 107 |
+ // allocated ports. On cleanup error, just log |
|
| 108 |
+ // a warning message |
|
| 109 |
+ if cuErr := n.releasePortsInternal(bs); cuErr != nil {
|
|
| 110 |
+ logrus.Warnf("Upon allocation failure "+
|
|
| 111 |
+ "for %v, failed to clear previously "+ |
|
| 112 |
+ "allocated port bindings: %v", b, cuErr) |
|
| 113 |
+ } |
|
| 114 |
+ return nil, err |
|
| 115 |
+ } |
|
| 116 |
+ bs = append(bs, b) |
|
| 117 |
+ } |
|
| 118 |
+ return bs, nil |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP) error {
|
|
| 122 |
+ var ( |
|
| 123 |
+ host net.Addr |
|
| 124 |
+ err error |
|
| 125 |
+ ) |
|
| 126 |
+ |
|
| 127 |
+ // Store the container interface address in the operational binding |
|
| 128 |
+ bnd.IP = containerIP |
|
| 129 |
+ |
|
| 130 |
+ // Adjust the host address in the operational binding |
|
| 131 |
+ if len(bnd.HostIP) == 0 {
|
|
| 132 |
+ bnd.HostIP = defHostIP |
|
| 133 |
+ } |
|
| 134 |
+ |
|
| 135 |
+ // Adjust HostPortEnd if this is not a range. |
|
| 136 |
+ if bnd.HostPortEnd == 0 {
|
|
| 137 |
+ bnd.HostPortEnd = bnd.HostPort |
|
| 138 |
+ } |
|
| 139 |
+ |
|
| 140 |
+ // Construct the container side transport address |
|
| 141 |
+ container, err := bnd.ContainerAddr() |
|
| 142 |
+ if err != nil {
|
|
| 143 |
+ return err |
|
| 144 |
+ } |
|
| 145 |
+ |
|
| 146 |
+ // Try up to maxAllocatePortAttempts times to get a port that's |
|
| 147 |
+ // not already allocated. |
|
| 148 |
+ for i := 0; i < maxAllocatePortAttempts; i++ {
|
|
| 149 |
+ if host, err = n.portMapper.MapRange(container, bnd.HostIP, |
|
| 150 |
+ int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil {
|
|
| 151 |
+ break |
|
| 152 |
+ } |
|
| 153 |
+ // There is no point in immediately retrying to map an |
|
| 154 |
+ // explicitly chosen port. |
|
| 155 |
+ if bnd.HostPort != 0 {
|
|
| 156 |
+ logrus.Warnf( |
|
| 157 |
+ "Failed to allocate and map port %d-%d: %s", |
|
| 158 |
+ bnd.HostPort, bnd.HostPortEnd, err) |
|
| 159 |
+ break |
|
| 160 |
+ } |
|
| 161 |
+ logrus.Warnf("Failed to allocate and map port: %s, retry: %d",
|
|
| 162 |
+ err, i+1) |
|
| 163 |
+ } |
|
| 164 |
+ if err != nil {
|
|
| 165 |
+ return err |
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 168 |
+ // Save the host port (regardless it was or not specified in the |
|
| 169 |
+ // binding) |
|
| 170 |
+ switch netAddr := host.(type) {
|
|
| 171 |
+ case *net.TCPAddr: |
|
| 172 |
+ bnd.HostPort = uint16(host.(*net.TCPAddr).Port) |
|
| 173 |
+ return nil |
|
| 174 |
+ case *net.UDPAddr: |
|
| 175 |
+ bnd.HostPort = uint16(host.(*net.UDPAddr).Port) |
|
| 176 |
+ return nil |
|
| 177 |
+ default: |
|
| 178 |
+ // For completeness |
|
| 179 |
+ return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
|
|
| 180 |
+ } |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
|
|
| 184 |
+ err := n.releasePortsInternal(ep.portMapping) |
|
| 185 |
+ if err != nil {
|
|
| 186 |
+ return nil |
|
| 187 |
+ } |
|
| 188 |
+ |
|
| 189 |
+ // remove rules if there are any port mappings |
|
| 190 |
+ if len(ep.portMapping) > 0 {
|
|
| 191 |
+ removePFRules(ep.id) |
|
| 192 |
+ } |
|
| 193 |
+ |
|
| 194 |
+ return nil |
|
| 195 |
+ |
|
| 196 |
+} |
|
| 197 |
+ |
|
| 198 |
+func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
|
|
| 199 |
+ var errorBuf bytes.Buffer |
|
| 200 |
+ |
|
| 201 |
+ // Attempt to release all port bindings, do not stop on failure |
|
| 202 |
+ for _, m := range bindings {
|
|
| 203 |
+ if err := n.releasePort(m); err != nil {
|
|
| 204 |
+ errorBuf.WriteString( |
|
| 205 |
+ fmt.Sprintf( |
|
| 206 |
+ "\ncould not release %v because of %v", |
|
| 207 |
+ m, err)) |
|
| 208 |
+ } |
|
| 209 |
+ } |
|
| 210 |
+ |
|
| 211 |
+ if errorBuf.Len() != 0 {
|
|
| 212 |
+ return errors.New(errorBuf.String()) |
|
| 213 |
+ } |
|
| 214 |
+ return nil |
|
| 215 |
+} |
|
| 216 |
+ |
|
| 217 |
+func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
|
|
| 218 |
+ // Construct the host side transport address |
|
| 219 |
+ host, err := bnd.HostAddr() |
|
| 220 |
+ if err != nil {
|
|
| 221 |
+ return err |
|
| 222 |
+ } |
|
| 223 |
+ return n.portMapper.Unmap(host) |
|
| 224 |
+} |
| ... | ... |
@@ -1,5 +1,13 @@ |
| 1 | 1 |
package libnetwork |
| 2 | 2 |
|
| 3 |
+import ( |
|
| 4 |
+ "github.com/docker/libnetwork/drivers/null" |
|
| 5 |
+ "github.com/docker/libnetwork/drivers/solaris/bridge" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 3 | 8 |
func getInitializers() []initializer {
|
| 4 |
- return []initializer{}
|
|
| 9 |
+ return []initializer{
|
|
| 10 |
+ {bridge.Init, "bridge"},
|
|
| 11 |
+ {null.Init, "null"},
|
|
| 12 |
+ } |
|
| 5 | 13 |
} |
| 6 | 14 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,995 @@ |
| 0 |
+package libnetwork_test |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "encoding/json" |
|
| 5 |
+ "flag" |
|
| 6 |
+ "fmt" |
|
| 7 |
+ "io/ioutil" |
|
| 8 |
+ "net" |
|
| 9 |
+ "os" |
|
| 10 |
+ "os/exec" |
|
| 11 |
+ "runtime" |
|
| 12 |
+ "strconv" |
|
| 13 |
+ "strings" |
|
| 14 |
+ "testing" |
|
| 15 |
+ |
|
| 16 |
+ log "github.com/Sirupsen/logrus" |
|
| 17 |
+ "github.com/docker/docker/pkg/reexec" |
|
| 18 |
+ "github.com/docker/libnetwork" |
|
| 19 |
+ "github.com/docker/libnetwork/ipamapi" |
|
| 20 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 21 |
+ "github.com/docker/libnetwork/options" |
|
| 22 |
+ "github.com/docker/libnetwork/osl" |
|
| 23 |
+ "github.com/docker/libnetwork/testutils" |
|
| 24 |
+ "github.com/docker/libnetwork/types" |
|
| 25 |
+ "github.com/opencontainers/runc/libcontainer" |
|
| 26 |
+ "github.com/opencontainers/runc/libcontainer/configs" |
|
| 27 |
+ "github.com/vishvananda/netlink" |
|
| 28 |
+ "github.com/vishvananda/netns" |
|
| 29 |
+) |
|
| 30 |
+ |
|
| 31 |
+func TestHost(t *testing.T) {
|
|
| 32 |
+ sbx1, err := controller.NewSandbox("host_c1",
|
|
| 33 |
+ libnetwork.OptionHostname("test1"),
|
|
| 34 |
+ libnetwork.OptionDomainname("docker.io"),
|
|
| 35 |
+ libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
|
| 36 |
+ libnetwork.OptionUseDefaultSandbox()) |
|
| 37 |
+ if err != nil {
|
|
| 38 |
+ t.Fatal(err) |
|
| 39 |
+ } |
|
| 40 |
+ defer func() {
|
|
| 41 |
+ if err := sbx1.Delete(); err != nil {
|
|
| 42 |
+ t.Fatal(err) |
|
| 43 |
+ } |
|
| 44 |
+ }() |
|
| 45 |
+ |
|
| 46 |
+ sbx2, err := controller.NewSandbox("host_c2",
|
|
| 47 |
+ libnetwork.OptionHostname("test2"),
|
|
| 48 |
+ libnetwork.OptionDomainname("docker.io"),
|
|
| 49 |
+ libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
|
| 50 |
+ libnetwork.OptionUseDefaultSandbox()) |
|
| 51 |
+ if err != nil {
|
|
| 52 |
+ t.Fatal(err) |
|
| 53 |
+ } |
|
| 54 |
+ defer func() {
|
|
| 55 |
+ if err := sbx2.Delete(); err != nil {
|
|
| 56 |
+ t.Fatal(err) |
|
| 57 |
+ } |
|
| 58 |
+ }() |
|
| 59 |
+ |
|
| 60 |
+ network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil)
|
|
| 61 |
+ if err != nil {
|
|
| 62 |
+ t.Fatal(err) |
|
| 63 |
+ } |
|
| 64 |
+ |
|
| 65 |
+ ep1, err := network.CreateEndpoint("testep1")
|
|
| 66 |
+ if err != nil {
|
|
| 67 |
+ t.Fatal(err) |
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 70 |
+ if err := ep1.Join(sbx1); err != nil {
|
|
| 71 |
+ t.Fatal(err) |
|
| 72 |
+ } |
|
| 73 |
+ |
|
| 74 |
+ ep2, err := network.CreateEndpoint("testep2")
|
|
| 75 |
+ if err != nil {
|
|
| 76 |
+ t.Fatal(err) |
|
| 77 |
+ } |
|
| 78 |
+ |
|
| 79 |
+ if err := ep2.Join(sbx2); err != nil {
|
|
| 80 |
+ t.Fatal(err) |
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ if err := ep1.Leave(sbx1); err != nil {
|
|
| 84 |
+ t.Fatal(err) |
|
| 85 |
+ } |
|
| 86 |
+ |
|
| 87 |
+ if err := ep2.Leave(sbx2); err != nil {
|
|
| 88 |
+ t.Fatal(err) |
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ if err := ep1.Delete(false); err != nil {
|
|
| 92 |
+ t.Fatal(err) |
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ if err := ep2.Delete(false); err != nil {
|
|
| 96 |
+ t.Fatal(err) |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ // Try to create another host endpoint and join/leave that. |
|
| 100 |
+ cnt3, err := controller.NewSandbox("host_c3",
|
|
| 101 |
+ libnetwork.OptionHostname("test3"),
|
|
| 102 |
+ libnetwork.OptionDomainname("docker.io"),
|
|
| 103 |
+ libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
|
| 104 |
+ libnetwork.OptionUseDefaultSandbox()) |
|
| 105 |
+ if err != nil {
|
|
| 106 |
+ t.Fatal(err) |
|
| 107 |
+ } |
|
| 108 |
+ defer func() {
|
|
| 109 |
+ if err := cnt3.Delete(); err != nil {
|
|
| 110 |
+ t.Fatal(err) |
|
| 111 |
+ } |
|
| 112 |
+ }() |
|
| 113 |
+ |
|
| 114 |
+ ep3, err := network.CreateEndpoint("testep3")
|
|
| 115 |
+ if err != nil {
|
|
| 116 |
+ t.Fatal(err) |
|
| 117 |
+ } |
|
| 118 |
+ |
|
| 119 |
+ if err := ep3.Join(sbx2); err != nil {
|
|
| 120 |
+ t.Fatal(err) |
|
| 121 |
+ } |
|
| 122 |
+ |
|
| 123 |
+ if err := ep3.Leave(sbx2); err != nil {
|
|
| 124 |
+ t.Fatal(err) |
|
| 125 |
+ } |
|
| 126 |
+ |
|
| 127 |
+ if err := ep3.Delete(false); err != nil {
|
|
| 128 |
+ t.Fatal(err) |
|
| 129 |
+ } |
|
| 130 |
+} |
|
| 131 |
+ |
|
| 132 |
+// Testing IPV6 from MAC address |
|
| 133 |
+func TestBridgeIpv6FromMac(t *testing.T) {
|
|
| 134 |
+ if !testutils.IsRunningInContainer() {
|
|
| 135 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 136 |
+ } |
|
| 137 |
+ |
|
| 138 |
+ netOption := options.Generic{
|
|
| 139 |
+ netlabel.GenericData: options.Generic{
|
|
| 140 |
+ "BridgeName": "testipv6mac", |
|
| 141 |
+ "EnableICC": true, |
|
| 142 |
+ "EnableIPMasquerade": true, |
|
| 143 |
+ }, |
|
| 144 |
+ } |
|
| 145 |
+ ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}}
|
|
| 146 |
+ ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
|
|
| 147 |
+ |
|
| 148 |
+ network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "", |
|
| 149 |
+ libnetwork.NetworkOptionGeneric(netOption), |
|
| 150 |
+ libnetwork.NetworkOptionEnableIPv6(true), |
|
| 151 |
+ libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil), |
|
| 152 |
+ libnetwork.NetworkOptionDeferIPv6Alloc(true)) |
|
| 153 |
+ if err != nil {
|
|
| 154 |
+ t.Fatal(err) |
|
| 155 |
+ } |
|
| 156 |
+ |
|
| 157 |
+ mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
|
|
| 158 |
+ epOption := options.Generic{netlabel.MacAddress: mac}
|
|
| 159 |
+ |
|
| 160 |
+ ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption))
|
|
| 161 |
+ if err != nil {
|
|
| 162 |
+ t.Fatal(err) |
|
| 163 |
+ } |
|
| 164 |
+ |
|
| 165 |
+ iface := ep.Info().Iface() |
|
| 166 |
+ if !bytes.Equal(iface.MacAddress(), mac) {
|
|
| 167 |
+ t.Fatalf("Unexpected mac address: %v", iface.MacAddress())
|
|
| 168 |
+ } |
|
| 169 |
+ |
|
| 170 |
+ ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64")
|
|
| 171 |
+ expIP.IP = ip |
|
| 172 |
+ if !types.CompareIPNet(expIP, iface.AddressIPv6()) {
|
|
| 173 |
+ t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6())
|
|
| 174 |
+ } |
|
| 175 |
+ |
|
| 176 |
+ if err := ep.Delete(false); err != nil {
|
|
| 177 |
+ t.Fatal(err) |
|
| 178 |
+ } |
|
| 179 |
+ |
|
| 180 |
+ if err := network.Delete(); err != nil {
|
|
| 181 |
+ t.Fatal(err) |
|
| 182 |
+ } |
|
| 183 |
+} |
|
| 184 |
+ |
|
| 185 |
+func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
|
|
| 186 |
+ key := info.Sandbox().Key() |
|
| 187 |
+ sbNs, err := netns.GetFromPath(key) |
|
| 188 |
+ if err != nil {
|
|
| 189 |
+ t.Fatalf("Failed to get network namespace path %q: %v", key, err)
|
|
| 190 |
+ } |
|
| 191 |
+ defer sbNs.Close() |
|
| 192 |
+ |
|
| 193 |
+ nh, err := netlink.NewHandleAt(sbNs) |
|
| 194 |
+ if err != nil {
|
|
| 195 |
+ t.Fatal(err) |
|
| 196 |
+ } |
|
| 197 |
+ |
|
| 198 |
+ _, err = nh.LinkByName("eth0")
|
|
| 199 |
+ if err != nil {
|
|
| 200 |
+ t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
|
|
| 201 |
+ } |
|
| 202 |
+ |
|
| 203 |
+ _, err = nh.LinkByName("eth1")
|
|
| 204 |
+ if err != nil {
|
|
| 205 |
+ t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err)
|
|
| 206 |
+ } |
|
| 207 |
+} |
|
| 208 |
+ |
|
| 209 |
+func TestEndpointJoin(t *testing.T) {
|
|
| 210 |
+ if !testutils.IsRunningInContainer() {
|
|
| 211 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 212 |
+ } |
|
| 213 |
+ |
|
| 214 |
+ // Create network 1 and add 2 endpoint: ep11, ep12 |
|
| 215 |
+ netOption := options.Generic{
|
|
| 216 |
+ netlabel.GenericData: options.Generic{
|
|
| 217 |
+ "BridgeName": "testnetwork1", |
|
| 218 |
+ "EnableICC": true, |
|
| 219 |
+ "EnableIPMasquerade": true, |
|
| 220 |
+ }, |
|
| 221 |
+ } |
|
| 222 |
+ ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
|
|
| 223 |
+ n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "", |
|
| 224 |
+ libnetwork.NetworkOptionGeneric(netOption), |
|
| 225 |
+ libnetwork.NetworkOptionEnableIPv6(true), |
|
| 226 |
+ libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil), |
|
| 227 |
+ libnetwork.NetworkOptionDeferIPv6Alloc(true)) |
|
| 228 |
+ if err != nil {
|
|
| 229 |
+ t.Fatal(err) |
|
| 230 |
+ } |
|
| 231 |
+ defer func() {
|
|
| 232 |
+ if err := n1.Delete(); err != nil {
|
|
| 233 |
+ t.Fatal(err) |
|
| 234 |
+ } |
|
| 235 |
+ }() |
|
| 236 |
+ |
|
| 237 |
+ ep1, err := n1.CreateEndpoint("ep1")
|
|
| 238 |
+ if err != nil {
|
|
| 239 |
+ t.Fatal(err) |
|
| 240 |
+ } |
|
| 241 |
+ defer func() {
|
|
| 242 |
+ if err := ep1.Delete(false); err != nil {
|
|
| 243 |
+ t.Fatal(err) |
|
| 244 |
+ } |
|
| 245 |
+ }() |
|
| 246 |
+ |
|
| 247 |
+ // Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint() |
|
| 248 |
+ info := ep1.Info() |
|
| 249 |
+ iface := info.Iface() |
|
| 250 |
+ if iface.Address() != nil && iface.Address().IP.To4() == nil {
|
|
| 251 |
+ t.Fatalf("Invalid IP address returned: %v", iface.Address())
|
|
| 252 |
+ } |
|
| 253 |
+ if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil {
|
|
| 254 |
+ t.Fatalf("Invalid IPv6 address returned: %v", iface.Address())
|
|
| 255 |
+ } |
|
| 256 |
+ |
|
| 257 |
+ if len(info.Gateway()) != 0 {
|
|
| 258 |
+ t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway())
|
|
| 259 |
+ } |
|
| 260 |
+ if len(info.GatewayIPv6()) != 0 {
|
|
| 261 |
+ t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6())
|
|
| 262 |
+ } |
|
| 263 |
+ |
|
| 264 |
+ if info.Sandbox() != nil {
|
|
| 265 |
+ t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key())
|
|
| 266 |
+ } |
|
| 267 |
+ |
|
| 268 |
+ // test invalid joins |
|
| 269 |
+ err = ep1.Join(nil) |
|
| 270 |
+ if err == nil {
|
|
| 271 |
+ t.Fatalf("Expected to fail join with nil Sandbox")
|
|
| 272 |
+ } |
|
| 273 |
+ if _, ok := err.(types.BadRequestError); !ok {
|
|
| 274 |
+ t.Fatalf("Unexpected error type returned: %T", err)
|
|
| 275 |
+ } |
|
| 276 |
+ |
|
| 277 |
+ fsbx := &fakeSandbox{}
|
|
| 278 |
+ if err = ep1.Join(fsbx); err == nil {
|
|
| 279 |
+ t.Fatalf("Expected to fail join with invalid Sandbox")
|
|
| 280 |
+ } |
|
| 281 |
+ if _, ok := err.(types.BadRequestError); !ok {
|
|
| 282 |
+ t.Fatalf("Unexpected error type returned: %T", err)
|
|
| 283 |
+ } |
|
| 284 |
+ |
|
| 285 |
+ sb, err := controller.NewSandbox(containerID, |
|
| 286 |
+ libnetwork.OptionHostname("test"),
|
|
| 287 |
+ libnetwork.OptionDomainname("docker.io"),
|
|
| 288 |
+ libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
|
| 289 |
+ if err != nil {
|
|
| 290 |
+ t.Fatal(err) |
|
| 291 |
+ } |
|
| 292 |
+ |
|
| 293 |
+ defer func() {
|
|
| 294 |
+ if err := sb.Delete(); err != nil {
|
|
| 295 |
+ t.Fatal(err) |
|
| 296 |
+ } |
|
| 297 |
+ }() |
|
| 298 |
+ |
|
| 299 |
+ err = ep1.Join(sb) |
|
| 300 |
+ if err != nil {
|
|
| 301 |
+ t.Fatal(err) |
|
| 302 |
+ } |
|
| 303 |
+ defer func() {
|
|
| 304 |
+ err = ep1.Leave(sb) |
|
| 305 |
+ if err != nil {
|
|
| 306 |
+ t.Fatal(err) |
|
| 307 |
+ } |
|
| 308 |
+ }() |
|
| 309 |
+ |
|
| 310 |
+ // Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined. |
|
| 311 |
+ info = ep1.Info() |
|
| 312 |
+ if len(info.Gateway()) == 0 {
|
|
| 313 |
+ t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway())
|
|
| 314 |
+ } |
|
| 315 |
+ if len(info.GatewayIPv6()) == 0 {
|
|
| 316 |
+ t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6())
|
|
| 317 |
+ } |
|
| 318 |
+ |
|
| 319 |
+ if info.Sandbox() == nil {
|
|
| 320 |
+ t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
|
|
| 321 |
+ } |
|
| 322 |
+ |
|
| 323 |
+ // Check endpoint provided container information |
|
| 324 |
+ if ep1.Info().Sandbox().Key() != sb.Key() {
|
|
| 325 |
+ t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key())
|
|
| 326 |
+ } |
|
| 327 |
+ |
|
| 328 |
+ // Attempt retrieval of endpoint interfaces statistics |
|
| 329 |
+ stats, err := sb.Statistics() |
|
| 330 |
+ if err != nil {
|
|
| 331 |
+ t.Fatal(err) |
|
| 332 |
+ } |
|
| 333 |
+ if _, ok := stats["eth0"]; !ok {
|
|
| 334 |
+ t.Fatalf("Did not find eth0 statistics")
|
|
| 335 |
+ } |
|
| 336 |
+ |
|
| 337 |
+ // Now test the container joining another network |
|
| 338 |
+ n2, err := createTestNetwork(bridgeNetType, "testnetwork2", |
|
| 339 |
+ options.Generic{
|
|
| 340 |
+ netlabel.GenericData: options.Generic{
|
|
| 341 |
+ "BridgeName": "testnetwork2", |
|
| 342 |
+ }, |
|
| 343 |
+ }, nil, nil) |
|
| 344 |
+ if err != nil {
|
|
| 345 |
+ t.Fatal(err) |
|
| 346 |
+ } |
|
| 347 |
+ defer func() {
|
|
| 348 |
+ if err := n2.Delete(); err != nil {
|
|
| 349 |
+ t.Fatal(err) |
|
| 350 |
+ } |
|
| 351 |
+ }() |
|
| 352 |
+ |
|
| 353 |
+ ep2, err := n2.CreateEndpoint("ep2")
|
|
| 354 |
+ if err != nil {
|
|
| 355 |
+ t.Fatal(err) |
|
| 356 |
+ } |
|
| 357 |
+ defer func() {
|
|
| 358 |
+ if err := ep2.Delete(false); err != nil {
|
|
| 359 |
+ t.Fatal(err) |
|
| 360 |
+ } |
|
| 361 |
+ }() |
|
| 362 |
+ |
|
| 363 |
+ err = ep2.Join(sb) |
|
| 364 |
+ if err != nil {
|
|
| 365 |
+ t.Fatal(err) |
|
| 366 |
+ } |
|
| 367 |
+ defer func() {
|
|
| 368 |
+ err = ep2.Leave(sb) |
|
| 369 |
+ if err != nil {
|
|
| 370 |
+ t.Fatal(err) |
|
| 371 |
+ } |
|
| 372 |
+ }() |
|
| 373 |
+ |
|
| 374 |
+ if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
|
|
| 375 |
+ t.Fatalf("ep1 and ep2 returned different container sandbox key")
|
|
| 376 |
+ } |
|
| 377 |
+ |
|
| 378 |
+ checkSandbox(t, info) |
|
| 379 |
+} |
|
| 380 |
+ |
|
| 381 |
+func TestExternalKey(t *testing.T) {
|
|
| 382 |
+ externalKeyTest(t, false) |
|
| 383 |
+} |
|
| 384 |
+ |
|
| 385 |
+func externalKeyTest(t *testing.T, reexec bool) {
|
|
| 386 |
+ if !testutils.IsRunningInContainer() {
|
|
| 387 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 388 |
+ } |
|
| 389 |
+ |
|
| 390 |
+ n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
|
|
| 391 |
+ netlabel.GenericData: options.Generic{
|
|
| 392 |
+ "BridgeName": "testnetwork", |
|
| 393 |
+ }, |
|
| 394 |
+ }, nil, nil) |
|
| 395 |
+ if err != nil {
|
|
| 396 |
+ t.Fatal(err) |
|
| 397 |
+ } |
|
| 398 |
+ defer func() {
|
|
| 399 |
+ if err := n.Delete(); err != nil {
|
|
| 400 |
+ t.Fatal(err) |
|
| 401 |
+ } |
|
| 402 |
+ }() |
|
| 403 |
+ |
|
| 404 |
+ ep, err := n.CreateEndpoint("ep1")
|
|
| 405 |
+ if err != nil {
|
|
| 406 |
+ t.Fatal(err) |
|
| 407 |
+ } |
|
| 408 |
+ defer func() {
|
|
| 409 |
+ err = ep.Delete(false) |
|
| 410 |
+ if err != nil {
|
|
| 411 |
+ t.Fatal(err) |
|
| 412 |
+ } |
|
| 413 |
+ }() |
|
| 414 |
+ |
|
| 415 |
+ ep2, err := n.CreateEndpoint("ep2")
|
|
| 416 |
+ if err != nil {
|
|
| 417 |
+ t.Fatal(err) |
|
| 418 |
+ } |
|
| 419 |
+ defer func() {
|
|
| 420 |
+ err = ep2.Delete(false) |
|
| 421 |
+ if err != nil {
|
|
| 422 |
+ t.Fatal(err) |
|
| 423 |
+ } |
|
| 424 |
+ }() |
|
| 425 |
+ |
|
| 426 |
+ cnt, err := controller.NewSandbox(containerID, |
|
| 427 |
+ libnetwork.OptionHostname("test"),
|
|
| 428 |
+ libnetwork.OptionDomainname("docker.io"),
|
|
| 429 |
+ libnetwork.OptionUseExternalKey(), |
|
| 430 |
+ libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
|
| 431 |
+ defer func() {
|
|
| 432 |
+ if err := cnt.Delete(); err != nil {
|
|
| 433 |
+ t.Fatal(err) |
|
| 434 |
+ } |
|
| 435 |
+ osl.GC() |
|
| 436 |
+ }() |
|
| 437 |
+ |
|
| 438 |
+ // Join endpoint to sandbox before SetKey |
|
| 439 |
+ err = ep.Join(cnt) |
|
| 440 |
+ if err != nil {
|
|
| 441 |
+ t.Fatal(err) |
|
| 442 |
+ } |
|
| 443 |
+ defer func() {
|
|
| 444 |
+ err = ep.Leave(cnt) |
|
| 445 |
+ if err != nil {
|
|
| 446 |
+ t.Fatal(err) |
|
| 447 |
+ } |
|
| 448 |
+ }() |
|
| 449 |
+ |
|
| 450 |
+ sbox := ep.Info().Sandbox() |
|
| 451 |
+ if sbox == nil {
|
|
| 452 |
+ t.Fatalf("Expected to have a valid Sandbox")
|
|
| 453 |
+ } |
|
| 454 |
+ |
|
| 455 |
+ if reexec {
|
|
| 456 |
+ err := reexecSetKey("this-must-fail", containerID, controller.ID())
|
|
| 457 |
+ if err == nil {
|
|
| 458 |
+ t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created")
|
|
| 459 |
+ } |
|
| 460 |
+ } else {
|
|
| 461 |
+ // Setting an non-existing key (namespace) must fail |
|
| 462 |
+ if err := sbox.SetKey("this-must-fail"); err == nil {
|
|
| 463 |
+ t.Fatalf("Setkey must fail if the corresponding namespace is not created")
|
|
| 464 |
+ } |
|
| 465 |
+ } |
|
| 466 |
+ |
|
| 467 |
+ // Create a new OS sandbox using the osl API before using it in SetKey |
|
| 468 |
+ if extOsBox, err := osl.NewSandbox("ValidKey", true, false); err != nil {
|
|
| 469 |
+ t.Fatalf("Failed to create new osl sandbox")
|
|
| 470 |
+ } else {
|
|
| 471 |
+ defer func() {
|
|
| 472 |
+ if err := extOsBox.Destroy(); err != nil {
|
|
| 473 |
+ log.Warnf("Failed to remove os sandbox: %v", err)
|
|
| 474 |
+ } |
|
| 475 |
+ }() |
|
| 476 |
+ } |
|
| 477 |
+ |
|
| 478 |
+ if reexec {
|
|
| 479 |
+ err := reexecSetKey("ValidKey", containerID, controller.ID())
|
|
| 480 |
+ if err != nil {
|
|
| 481 |
+ t.Fatalf("SetExternalKey failed with %v", err)
|
|
| 482 |
+ } |
|
| 483 |
+ } else {
|
|
| 484 |
+ if err := sbox.SetKey("ValidKey"); err != nil {
|
|
| 485 |
+ t.Fatalf("Setkey failed with %v", err)
|
|
| 486 |
+ } |
|
| 487 |
+ } |
|
| 488 |
+ |
|
| 489 |
+ // Join endpoint to sandbox after SetKey |
|
| 490 |
+ err = ep2.Join(sbox) |
|
| 491 |
+ if err != nil {
|
|
| 492 |
+ t.Fatal(err) |
|
| 493 |
+ } |
|
| 494 |
+ defer func() {
|
|
| 495 |
+ err = ep2.Leave(sbox) |
|
| 496 |
+ if err != nil {
|
|
| 497 |
+ t.Fatal(err) |
|
| 498 |
+ } |
|
| 499 |
+ }() |
|
| 500 |
+ |
|
| 501 |
+ if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
|
|
| 502 |
+ t.Fatalf("ep1 and ep2 returned different container sandbox key")
|
|
| 503 |
+ } |
|
| 504 |
+ |
|
| 505 |
+ checkSandbox(t, ep.Info()) |
|
| 506 |
+} |
|
| 507 |
+ |
|
| 508 |
+func reexecSetKey(key string, containerID string, controllerID string) error {
|
|
| 509 |
+ var ( |
|
| 510 |
+ state libcontainer.State |
|
| 511 |
+ b []byte |
|
| 512 |
+ err error |
|
| 513 |
+ ) |
|
| 514 |
+ |
|
| 515 |
+ state.NamespacePaths = make(map[configs.NamespaceType]string) |
|
| 516 |
+ state.NamespacePaths[configs.NamespaceType("NEWNET")] = key
|
|
| 517 |
+ if b, err = json.Marshal(state); err != nil {
|
|
| 518 |
+ return err |
|
| 519 |
+ } |
|
| 520 |
+ cmd := &exec.Cmd{
|
|
| 521 |
+ Path: reexec.Self(), |
|
| 522 |
+ Args: append([]string{"libnetwork-setkey"}, containerID, controllerID),
|
|
| 523 |
+ Stdin: strings.NewReader(string(b)), |
|
| 524 |
+ Stdout: os.Stdout, |
|
| 525 |
+ Stderr: os.Stderr, |
|
| 526 |
+ } |
|
| 527 |
+ return cmd.Run() |
|
| 528 |
+} |
|
| 529 |
+ |
|
| 530 |
+func TestEnableIPv6(t *testing.T) {
|
|
| 531 |
+ if !testutils.IsRunningInContainer() {
|
|
| 532 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 533 |
+ } |
|
| 534 |
+ |
|
| 535 |
+ tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
|
| 536 |
+ expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n")
|
|
| 537 |
+ //take a copy of resolv.conf for restoring after test completes |
|
| 538 |
+ resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
| 539 |
+ if err != nil {
|
|
| 540 |
+ t.Fatal(err) |
|
| 541 |
+ } |
|
| 542 |
+ //cleanup |
|
| 543 |
+ defer func() {
|
|
| 544 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
|
| 545 |
+ t.Fatal(err) |
|
| 546 |
+ } |
|
| 547 |
+ }() |
|
| 548 |
+ |
|
| 549 |
+ netOption := options.Generic{
|
|
| 550 |
+ netlabel.EnableIPv6: true, |
|
| 551 |
+ netlabel.GenericData: options.Generic{
|
|
| 552 |
+ "BridgeName": "testnetwork", |
|
| 553 |
+ }, |
|
| 554 |
+ } |
|
| 555 |
+ ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe99::/64", Gateway: "fe99::9"}}
|
|
| 556 |
+ |
|
| 557 |
+ n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList)
|
|
| 558 |
+ if err != nil {
|
|
| 559 |
+ t.Fatal(err) |
|
| 560 |
+ } |
|
| 561 |
+ defer func() {
|
|
| 562 |
+ if err := n.Delete(); err != nil {
|
|
| 563 |
+ t.Fatal(err) |
|
| 564 |
+ } |
|
| 565 |
+ }() |
|
| 566 |
+ |
|
| 567 |
+ ep1, err := n.CreateEndpoint("ep1")
|
|
| 568 |
+ if err != nil {
|
|
| 569 |
+ t.Fatal(err) |
|
| 570 |
+ } |
|
| 571 |
+ |
|
| 572 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
|
|
| 573 |
+ t.Fatal(err) |
|
| 574 |
+ } |
|
| 575 |
+ |
|
| 576 |
+ resolvConfPath := "/tmp/libnetwork_test/resolv.conf" |
|
| 577 |
+ defer os.Remove(resolvConfPath) |
|
| 578 |
+ |
|
| 579 |
+ sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) |
|
| 580 |
+ if err != nil {
|
|
| 581 |
+ t.Fatal(err) |
|
| 582 |
+ } |
|
| 583 |
+ defer func() {
|
|
| 584 |
+ if err := sb.Delete(); err != nil {
|
|
| 585 |
+ t.Fatal(err) |
|
| 586 |
+ } |
|
| 587 |
+ }() |
|
| 588 |
+ |
|
| 589 |
+ err = ep1.Join(sb) |
|
| 590 |
+ if err != nil {
|
|
| 591 |
+ t.Fatal(err) |
|
| 592 |
+ } |
|
| 593 |
+ |
|
| 594 |
+ content, err := ioutil.ReadFile(resolvConfPath) |
|
| 595 |
+ if err != nil {
|
|
| 596 |
+ t.Fatal(err) |
|
| 597 |
+ } |
|
| 598 |
+ |
|
| 599 |
+ if !bytes.Equal(content, expectedResolvConf) {
|
|
| 600 |
+ t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf), string(content))
|
|
| 601 |
+ } |
|
| 602 |
+ |
|
| 603 |
+ if err != nil {
|
|
| 604 |
+ t.Fatal(err) |
|
| 605 |
+ } |
|
| 606 |
+} |
|
| 607 |
+ |
|
| 608 |
+func TestResolvConfHost(t *testing.T) {
|
|
| 609 |
+ if !testutils.IsRunningInContainer() {
|
|
| 610 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 611 |
+ } |
|
| 612 |
+ |
|
| 613 |
+ tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n")
|
|
| 614 |
+ |
|
| 615 |
+ //take a copy of resolv.conf for restoring after test completes |
|
| 616 |
+ resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
| 617 |
+ if err != nil {
|
|
| 618 |
+ t.Fatal(err) |
|
| 619 |
+ } |
|
| 620 |
+ //cleanup |
|
| 621 |
+ defer func() {
|
|
| 622 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
|
| 623 |
+ t.Fatal(err) |
|
| 624 |
+ } |
|
| 625 |
+ }() |
|
| 626 |
+ |
|
| 627 |
+ n, err := controller.NetworkByName("testhost")
|
|
| 628 |
+ if err != nil {
|
|
| 629 |
+ t.Fatal(err) |
|
| 630 |
+ } |
|
| 631 |
+ |
|
| 632 |
+ ep1, err := n.CreateEndpoint("ep1", libnetwork.CreateOptionDisableResolution())
|
|
| 633 |
+ if err != nil {
|
|
| 634 |
+ t.Fatal(err) |
|
| 635 |
+ } |
|
| 636 |
+ |
|
| 637 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
|
|
| 638 |
+ t.Fatal(err) |
|
| 639 |
+ } |
|
| 640 |
+ |
|
| 641 |
+ resolvConfPath := "/tmp/libnetwork_test/resolv.conf" |
|
| 642 |
+ defer os.Remove(resolvConfPath) |
|
| 643 |
+ |
|
| 644 |
+ sb, err := controller.NewSandbox(containerID, |
|
| 645 |
+ libnetwork.OptionResolvConfPath(resolvConfPath), |
|
| 646 |
+ libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
|
|
| 647 |
+ if err != nil {
|
|
| 648 |
+ t.Fatal(err) |
|
| 649 |
+ } |
|
| 650 |
+ defer func() {
|
|
| 651 |
+ if err := sb.Delete(); err != nil {
|
|
| 652 |
+ t.Fatal(err) |
|
| 653 |
+ } |
|
| 654 |
+ }() |
|
| 655 |
+ |
|
| 656 |
+ err = ep1.Join(sb) |
|
| 657 |
+ if err != nil {
|
|
| 658 |
+ t.Fatal(err) |
|
| 659 |
+ } |
|
| 660 |
+ defer func() {
|
|
| 661 |
+ err = ep1.Leave(sb) |
|
| 662 |
+ if err != nil {
|
|
| 663 |
+ t.Fatal(err) |
|
| 664 |
+ } |
|
| 665 |
+ }() |
|
| 666 |
+ |
|
| 667 |
+ finfo, err := os.Stat(resolvConfPath) |
|
| 668 |
+ if err != nil {
|
|
| 669 |
+ t.Fatal(err) |
|
| 670 |
+ } |
|
| 671 |
+ |
|
| 672 |
+ fmode := (os.FileMode)(0644) |
|
| 673 |
+ if finfo.Mode() != fmode {
|
|
| 674 |
+ t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
|
|
| 675 |
+ } |
|
| 676 |
+ |
|
| 677 |
+ content, err := ioutil.ReadFile(resolvConfPath) |
|
| 678 |
+ if err != nil {
|
|
| 679 |
+ t.Fatal(err) |
|
| 680 |
+ } |
|
| 681 |
+ |
|
| 682 |
+ if !bytes.Equal(content, tmpResolvConf) {
|
|
| 683 |
+ t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content))
|
|
| 684 |
+ } |
|
| 685 |
+} |
|
| 686 |
+ |
|
| 687 |
+func TestResolvConf(t *testing.T) {
|
|
| 688 |
+ if !testutils.IsRunningInContainer() {
|
|
| 689 |
+ defer testutils.SetupTestOSContext(t)() |
|
| 690 |
+ } |
|
| 691 |
+ |
|
| 692 |
+ tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
|
| 693 |
+ tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
|
| 694 |
+ expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n")
|
|
| 695 |
+ tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n")
|
|
| 696 |
+ |
|
| 697 |
+ //take a copy of resolv.conf for restoring after test completes |
|
| 698 |
+ resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
| 699 |
+ if err != nil {
|
|
| 700 |
+ t.Fatal(err) |
|
| 701 |
+ } |
|
| 702 |
+ //cleanup |
|
| 703 |
+ defer func() {
|
|
| 704 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
|
| 705 |
+ t.Fatal(err) |
|
| 706 |
+ } |
|
| 707 |
+ }() |
|
| 708 |
+ |
|
| 709 |
+ netOption := options.Generic{
|
|
| 710 |
+ netlabel.GenericData: options.Generic{
|
|
| 711 |
+ "BridgeName": "testnetwork", |
|
| 712 |
+ }, |
|
| 713 |
+ } |
|
| 714 |
+ n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil)
|
|
| 715 |
+ if err != nil {
|
|
| 716 |
+ t.Fatal(err) |
|
| 717 |
+ } |
|
| 718 |
+ defer func() {
|
|
| 719 |
+ if err := n.Delete(); err != nil {
|
|
| 720 |
+ t.Fatal(err) |
|
| 721 |
+ } |
|
| 722 |
+ }() |
|
| 723 |
+ |
|
| 724 |
+ ep, err := n.CreateEndpoint("ep")
|
|
| 725 |
+ if err != nil {
|
|
| 726 |
+ t.Fatal(err) |
|
| 727 |
+ } |
|
| 728 |
+ |
|
| 729 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil {
|
|
| 730 |
+ t.Fatal(err) |
|
| 731 |
+ } |
|
| 732 |
+ |
|
| 733 |
+ resolvConfPath := "/tmp/libnetwork_test/resolv.conf" |
|
| 734 |
+ defer os.Remove(resolvConfPath) |
|
| 735 |
+ |
|
| 736 |
+ sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) |
|
| 737 |
+ if err != nil {
|
|
| 738 |
+ t.Fatal(err) |
|
| 739 |
+ } |
|
| 740 |
+ defer func() {
|
|
| 741 |
+ if err := sb1.Delete(); err != nil {
|
|
| 742 |
+ t.Fatal(err) |
|
| 743 |
+ } |
|
| 744 |
+ }() |
|
| 745 |
+ |
|
| 746 |
+ err = ep.Join(sb1) |
|
| 747 |
+ if err != nil {
|
|
| 748 |
+ t.Fatal(err) |
|
| 749 |
+ } |
|
| 750 |
+ |
|
| 751 |
+ finfo, err := os.Stat(resolvConfPath) |
|
| 752 |
+ if err != nil {
|
|
| 753 |
+ t.Fatal(err) |
|
| 754 |
+ } |
|
| 755 |
+ |
|
| 756 |
+ fmode := (os.FileMode)(0644) |
|
| 757 |
+ if finfo.Mode() != fmode {
|
|
| 758 |
+ t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
|
|
| 759 |
+ } |
|
| 760 |
+ |
|
| 761 |
+ content, err := ioutil.ReadFile(resolvConfPath) |
|
| 762 |
+ if err != nil {
|
|
| 763 |
+ t.Fatal(err) |
|
| 764 |
+ } |
|
| 765 |
+ |
|
| 766 |
+ if !bytes.Equal(content, expectedResolvConf1) {
|
|
| 767 |
+ fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content)
|
|
| 768 |
+ t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
|
|
| 769 |
+ } |
|
| 770 |
+ |
|
| 771 |
+ err = ep.Leave(sb1) |
|
| 772 |
+ if err != nil {
|
|
| 773 |
+ t.Fatal(err) |
|
| 774 |
+ } |
|
| 775 |
+ |
|
| 776 |
+ if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil {
|
|
| 777 |
+ t.Fatal(err) |
|
| 778 |
+ } |
|
| 779 |
+ |
|
| 780 |
+ sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath)) |
|
| 781 |
+ if err != nil {
|
|
| 782 |
+ t.Fatal(err) |
|
| 783 |
+ } |
|
| 784 |
+ defer func() {
|
|
| 785 |
+ if err := sb2.Delete(); err != nil {
|
|
| 786 |
+ t.Fatal(err) |
|
| 787 |
+ } |
|
| 788 |
+ }() |
|
| 789 |
+ |
|
| 790 |
+ err = ep.Join(sb2) |
|
| 791 |
+ if err != nil {
|
|
| 792 |
+ t.Fatal(err) |
|
| 793 |
+ } |
|
| 794 |
+ |
|
| 795 |
+ content, err = ioutil.ReadFile(resolvConfPath) |
|
| 796 |
+ if err != nil {
|
|
| 797 |
+ t.Fatal(err) |
|
| 798 |
+ } |
|
| 799 |
+ |
|
| 800 |
+ if !bytes.Equal(content, expectedResolvConf1) {
|
|
| 801 |
+ t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
|
|
| 802 |
+ } |
|
| 803 |
+ |
|
| 804 |
+ if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil {
|
|
| 805 |
+ t.Fatal(err) |
|
| 806 |
+ } |
|
| 807 |
+ |
|
| 808 |
+ err = ep.Leave(sb2) |
|
| 809 |
+ if err != nil {
|
|
| 810 |
+ t.Fatal(err) |
|
| 811 |
+ } |
|
| 812 |
+ |
|
| 813 |
+ err = ep.Join(sb2) |
|
| 814 |
+ if err != nil {
|
|
| 815 |
+ t.Fatal(err) |
|
| 816 |
+ } |
|
| 817 |
+ |
|
| 818 |
+ content, err = ioutil.ReadFile(resolvConfPath) |
|
| 819 |
+ if err != nil {
|
|
| 820 |
+ t.Fatal(err) |
|
| 821 |
+ } |
|
| 822 |
+ |
|
| 823 |
+ if !bytes.Equal(content, tmpResolvConf3) {
|
|
| 824 |
+ t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content))
|
|
| 825 |
+ } |
|
| 826 |
+} |
|
| 827 |
+ |
|
| 828 |
+func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
|
| 829 |
+ debugf("J%d.", thrNumber)
|
|
| 830 |
+ var err error |
|
| 831 |
+ |
|
| 832 |
+ sb := sboxes[thrNumber-1] |
|
| 833 |
+ err = ep.Join(sb) |
|
| 834 |
+ |
|
| 835 |
+ runtime.LockOSThread() |
|
| 836 |
+ if err != nil {
|
|
| 837 |
+ if _, ok := err.(types.ForbiddenError); !ok {
|
|
| 838 |
+ t.Fatalf("thread %d: %v", thrNumber, err)
|
|
| 839 |
+ } |
|
| 840 |
+ debugf("JE%d(%v).", thrNumber, err)
|
|
| 841 |
+ } |
|
| 842 |
+ debugf("JD%d.", thrNumber)
|
|
| 843 |
+} |
|
| 844 |
+ |
|
| 845 |
+func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
|
| 846 |
+ debugf("L%d.", thrNumber)
|
|
| 847 |
+ var err error |
|
| 848 |
+ |
|
| 849 |
+ sb := sboxes[thrNumber-1] |
|
| 850 |
+ |
|
| 851 |
+ err = ep.Leave(sb) |
|
| 852 |
+ runtime.LockOSThread() |
|
| 853 |
+ if err != nil {
|
|
| 854 |
+ if _, ok := err.(types.ForbiddenError); !ok {
|
|
| 855 |
+ t.Fatalf("thread %d: %v", thrNumber, err)
|
|
| 856 |
+ } |
|
| 857 |
+ debugf("LE%d(%v).", thrNumber, err)
|
|
| 858 |
+ } |
|
| 859 |
+ debugf("LD%d.", thrNumber)
|
|
| 860 |
+} |
|
| 861 |
+ |
|
| 862 |
+func runParallelTests(t *testing.T, thrNumber int) {
|
|
| 863 |
+ var ( |
|
| 864 |
+ ep libnetwork.Endpoint |
|
| 865 |
+ sb libnetwork.Sandbox |
|
| 866 |
+ err error |
|
| 867 |
+ ) |
|
| 868 |
+ |
|
| 869 |
+ t.Parallel() |
|
| 870 |
+ |
|
| 871 |
+ pTest := flag.Lookup("test.parallel")
|
|
| 872 |
+ if pTest == nil {
|
|
| 873 |
+ t.Skip("Skipped because test.parallel flag not set;")
|
|
| 874 |
+ } |
|
| 875 |
+ numParallel, err := strconv.Atoi(pTest.Value.String()) |
|
| 876 |
+ if err != nil {
|
|
| 877 |
+ t.Fatal(err) |
|
| 878 |
+ } |
|
| 879 |
+ if numParallel < numThreads {
|
|
| 880 |
+ t.Skip("Skipped because t.parallel was less than ", numThreads)
|
|
| 881 |
+ } |
|
| 882 |
+ |
|
| 883 |
+ runtime.LockOSThread() |
|
| 884 |
+ defer runtime.UnlockOSThread() |
|
| 885 |
+ |
|
| 886 |
+ if thrNumber == first {
|
|
| 887 |
+ createGlobalInstance(t) |
|
| 888 |
+ } |
|
| 889 |
+ |
|
| 890 |
+ if thrNumber != first {
|
|
| 891 |
+ select {
|
|
| 892 |
+ case <-start: |
|
| 893 |
+ } |
|
| 894 |
+ |
|
| 895 |
+ thrdone := make(chan struct{})
|
|
| 896 |
+ done <- thrdone |
|
| 897 |
+ defer close(thrdone) |
|
| 898 |
+ |
|
| 899 |
+ if thrNumber == last {
|
|
| 900 |
+ defer close(done) |
|
| 901 |
+ } |
|
| 902 |
+ |
|
| 903 |
+ err = netns.Set(testns) |
|
| 904 |
+ if err != nil {
|
|
| 905 |
+ t.Fatal(err) |
|
| 906 |
+ } |
|
| 907 |
+ } |
|
| 908 |
+ defer netns.Set(origns) |
|
| 909 |
+ |
|
| 910 |
+ net1, err := controller.NetworkByName("testhost")
|
|
| 911 |
+ if err != nil {
|
|
| 912 |
+ t.Fatal(err) |
|
| 913 |
+ } |
|
| 914 |
+ if net1 == nil {
|
|
| 915 |
+ t.Fatal("Could not find testhost")
|
|
| 916 |
+ } |
|
| 917 |
+ |
|
| 918 |
+ net2, err := controller.NetworkByName("network2")
|
|
| 919 |
+ if err != nil {
|
|
| 920 |
+ t.Fatal(err) |
|
| 921 |
+ } |
|
| 922 |
+ if net2 == nil {
|
|
| 923 |
+ t.Fatal("Could not find network2")
|
|
| 924 |
+ } |
|
| 925 |
+ |
|
| 926 |
+ epName := fmt.Sprintf("pep%d", thrNumber)
|
|
| 927 |
+ |
|
| 928 |
+ if thrNumber == first {
|
|
| 929 |
+ ep, err = net1.EndpointByName(epName) |
|
| 930 |
+ } else {
|
|
| 931 |
+ ep, err = net2.EndpointByName(epName) |
|
| 932 |
+ } |
|
| 933 |
+ |
|
| 934 |
+ if err != nil {
|
|
| 935 |
+ t.Fatal(err) |
|
| 936 |
+ } |
|
| 937 |
+ if ep == nil {
|
|
| 938 |
+ t.Fatal("Got nil ep with no error")
|
|
| 939 |
+ } |
|
| 940 |
+ |
|
| 941 |
+ cid := fmt.Sprintf("%drace", thrNumber)
|
|
| 942 |
+ controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid)) |
|
| 943 |
+ if sb == nil {
|
|
| 944 |
+ t.Fatalf("Got nil sandbox for container: %s", cid)
|
|
| 945 |
+ } |
|
| 946 |
+ |
|
| 947 |
+ for i := 0; i < iterCnt; i++ {
|
|
| 948 |
+ parallelJoin(t, sb, ep, thrNumber) |
|
| 949 |
+ parallelLeave(t, sb, ep, thrNumber) |
|
| 950 |
+ } |
|
| 951 |
+ |
|
| 952 |
+ debugf("\n")
|
|
| 953 |
+ |
|
| 954 |
+ err = sb.Delete() |
|
| 955 |
+ if err != nil {
|
|
| 956 |
+ t.Fatal(err) |
|
| 957 |
+ } |
|
| 958 |
+ if thrNumber == first {
|
|
| 959 |
+ for thrdone := range done {
|
|
| 960 |
+ select {
|
|
| 961 |
+ case <-thrdone: |
|
| 962 |
+ } |
|
| 963 |
+ } |
|
| 964 |
+ |
|
| 965 |
+ testns.Close() |
|
| 966 |
+ if err := net2.Delete(); err != nil {
|
|
| 967 |
+ t.Fatal(err) |
|
| 968 |
+ } |
|
| 969 |
+ } else {
|
|
| 970 |
+ err = ep.Delete(false) |
|
| 971 |
+ if err != nil {
|
|
| 972 |
+ t.Fatal(err) |
|
| 973 |
+ } |
|
| 974 |
+ } |
|
| 975 |
+} |
|
| 976 |
+ |
|
| 977 |
+func TestParallel1(t *testing.T) {
|
|
| 978 |
+ runParallelTests(t, 1) |
|
| 979 |
+} |
|
| 980 |
+ |
|
| 981 |
+func TestParallel2(t *testing.T) {
|
|
| 982 |
+ runParallelTests(t, 2) |
|
| 983 |
+} |
|
| 984 |
+ |
|
| 985 |
+func TestParallel3(t *testing.T) {
|
|
| 986 |
+ runParallelTests(t, 3) |
|
| 987 |
+} |
|
| 988 |
+ |
|
| 989 |
+func TestNullIpam(t *testing.T) {
|
|
| 990 |
+ _, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", "", libnetwork.NetworkOptionIpam(ipamapi.NullIPAM, "", nil, nil, nil)) |
|
| 991 |
+ if err == nil || err.Error() != "ipv4 pool is empty" {
|
|
| 992 |
+ t.Fatal("bridge network should complain empty pool")
|
|
| 993 |
+ } |
|
| 994 |
+} |
| ... | ... |
@@ -1,19 +1,12 @@ |
| 1 | 1 |
package libnetwork_test |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "bytes" |
|
| 5 |
- "encoding/json" |
|
| 6 |
- "flag" |
|
| 7 | 4 |
"fmt" |
| 8 | 5 |
"io/ioutil" |
| 9 | 6 |
"net" |
| 10 | 7 |
"net/http" |
| 11 | 8 |
"net/http/httptest" |
| 12 | 9 |
"os" |
| 13 |
- "os/exec" |
|
| 14 |
- "runtime" |
|
| 15 |
- "strconv" |
|
| 16 |
- "strings" |
|
| 17 | 10 |
"sync" |
| 18 | 11 |
"testing" |
| 19 | 12 |
|
| ... | ... |
@@ -27,12 +20,8 @@ import ( |
| 27 | 27 |
"github.com/docker/libnetwork/ipamapi" |
| 28 | 28 |
"github.com/docker/libnetwork/netlabel" |
| 29 | 29 |
"github.com/docker/libnetwork/options" |
| 30 |
- "github.com/docker/libnetwork/osl" |
|
| 31 | 30 |
"github.com/docker/libnetwork/testutils" |
| 32 | 31 |
"github.com/docker/libnetwork/types" |
| 33 |
- "github.com/opencontainers/runc/libcontainer" |
|
| 34 |
- "github.com/opencontainers/runc/libcontainer/configs" |
|
| 35 |
- "github.com/vishvananda/netlink" |
|
| 36 | 32 |
"github.com/vishvananda/netns" |
| 37 | 33 |
) |
| 38 | 34 |
|
| ... | ... |
@@ -151,107 +140,6 @@ func TestNull(t *testing.T) {
|
| 151 | 151 |
} |
| 152 | 152 |
} |
| 153 | 153 |
|
| 154 |
-func TestHost(t *testing.T) {
|
|
| 155 |
- sbx1, err := controller.NewSandbox("host_c1",
|
|
| 156 |
- libnetwork.OptionHostname("test1"),
|
|
| 157 |
- libnetwork.OptionDomainname("docker.io"),
|
|
| 158 |
- libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
|
| 159 |
- libnetwork.OptionUseDefaultSandbox()) |
|
| 160 |
- if err != nil {
|
|
| 161 |
- t.Fatal(err) |
|
| 162 |
- } |
|
| 163 |
- defer func() {
|
|
| 164 |
- if err := sbx1.Delete(); err != nil {
|
|
| 165 |
- t.Fatal(err) |
|
| 166 |
- } |
|
| 167 |
- }() |
|
| 168 |
- |
|
| 169 |
- sbx2, err := controller.NewSandbox("host_c2",
|
|
| 170 |
- libnetwork.OptionHostname("test2"),
|
|
| 171 |
- libnetwork.OptionDomainname("docker.io"),
|
|
| 172 |
- libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
|
| 173 |
- libnetwork.OptionUseDefaultSandbox()) |
|
| 174 |
- if err != nil {
|
|
| 175 |
- t.Fatal(err) |
|
| 176 |
- } |
|
| 177 |
- defer func() {
|
|
| 178 |
- if err := sbx2.Delete(); err != nil {
|
|
| 179 |
- t.Fatal(err) |
|
| 180 |
- } |
|
| 181 |
- }() |
|
| 182 |
- |
|
| 183 |
- network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil)
|
|
| 184 |
- if err != nil {
|
|
| 185 |
- t.Fatal(err) |
|
| 186 |
- } |
|
| 187 |
- |
|
| 188 |
- ep1, err := network.CreateEndpoint("testep1")
|
|
| 189 |
- if err != nil {
|
|
| 190 |
- t.Fatal(err) |
|
| 191 |
- } |
|
| 192 |
- |
|
| 193 |
- if err := ep1.Join(sbx1); err != nil {
|
|
| 194 |
- t.Fatal(err) |
|
| 195 |
- } |
|
| 196 |
- |
|
| 197 |
- ep2, err := network.CreateEndpoint("testep2")
|
|
| 198 |
- if err != nil {
|
|
| 199 |
- t.Fatal(err) |
|
| 200 |
- } |
|
| 201 |
- |
|
| 202 |
- if err := ep2.Join(sbx2); err != nil {
|
|
| 203 |
- t.Fatal(err) |
|
| 204 |
- } |
|
| 205 |
- |
|
| 206 |
- if err := ep1.Leave(sbx1); err != nil {
|
|
| 207 |
- t.Fatal(err) |
|
| 208 |
- } |
|
| 209 |
- |
|
| 210 |
- if err := ep2.Leave(sbx2); err != nil {
|
|
| 211 |
- t.Fatal(err) |
|
| 212 |
- } |
|
| 213 |
- |
|
| 214 |
- if err := ep1.Delete(false); err != nil {
|
|
| 215 |
- t.Fatal(err) |
|
| 216 |
- } |
|
| 217 |
- |
|
| 218 |
- if err := ep2.Delete(false); err != nil {
|
|
| 219 |
- t.Fatal(err) |
|
| 220 |
- } |
|
| 221 |
- |
|
| 222 |
- // Try to create another host endpoint and join/leave that. |
|
| 223 |
- cnt3, err := controller.NewSandbox("host_c3",
|
|
| 224 |
- libnetwork.OptionHostname("test3"),
|
|
| 225 |
- libnetwork.OptionDomainname("docker.io"),
|
|
| 226 |
- libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
|
| 227 |
- libnetwork.OptionUseDefaultSandbox()) |
|
| 228 |
- if err != nil {
|
|
| 229 |
- t.Fatal(err) |
|
| 230 |
- } |
|
| 231 |
- defer func() {
|
|
| 232 |
- if err := cnt3.Delete(); err != nil {
|
|
| 233 |
- t.Fatal(err) |
|
| 234 |
- } |
|
| 235 |
- }() |
|
| 236 |
- |
|
| 237 |
- ep3, err := network.CreateEndpoint("testep3")
|
|
| 238 |
- if err != nil {
|
|
| 239 |
- t.Fatal(err) |
|
| 240 |
- } |
|
| 241 |
- |
|
| 242 |
- if err := ep3.Join(sbx2); err != nil {
|
|
| 243 |
- t.Fatal(err) |
|
| 244 |
- } |
|
| 245 |
- |
|
| 246 |
- if err := ep3.Leave(sbx2); err != nil {
|
|
| 247 |
- t.Fatal(err) |
|
| 248 |
- } |
|
| 249 |
- |
|
| 250 |
- if err := ep3.Delete(false); err != nil {
|
|
| 251 |
- t.Fatal(err) |
|
| 252 |
- } |
|
| 253 |
-} |
|
| 254 |
- |
|
| 255 | 154 |
func TestBridge(t *testing.T) {
|
| 256 | 155 |
if !testutils.IsRunningInContainer() {
|
| 257 | 156 |
defer testutils.SetupTestOSContext(t)() |
| ... | ... |
@@ -315,59 +203,6 @@ func TestBridge(t *testing.T) {
|
| 315 | 315 |
} |
| 316 | 316 |
} |
| 317 | 317 |
|
| 318 |
-// Testing IPV6 from MAC address |
|
| 319 |
-func TestBridgeIpv6FromMac(t *testing.T) {
|
|
| 320 |
- if !testutils.IsRunningInContainer() {
|
|
| 321 |
- defer testutils.SetupTestOSContext(t)() |
|
| 322 |
- } |
|
| 323 |
- |
|
| 324 |
- netOption := options.Generic{
|
|
| 325 |
- netlabel.GenericData: options.Generic{
|
|
| 326 |
- "BridgeName": "testipv6mac", |
|
| 327 |
- "EnableICC": true, |
|
| 328 |
- "EnableIPMasquerade": true, |
|
| 329 |
- }, |
|
| 330 |
- } |
|
| 331 |
- ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}}
|
|
| 332 |
- ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
|
|
| 333 |
- |
|
| 334 |
- network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "", |
|
| 335 |
- libnetwork.NetworkOptionGeneric(netOption), |
|
| 336 |
- libnetwork.NetworkOptionEnableIPv6(true), |
|
| 337 |
- libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil), |
|
| 338 |
- libnetwork.NetworkOptionDeferIPv6Alloc(true)) |
|
| 339 |
- if err != nil {
|
|
| 340 |
- t.Fatal(err) |
|
| 341 |
- } |
|
| 342 |
- |
|
| 343 |
- mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
|
|
| 344 |
- epOption := options.Generic{netlabel.MacAddress: mac}
|
|
| 345 |
- |
|
| 346 |
- ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption))
|
|
| 347 |
- if err != nil {
|
|
| 348 |
- t.Fatal(err) |
|
| 349 |
- } |
|
| 350 |
- |
|
| 351 |
- iface := ep.Info().Iface() |
|
| 352 |
- if !bytes.Equal(iface.MacAddress(), mac) {
|
|
| 353 |
- t.Fatalf("Unexpected mac address: %v", iface.MacAddress())
|
|
| 354 |
- } |
|
| 355 |
- |
|
| 356 |
- ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64")
|
|
| 357 |
- expIP.IP = ip |
|
| 358 |
- if !types.CompareIPNet(expIP, iface.AddressIPv6()) {
|
|
| 359 |
- t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6())
|
|
| 360 |
- } |
|
| 361 |
- |
|
| 362 |
- if err := ep.Delete(false); err != nil {
|
|
| 363 |
- t.Fatal(err) |
|
| 364 |
- } |
|
| 365 |
- |
|
| 366 |
- if err := network.Delete(); err != nil {
|
|
| 367 |
- t.Fatal(err) |
|
| 368 |
- } |
|
| 369 |
-} |
|
| 370 |
- |
|
| 371 | 318 |
func TestUnknownDriver(t *testing.T) {
|
| 372 | 319 |
if !testutils.IsRunningInContainer() {
|
| 373 | 320 |
defer testutils.SetupTestOSContext(t)() |
| ... | ... |
@@ -966,202 +801,6 @@ func TestNetworkQuery(t *testing.T) {
|
| 966 | 966 |
|
| 967 | 967 |
const containerID = "valid_c" |
| 968 | 968 |
|
| 969 |
-func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
|
|
| 970 |
- key := info.Sandbox().Key() |
|
| 971 |
- sbNs, err := netns.GetFromPath(key) |
|
| 972 |
- if err != nil {
|
|
| 973 |
- t.Fatalf("Failed to get network namespace path %q: %v", key, err)
|
|
| 974 |
- } |
|
| 975 |
- defer sbNs.Close() |
|
| 976 |
- |
|
| 977 |
- nh, err := netlink.NewHandleAt(sbNs) |
|
| 978 |
- if err != nil {
|
|
| 979 |
- t.Fatal(err) |
|
| 980 |
- } |
|
| 981 |
- |
|
| 982 |
- _, err = nh.LinkByName("eth0")
|
|
| 983 |
- if err != nil {
|
|
| 984 |
- t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
|
|
| 985 |
- } |
|
| 986 |
- |
|
| 987 |
- _, err = nh.LinkByName("eth1")
|
|
| 988 |
- if err != nil {
|
|
| 989 |
- t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err)
|
|
| 990 |
- } |
|
| 991 |
-} |
|
| 992 |
- |
|
| 993 |
-func TestEndpointJoin(t *testing.T) {
|
|
| 994 |
- if !testutils.IsRunningInContainer() {
|
|
| 995 |
- defer testutils.SetupTestOSContext(t)() |
|
| 996 |
- } |
|
| 997 |
- |
|
| 998 |
- // Create network 1 and add 2 endpoint: ep11, ep12 |
|
| 999 |
- netOption := options.Generic{
|
|
| 1000 |
- netlabel.GenericData: options.Generic{
|
|
| 1001 |
- "BridgeName": "testnetwork1", |
|
| 1002 |
- "EnableICC": true, |
|
| 1003 |
- "EnableIPMasquerade": true, |
|
| 1004 |
- }, |
|
| 1005 |
- } |
|
| 1006 |
- ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
|
|
| 1007 |
- n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "", |
|
| 1008 |
- libnetwork.NetworkOptionGeneric(netOption), |
|
| 1009 |
- libnetwork.NetworkOptionEnableIPv6(true), |
|
| 1010 |
- libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil), |
|
| 1011 |
- libnetwork.NetworkOptionDeferIPv6Alloc(true)) |
|
| 1012 |
- if err != nil {
|
|
| 1013 |
- t.Fatal(err) |
|
| 1014 |
- } |
|
| 1015 |
- defer func() {
|
|
| 1016 |
- if err := n1.Delete(); err != nil {
|
|
| 1017 |
- t.Fatal(err) |
|
| 1018 |
- } |
|
| 1019 |
- }() |
|
| 1020 |
- |
|
| 1021 |
- ep1, err := n1.CreateEndpoint("ep1")
|
|
| 1022 |
- if err != nil {
|
|
| 1023 |
- t.Fatal(err) |
|
| 1024 |
- } |
|
| 1025 |
- defer func() {
|
|
| 1026 |
- if err := ep1.Delete(false); err != nil {
|
|
| 1027 |
- t.Fatal(err) |
|
| 1028 |
- } |
|
| 1029 |
- }() |
|
| 1030 |
- |
|
| 1031 |
- // Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint() |
|
| 1032 |
- info := ep1.Info() |
|
| 1033 |
- iface := info.Iface() |
|
| 1034 |
- if iface.Address() != nil && iface.Address().IP.To4() == nil {
|
|
| 1035 |
- t.Fatalf("Invalid IP address returned: %v", iface.Address())
|
|
| 1036 |
- } |
|
| 1037 |
- if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil {
|
|
| 1038 |
- t.Fatalf("Invalid IPv6 address returned: %v", iface.Address())
|
|
| 1039 |
- } |
|
| 1040 |
- |
|
| 1041 |
- if len(info.Gateway()) != 0 {
|
|
| 1042 |
- t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway())
|
|
| 1043 |
- } |
|
| 1044 |
- if len(info.GatewayIPv6()) != 0 {
|
|
| 1045 |
- t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6())
|
|
| 1046 |
- } |
|
| 1047 |
- |
|
| 1048 |
- if info.Sandbox() != nil {
|
|
| 1049 |
- t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key())
|
|
| 1050 |
- } |
|
| 1051 |
- |
|
| 1052 |
- // test invalid joins |
|
| 1053 |
- err = ep1.Join(nil) |
|
| 1054 |
- if err == nil {
|
|
| 1055 |
- t.Fatalf("Expected to fail join with nil Sandbox")
|
|
| 1056 |
- } |
|
| 1057 |
- if _, ok := err.(types.BadRequestError); !ok {
|
|
| 1058 |
- t.Fatalf("Unexpected error type returned: %T", err)
|
|
| 1059 |
- } |
|
| 1060 |
- |
|
| 1061 |
- fsbx := &fakeSandbox{}
|
|
| 1062 |
- if err = ep1.Join(fsbx); err == nil {
|
|
| 1063 |
- t.Fatalf("Expected to fail join with invalid Sandbox")
|
|
| 1064 |
- } |
|
| 1065 |
- if _, ok := err.(types.BadRequestError); !ok {
|
|
| 1066 |
- t.Fatalf("Unexpected error type returned: %T", err)
|
|
| 1067 |
- } |
|
| 1068 |
- |
|
| 1069 |
- sb, err := controller.NewSandbox(containerID, |
|
| 1070 |
- libnetwork.OptionHostname("test"),
|
|
| 1071 |
- libnetwork.OptionDomainname("docker.io"),
|
|
| 1072 |
- libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
|
| 1073 |
- if err != nil {
|
|
| 1074 |
- t.Fatal(err) |
|
| 1075 |
- } |
|
| 1076 |
- |
|
| 1077 |
- defer func() {
|
|
| 1078 |
- if err := sb.Delete(); err != nil {
|
|
| 1079 |
- t.Fatal(err) |
|
| 1080 |
- } |
|
| 1081 |
- }() |
|
| 1082 |
- |
|
| 1083 |
- err = ep1.Join(sb) |
|
| 1084 |
- if err != nil {
|
|
| 1085 |
- t.Fatal(err) |
|
| 1086 |
- } |
|
| 1087 |
- defer func() {
|
|
| 1088 |
- err = ep1.Leave(sb) |
|
| 1089 |
- if err != nil {
|
|
| 1090 |
- t.Fatal(err) |
|
| 1091 |
- } |
|
| 1092 |
- }() |
|
| 1093 |
- |
|
| 1094 |
- // Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined. |
|
| 1095 |
- info = ep1.Info() |
|
| 1096 |
- if len(info.Gateway()) == 0 {
|
|
| 1097 |
- t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway())
|
|
| 1098 |
- } |
|
| 1099 |
- if len(info.GatewayIPv6()) == 0 {
|
|
| 1100 |
- t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6())
|
|
| 1101 |
- } |
|
| 1102 |
- |
|
| 1103 |
- if info.Sandbox() == nil {
|
|
| 1104 |
- t.Fatalf("Expected a non-empty sandbox key for a joined endpoint. Instead found an empty sandbox key")
|
|
| 1105 |
- } |
|
| 1106 |
- |
|
| 1107 |
- // Check endpoint provided container information |
|
| 1108 |
- if ep1.Info().Sandbox().Key() != sb.Key() {
|
|
| 1109 |
- t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key())
|
|
| 1110 |
- } |
|
| 1111 |
- |
|
| 1112 |
- // Attempt retrieval of endpoint interfaces statistics |
|
| 1113 |
- stats, err := sb.Statistics() |
|
| 1114 |
- if err != nil {
|
|
| 1115 |
- t.Fatal(err) |
|
| 1116 |
- } |
|
| 1117 |
- if _, ok := stats["eth0"]; !ok {
|
|
| 1118 |
- t.Fatalf("Did not find eth0 statistics")
|
|
| 1119 |
- } |
|
| 1120 |
- |
|
| 1121 |
- // Now test the container joining another network |
|
| 1122 |
- n2, err := createTestNetwork(bridgeNetType, "testnetwork2", |
|
| 1123 |
- options.Generic{
|
|
| 1124 |
- netlabel.GenericData: options.Generic{
|
|
| 1125 |
- "BridgeName": "testnetwork2", |
|
| 1126 |
- }, |
|
| 1127 |
- }, nil, nil) |
|
| 1128 |
- if err != nil {
|
|
| 1129 |
- t.Fatal(err) |
|
| 1130 |
- } |
|
| 1131 |
- defer func() {
|
|
| 1132 |
- if err := n2.Delete(); err != nil {
|
|
| 1133 |
- t.Fatal(err) |
|
| 1134 |
- } |
|
| 1135 |
- }() |
|
| 1136 |
- |
|
| 1137 |
- ep2, err := n2.CreateEndpoint("ep2")
|
|
| 1138 |
- if err != nil {
|
|
| 1139 |
- t.Fatal(err) |
|
| 1140 |
- } |
|
| 1141 |
- defer func() {
|
|
| 1142 |
- if err := ep2.Delete(false); err != nil {
|
|
| 1143 |
- t.Fatal(err) |
|
| 1144 |
- } |
|
| 1145 |
- }() |
|
| 1146 |
- |
|
| 1147 |
- err = ep2.Join(sb) |
|
| 1148 |
- if err != nil {
|
|
| 1149 |
- t.Fatal(err) |
|
| 1150 |
- } |
|
| 1151 |
- defer func() {
|
|
| 1152 |
- err = ep2.Leave(sb) |
|
| 1153 |
- if err != nil {
|
|
| 1154 |
- t.Fatal(err) |
|
| 1155 |
- } |
|
| 1156 |
- }() |
|
| 1157 |
- |
|
| 1158 |
- if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
|
|
| 1159 |
- t.Fatalf("ep1 and ep2 returned different container sandbox key")
|
|
| 1160 |
- } |
|
| 1161 |
- |
|
| 1162 |
- checkSandbox(t, info) |
|
| 1163 |
-} |
|
| 1164 |
- |
|
| 1165 | 969 |
type fakeSandbox struct{}
|
| 1166 | 970 |
|
| 1167 | 971 |
func (f *fakeSandbox) ID() string {
|
| ... | ... |
@@ -1216,155 +855,6 @@ func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint {
|
| 1216 | 1216 |
return nil |
| 1217 | 1217 |
} |
| 1218 | 1218 |
|
| 1219 |
-func TestExternalKey(t *testing.T) {
|
|
| 1220 |
- externalKeyTest(t, false) |
|
| 1221 |
-} |
|
| 1222 |
- |
|
| 1223 |
-func externalKeyTest(t *testing.T, reexec bool) {
|
|
| 1224 |
- if !testutils.IsRunningInContainer() {
|
|
| 1225 |
- defer testutils.SetupTestOSContext(t)() |
|
| 1226 |
- } |
|
| 1227 |
- |
|
| 1228 |
- n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
|
|
| 1229 |
- netlabel.GenericData: options.Generic{
|
|
| 1230 |
- "BridgeName": "testnetwork", |
|
| 1231 |
- }, |
|
| 1232 |
- }, nil, nil) |
|
| 1233 |
- if err != nil {
|
|
| 1234 |
- t.Fatal(err) |
|
| 1235 |
- } |
|
| 1236 |
- defer func() {
|
|
| 1237 |
- if err := n.Delete(); err != nil {
|
|
| 1238 |
- t.Fatal(err) |
|
| 1239 |
- } |
|
| 1240 |
- }() |
|
| 1241 |
- |
|
| 1242 |
- ep, err := n.CreateEndpoint("ep1")
|
|
| 1243 |
- if err != nil {
|
|
| 1244 |
- t.Fatal(err) |
|
| 1245 |
- } |
|
| 1246 |
- defer func() {
|
|
| 1247 |
- err = ep.Delete(false) |
|
| 1248 |
- if err != nil {
|
|
| 1249 |
- t.Fatal(err) |
|
| 1250 |
- } |
|
| 1251 |
- }() |
|
| 1252 |
- |
|
| 1253 |
- ep2, err := n.CreateEndpoint("ep2")
|
|
| 1254 |
- if err != nil {
|
|
| 1255 |
- t.Fatal(err) |
|
| 1256 |
- } |
|
| 1257 |
- defer func() {
|
|
| 1258 |
- err = ep2.Delete(false) |
|
| 1259 |
- if err != nil {
|
|
| 1260 |
- t.Fatal(err) |
|
| 1261 |
- } |
|
| 1262 |
- }() |
|
| 1263 |
- |
|
| 1264 |
- cnt, err := controller.NewSandbox(containerID, |
|
| 1265 |
- libnetwork.OptionHostname("test"),
|
|
| 1266 |
- libnetwork.OptionDomainname("docker.io"),
|
|
| 1267 |
- libnetwork.OptionUseExternalKey(), |
|
| 1268 |
- libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
|
| 1269 |
- defer func() {
|
|
| 1270 |
- if err := cnt.Delete(); err != nil {
|
|
| 1271 |
- t.Fatal(err) |
|
| 1272 |
- } |
|
| 1273 |
- osl.GC() |
|
| 1274 |
- }() |
|
| 1275 |
- |
|
| 1276 |
- // Join endpoint to sandbox before SetKey |
|
| 1277 |
- err = ep.Join(cnt) |
|
| 1278 |
- if err != nil {
|
|
| 1279 |
- t.Fatal(err) |
|
| 1280 |
- } |
|
| 1281 |
- defer func() {
|
|
| 1282 |
- err = ep.Leave(cnt) |
|
| 1283 |
- if err != nil {
|
|
| 1284 |
- t.Fatal(err) |
|
| 1285 |
- } |
|
| 1286 |
- }() |
|
| 1287 |
- |
|
| 1288 |
- sbox := ep.Info().Sandbox() |
|
| 1289 |
- if sbox == nil {
|
|
| 1290 |
- t.Fatalf("Expected to have a valid Sandbox")
|
|
| 1291 |
- } |
|
| 1292 |
- |
|
| 1293 |
- if reexec {
|
|
| 1294 |
- err := reexecSetKey("this-must-fail", containerID, controller.ID())
|
|
| 1295 |
- if err == nil {
|
|
| 1296 |
- t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created")
|
|
| 1297 |
- } |
|
| 1298 |
- } else {
|
|
| 1299 |
- // Setting a non-existing key (namespace) must fail |
|
| 1300 |
- if err := sbox.SetKey("this-must-fail"); err == nil {
|
|
| 1301 |
- t.Fatalf("Setkey must fail if the corresponding namespace is not created")
|
|
| 1302 |
- } |
|
| 1303 |
- } |
|
| 1304 |
- |
|
| 1305 |
- // Create a new OS sandbox using the osl API before using it in SetKey |
|
| 1306 |
- if extOsBox, err := osl.NewSandbox("ValidKey", true, false); err != nil {
|
|
| 1307 |
- t.Fatalf("Failed to create new osl sandbox")
|
|
| 1308 |
- } else {
|
|
| 1309 |
- defer func() {
|
|
| 1310 |
- if err := extOsBox.Destroy(); err != nil {
|
|
| 1311 |
- log.Warnf("Failed to remove os sandbox: %v", err)
|
|
| 1312 |
- } |
|
| 1313 |
- }() |
|
| 1314 |
- } |
|
| 1315 |
- |
|
| 1316 |
- if reexec {
|
|
| 1317 |
- err := reexecSetKey("ValidKey", containerID, controller.ID())
|
|
| 1318 |
- if err != nil {
|
|
| 1319 |
- t.Fatalf("SetExternalKey failed with %v", err)
|
|
| 1320 |
- } |
|
| 1321 |
- } else {
|
|
| 1322 |
- if err := sbox.SetKey("ValidKey"); err != nil {
|
|
| 1323 |
- t.Fatalf("Setkey failed with %v", err)
|
|
| 1324 |
- } |
|
| 1325 |
- } |
|
| 1326 |
- |
|
| 1327 |
- // Join endpoint to sandbox after SetKey |
|
| 1328 |
- err = ep2.Join(sbox) |
|
| 1329 |
- if err != nil {
|
|
| 1330 |
- t.Fatal(err) |
|
| 1331 |
- } |
|
| 1332 |
- defer func() {
|
|
| 1333 |
- err = ep2.Leave(sbox) |
|
| 1334 |
- if err != nil {
|
|
| 1335 |
- t.Fatal(err) |
|
| 1336 |
- } |
|
| 1337 |
- }() |
|
| 1338 |
- |
|
| 1339 |
- if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
|
|
| 1340 |
- t.Fatalf("ep1 and ep2 returned different container sandbox key")
|
|
| 1341 |
- } |
|
| 1342 |
- |
|
| 1343 |
- checkSandbox(t, ep.Info()) |
|
| 1344 |
-} |
|
| 1345 |
- |
|
| 1346 |
-func reexecSetKey(key string, containerID string, controllerID string) error {
|
|
| 1347 |
- var ( |
|
| 1348 |
- state libcontainer.State |
|
| 1349 |
- b []byte |
|
| 1350 |
- err error |
|
| 1351 |
- ) |
|
| 1352 |
- |
|
| 1353 |
- state.NamespacePaths = make(map[configs.NamespaceType]string) |
|
| 1354 |
- state.NamespacePaths[configs.NamespaceType("NEWNET")] = key
|
|
| 1355 |
- if b, err = json.Marshal(state); err != nil {
|
|
| 1356 |
- return err |
|
| 1357 |
- } |
|
| 1358 |
- cmd := &exec.Cmd{
|
|
| 1359 |
- Path: reexec.Self(), |
|
| 1360 |
- Args: append([]string{"libnetwork-setkey"}, containerID, controllerID),
|
|
| 1361 |
- Stdin: strings.NewReader(string(b)), |
|
| 1362 |
- Stdout: os.Stdout, |
|
| 1363 |
- Stderr: os.Stderr, |
|
| 1364 |
- } |
|
| 1365 |
- return cmd.Run() |
|
| 1366 |
-} |
|
| 1367 |
- |
|
| 1368 | 1219 |
func TestEndpointDeleteWithActiveContainer(t *testing.T) {
|
| 1369 | 1220 |
if !testutils.IsRunningInContainer() {
|
| 1370 | 1221 |
defer testutils.SetupTestOSContext(t)() |
| ... | ... |
@@ -1678,304 +1168,6 @@ func TestEndpointUpdateParent(t *testing.T) {
|
| 1678 | 1678 |
} |
| 1679 | 1679 |
} |
| 1680 | 1680 |
|
| 1681 |
-func TestEnableIPv6(t *testing.T) {
|
|
| 1682 |
- if !testutils.IsRunningInContainer() {
|
|
| 1683 |
- defer testutils.SetupTestOSContext(t)() |
|
| 1684 |
- } |
|
| 1685 |
- |
|
| 1686 |
- tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
|
| 1687 |
- expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n")
|
|
| 1688 |
- //take a copy of resolv.conf for restoring after test completes |
|
| 1689 |
- resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
| 1690 |
- if err != nil {
|
|
| 1691 |
- t.Fatal(err) |
|
| 1692 |
- } |
|
| 1693 |
- //cleanup |
|
| 1694 |
- defer func() {
|
|
| 1695 |
- if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
|
| 1696 |
- t.Fatal(err) |
|
| 1697 |
- } |
|
| 1698 |
- }() |
|
| 1699 |
- |
|
| 1700 |
- netOption := options.Generic{
|
|
| 1701 |
- netlabel.EnableIPv6: true, |
|
| 1702 |
- netlabel.GenericData: options.Generic{
|
|
| 1703 |
- "BridgeName": "testnetwork", |
|
| 1704 |
- }, |
|
| 1705 |
- } |
|
| 1706 |
- ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe99::/64", Gateway: "fe99::9"}}
|
|
| 1707 |
- |
|
| 1708 |
- n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList)
|
|
| 1709 |
- if err != nil {
|
|
| 1710 |
- t.Fatal(err) |
|
| 1711 |
- } |
|
| 1712 |
- defer func() {
|
|
| 1713 |
- if err := n.Delete(); err != nil {
|
|
| 1714 |
- t.Fatal(err) |
|
| 1715 |
- } |
|
| 1716 |
- }() |
|
| 1717 |
- |
|
| 1718 |
- ep1, err := n.CreateEndpoint("ep1")
|
|
| 1719 |
- if err != nil {
|
|
| 1720 |
- t.Fatal(err) |
|
| 1721 |
- } |
|
| 1722 |
- |
|
| 1723 |
- if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
|
|
| 1724 |
- t.Fatal(err) |
|
| 1725 |
- } |
|
| 1726 |
- |
|
| 1727 |
- resolvConfPath := "/tmp/libnetwork_test/resolv.conf" |
|
| 1728 |
- defer os.Remove(resolvConfPath) |
|
| 1729 |
- |
|
| 1730 |
- sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) |
|
| 1731 |
- if err != nil {
|
|
| 1732 |
- t.Fatal(err) |
|
| 1733 |
- } |
|
| 1734 |
- defer func() {
|
|
| 1735 |
- if err := sb.Delete(); err != nil {
|
|
| 1736 |
- t.Fatal(err) |
|
| 1737 |
- } |
|
| 1738 |
- }() |
|
| 1739 |
- |
|
| 1740 |
- err = ep1.Join(sb) |
|
| 1741 |
- if err != nil {
|
|
| 1742 |
- t.Fatal(err) |
|
| 1743 |
- } |
|
| 1744 |
- |
|
| 1745 |
- content, err := ioutil.ReadFile(resolvConfPath) |
|
| 1746 |
- if err != nil {
|
|
| 1747 |
- t.Fatal(err) |
|
| 1748 |
- } |
|
| 1749 |
- |
|
| 1750 |
- if !bytes.Equal(content, expectedResolvConf) {
|
|
| 1751 |
- t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf), string(content))
|
|
| 1752 |
- } |
|
| 1753 |
- |
|
| 1754 |
- if err != nil {
|
|
| 1755 |
- t.Fatal(err) |
|
| 1756 |
- } |
|
| 1757 |
-} |
|
| 1758 |
- |
|
| 1759 |
-func TestResolvConfHost(t *testing.T) {
|
|
| 1760 |
- if !testutils.IsRunningInContainer() {
|
|
| 1761 |
- defer testutils.SetupTestOSContext(t)() |
|
| 1762 |
- } |
|
| 1763 |
- |
|
| 1764 |
- tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n")
|
|
| 1765 |
- |
|
| 1766 |
- //take a copy of resolv.conf for restoring after test completes |
|
| 1767 |
- resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
| 1768 |
- if err != nil {
|
|
| 1769 |
- t.Fatal(err) |
|
| 1770 |
- } |
|
| 1771 |
- //cleanup |
|
| 1772 |
- defer func() {
|
|
| 1773 |
- if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
|
| 1774 |
- t.Fatal(err) |
|
| 1775 |
- } |
|
| 1776 |
- }() |
|
| 1777 |
- |
|
| 1778 |
- n, err := controller.NetworkByName("testhost")
|
|
| 1779 |
- if err != nil {
|
|
| 1780 |
- t.Fatal(err) |
|
| 1781 |
- } |
|
| 1782 |
- |
|
| 1783 |
- ep1, err := n.CreateEndpoint("ep1", libnetwork.CreateOptionDisableResolution())
|
|
| 1784 |
- if err != nil {
|
|
| 1785 |
- t.Fatal(err) |
|
| 1786 |
- } |
|
| 1787 |
- |
|
| 1788 |
- if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
|
|
| 1789 |
- t.Fatal(err) |
|
| 1790 |
- } |
|
| 1791 |
- |
|
| 1792 |
- resolvConfPath := "/tmp/libnetwork_test/resolv.conf" |
|
| 1793 |
- defer os.Remove(resolvConfPath) |
|
| 1794 |
- |
|
| 1795 |
- sb, err := controller.NewSandbox(containerID, |
|
| 1796 |
- libnetwork.OptionResolvConfPath(resolvConfPath), |
|
| 1797 |
- libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
|
|
| 1798 |
- if err != nil {
|
|
| 1799 |
- t.Fatal(err) |
|
| 1800 |
- } |
|
| 1801 |
- defer func() {
|
|
| 1802 |
- if err := sb.Delete(); err != nil {
|
|
| 1803 |
- t.Fatal(err) |
|
| 1804 |
- } |
|
| 1805 |
- }() |
|
| 1806 |
- |
|
| 1807 |
- err = ep1.Join(sb) |
|
| 1808 |
- if err != nil {
|
|
| 1809 |
- t.Fatal(err) |
|
| 1810 |
- } |
|
| 1811 |
- defer func() {
|
|
| 1812 |
- err = ep1.Leave(sb) |
|
| 1813 |
- if err != nil {
|
|
| 1814 |
- t.Fatal(err) |
|
| 1815 |
- } |
|
| 1816 |
- }() |
|
| 1817 |
- |
|
| 1818 |
- finfo, err := os.Stat(resolvConfPath) |
|
| 1819 |
- if err != nil {
|
|
| 1820 |
- t.Fatal(err) |
|
| 1821 |
- } |
|
| 1822 |
- |
|
| 1823 |
- fmode := (os.FileMode)(0644) |
|
| 1824 |
- if finfo.Mode() != fmode {
|
|
| 1825 |
- t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
|
|
| 1826 |
- } |
|
| 1827 |
- |
|
| 1828 |
- content, err := ioutil.ReadFile(resolvConfPath) |
|
| 1829 |
- if err != nil {
|
|
| 1830 |
- t.Fatal(err) |
|
| 1831 |
- } |
|
| 1832 |
- |
|
| 1833 |
- if !bytes.Equal(content, tmpResolvConf) {
|
|
| 1834 |
- t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content))
|
|
| 1835 |
- } |
|
| 1836 |
-} |
|
| 1837 |
- |
|
| 1838 |
-func TestResolvConf(t *testing.T) {
|
|
| 1839 |
- if !testutils.IsRunningInContainer() {
|
|
| 1840 |
- defer testutils.SetupTestOSContext(t)() |
|
| 1841 |
- } |
|
| 1842 |
- |
|
| 1843 |
- tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
|
| 1844 |
- tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
|
| 1845 |
- expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n")
|
|
| 1846 |
- tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n")
|
|
| 1847 |
- |
|
| 1848 |
- //take a copy of resolv.conf for restoring after test completes |
|
| 1849 |
- resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
| 1850 |
- if err != nil {
|
|
| 1851 |
- t.Fatal(err) |
|
| 1852 |
- } |
|
| 1853 |
- //cleanup |
|
| 1854 |
- defer func() {
|
|
| 1855 |
- if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
|
|
| 1856 |
- t.Fatal(err) |
|
| 1857 |
- } |
|
| 1858 |
- }() |
|
| 1859 |
- |
|
| 1860 |
- netOption := options.Generic{
|
|
| 1861 |
- netlabel.GenericData: options.Generic{
|
|
| 1862 |
- "BridgeName": "testnetwork", |
|
| 1863 |
- }, |
|
| 1864 |
- } |
|
| 1865 |
- n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil)
|
|
| 1866 |
- if err != nil {
|
|
| 1867 |
- t.Fatal(err) |
|
| 1868 |
- } |
|
| 1869 |
- defer func() {
|
|
| 1870 |
- if err := n.Delete(); err != nil {
|
|
| 1871 |
- t.Fatal(err) |
|
| 1872 |
- } |
|
| 1873 |
- }() |
|
| 1874 |
- |
|
| 1875 |
- ep, err := n.CreateEndpoint("ep")
|
|
| 1876 |
- if err != nil {
|
|
| 1877 |
- t.Fatal(err) |
|
| 1878 |
- } |
|
| 1879 |
- |
|
| 1880 |
- if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil {
|
|
| 1881 |
- t.Fatal(err) |
|
| 1882 |
- } |
|
| 1883 |
- |
|
| 1884 |
- resolvConfPath := "/tmp/libnetwork_test/resolv.conf" |
|
| 1885 |
- defer os.Remove(resolvConfPath) |
|
| 1886 |
- |
|
| 1887 |
- sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath)) |
|
| 1888 |
- if err != nil {
|
|
| 1889 |
- t.Fatal(err) |
|
| 1890 |
- } |
|
| 1891 |
- defer func() {
|
|
| 1892 |
- if err := sb1.Delete(); err != nil {
|
|
| 1893 |
- t.Fatal(err) |
|
| 1894 |
- } |
|
| 1895 |
- }() |
|
| 1896 |
- |
|
| 1897 |
- err = ep.Join(sb1) |
|
| 1898 |
- if err != nil {
|
|
| 1899 |
- t.Fatal(err) |
|
| 1900 |
- } |
|
| 1901 |
- |
|
| 1902 |
- finfo, err := os.Stat(resolvConfPath) |
|
| 1903 |
- if err != nil {
|
|
| 1904 |
- t.Fatal(err) |
|
| 1905 |
- } |
|
| 1906 |
- |
|
| 1907 |
- fmode := (os.FileMode)(0644) |
|
| 1908 |
- if finfo.Mode() != fmode {
|
|
| 1909 |
- t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
|
|
| 1910 |
- } |
|
| 1911 |
- |
|
| 1912 |
- content, err := ioutil.ReadFile(resolvConfPath) |
|
| 1913 |
- if err != nil {
|
|
| 1914 |
- t.Fatal(err) |
|
| 1915 |
- } |
|
| 1916 |
- |
|
| 1917 |
- if !bytes.Equal(content, expectedResolvConf1) {
|
|
| 1918 |
- fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content)
|
|
| 1919 |
- t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
|
|
| 1920 |
- } |
|
| 1921 |
- |
|
| 1922 |
- err = ep.Leave(sb1) |
|
| 1923 |
- if err != nil {
|
|
| 1924 |
- t.Fatal(err) |
|
| 1925 |
- } |
|
| 1926 |
- |
|
| 1927 |
- if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil {
|
|
| 1928 |
- t.Fatal(err) |
|
| 1929 |
- } |
|
| 1930 |
- |
|
| 1931 |
- sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath)) |
|
| 1932 |
- if err != nil {
|
|
| 1933 |
- t.Fatal(err) |
|
| 1934 |
- } |
|
| 1935 |
- defer func() {
|
|
| 1936 |
- if err := sb2.Delete(); err != nil {
|
|
| 1937 |
- t.Fatal(err) |
|
| 1938 |
- } |
|
| 1939 |
- }() |
|
| 1940 |
- |
|
| 1941 |
- err = ep.Join(sb2) |
|
| 1942 |
- if err != nil {
|
|
| 1943 |
- t.Fatal(err) |
|
| 1944 |
- } |
|
| 1945 |
- |
|
| 1946 |
- content, err = ioutil.ReadFile(resolvConfPath) |
|
| 1947 |
- if err != nil {
|
|
| 1948 |
- t.Fatal(err) |
|
| 1949 |
- } |
|
| 1950 |
- |
|
| 1951 |
- if !bytes.Equal(content, expectedResolvConf1) {
|
|
| 1952 |
- t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
|
|
| 1953 |
- } |
|
| 1954 |
- |
|
| 1955 |
- if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil {
|
|
| 1956 |
- t.Fatal(err) |
|
| 1957 |
- } |
|
| 1958 |
- |
|
| 1959 |
- err = ep.Leave(sb2) |
|
| 1960 |
- if err != nil {
|
|
| 1961 |
- t.Fatal(err) |
|
| 1962 |
- } |
|
| 1963 |
- |
|
| 1964 |
- err = ep.Join(sb2) |
|
| 1965 |
- if err != nil {
|
|
| 1966 |
- t.Fatal(err) |
|
| 1967 |
- } |
|
| 1968 |
- |
|
| 1969 |
- content, err = ioutil.ReadFile(resolvConfPath) |
|
| 1970 |
- if err != nil {
|
|
| 1971 |
- t.Fatal(err) |
|
| 1972 |
- } |
|
| 1973 |
- |
|
| 1974 |
- if !bytes.Equal(content, tmpResolvConf3) {
|
|
| 1975 |
- t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content))
|
|
| 1976 |
- } |
|
| 1977 |
-} |
|
| 1978 |
- |
|
| 1979 | 1681 |
func TestInvalidRemoteDriver(t *testing.T) {
|
| 1980 | 1682 |
if !testutils.IsRunningInContainer() {
|
| 1981 | 1683 |
t.Skip("Skipping test when not running inside a Container")
|
| ... | ... |
@@ -2164,171 +1356,3 @@ func debugf(format string, a ...interface{}) (int, error) {
|
| 2164 | 2164 |
|
| 2165 | 2165 |
return 0, nil |
| 2166 | 2166 |
} |
| 2167 |
- |
|
| 2168 |
-func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
|
| 2169 |
- debugf("J%d.", thrNumber)
|
|
| 2170 |
- var err error |
|
| 2171 |
- |
|
| 2172 |
- sb := sboxes[thrNumber-1] |
|
| 2173 |
- err = ep.Join(sb) |
|
| 2174 |
- |
|
| 2175 |
- runtime.LockOSThread() |
|
| 2176 |
- if err != nil {
|
|
| 2177 |
- if _, ok := err.(types.ForbiddenError); !ok {
|
|
| 2178 |
- t.Fatalf("thread %d: %v", thrNumber, err)
|
|
| 2179 |
- } |
|
| 2180 |
- debugf("JE%d(%v).", thrNumber, err)
|
|
| 2181 |
- } |
|
| 2182 |
- debugf("JD%d.", thrNumber)
|
|
| 2183 |
-} |
|
| 2184 |
- |
|
| 2185 |
-func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
|
| 2186 |
- debugf("L%d.", thrNumber)
|
|
| 2187 |
- var err error |
|
| 2188 |
- |
|
| 2189 |
- sb := sboxes[thrNumber-1] |
|
| 2190 |
- |
|
| 2191 |
- err = ep.Leave(sb) |
|
| 2192 |
- runtime.LockOSThread() |
|
| 2193 |
- if err != nil {
|
|
| 2194 |
- if _, ok := err.(types.ForbiddenError); !ok {
|
|
| 2195 |
- t.Fatalf("thread %d: %v", thrNumber, err)
|
|
| 2196 |
- } |
|
| 2197 |
- debugf("LE%d(%v).", thrNumber, err)
|
|
| 2198 |
- } |
|
| 2199 |
- debugf("LD%d.", thrNumber)
|
|
| 2200 |
-} |
|
| 2201 |
- |
|
| 2202 |
-func runParallelTests(t *testing.T, thrNumber int) {
|
|
| 2203 |
- var ( |
|
| 2204 |
- ep libnetwork.Endpoint |
|
| 2205 |
- sb libnetwork.Sandbox |
|
| 2206 |
- err error |
|
| 2207 |
- ) |
|
| 2208 |
- |
|
| 2209 |
- t.Parallel() |
|
| 2210 |
- |
|
| 2211 |
- pTest := flag.Lookup("test.parallel")
|
|
| 2212 |
- if pTest == nil {
|
|
| 2213 |
- t.Skip("Skipped because test.parallel flag not set;")
|
|
| 2214 |
- } |
|
| 2215 |
- numParallel, err := strconv.Atoi(pTest.Value.String()) |
|
| 2216 |
- if err != nil {
|
|
| 2217 |
- t.Fatal(err) |
|
| 2218 |
- } |
|
| 2219 |
- if numParallel < numThreads {
|
|
| 2220 |
- t.Skip("Skipped because t.parallel was less than ", numThreads)
|
|
| 2221 |
- } |
|
| 2222 |
- |
|
| 2223 |
- runtime.LockOSThread() |
|
| 2224 |
- defer runtime.UnlockOSThread() |
|
| 2225 |
- |
|
| 2226 |
- if thrNumber == first {
|
|
| 2227 |
- createGlobalInstance(t) |
|
| 2228 |
- } |
|
| 2229 |
- |
|
| 2230 |
- if thrNumber != first {
|
|
| 2231 |
- select {
|
|
| 2232 |
- case <-start: |
|
| 2233 |
- } |
|
| 2234 |
- |
|
| 2235 |
- thrdone := make(chan struct{})
|
|
| 2236 |
- done <- thrdone |
|
| 2237 |
- defer close(thrdone) |
|
| 2238 |
- |
|
| 2239 |
- if thrNumber == last {
|
|
| 2240 |
- defer close(done) |
|
| 2241 |
- } |
|
| 2242 |
- |
|
| 2243 |
- err = netns.Set(testns) |
|
| 2244 |
- if err != nil {
|
|
| 2245 |
- t.Fatal(err) |
|
| 2246 |
- } |
|
| 2247 |
- } |
|
| 2248 |
- defer netns.Set(origns) |
|
| 2249 |
- |
|
| 2250 |
- net1, err := controller.NetworkByName("testhost")
|
|
| 2251 |
- if err != nil {
|
|
| 2252 |
- t.Fatal(err) |
|
| 2253 |
- } |
|
| 2254 |
- if net1 == nil {
|
|
| 2255 |
- t.Fatal("Could not find testhost")
|
|
| 2256 |
- } |
|
| 2257 |
- |
|
| 2258 |
- net2, err := controller.NetworkByName("network2")
|
|
| 2259 |
- if err != nil {
|
|
| 2260 |
- t.Fatal(err) |
|
| 2261 |
- } |
|
| 2262 |
- if net2 == nil {
|
|
| 2263 |
- t.Fatal("Could not find network2")
|
|
| 2264 |
- } |
|
| 2265 |
- |
|
| 2266 |
- epName := fmt.Sprintf("pep%d", thrNumber)
|
|
| 2267 |
- |
|
| 2268 |
- if thrNumber == first {
|
|
| 2269 |
- ep, err = net1.EndpointByName(epName) |
|
| 2270 |
- } else {
|
|
| 2271 |
- ep, err = net2.EndpointByName(epName) |
|
| 2272 |
- } |
|
| 2273 |
- |
|
| 2274 |
- if err != nil {
|
|
| 2275 |
- t.Fatal(err) |
|
| 2276 |
- } |
|
| 2277 |
- if ep == nil {
|
|
| 2278 |
- t.Fatal("Got nil ep with no error")
|
|
| 2279 |
- } |
|
| 2280 |
- |
|
| 2281 |
- cid := fmt.Sprintf("%drace", thrNumber)
|
|
| 2282 |
- controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid)) |
|
| 2283 |
- if sb == nil {
|
|
| 2284 |
- t.Fatalf("Got nil sandbox for container: %s", cid)
|
|
| 2285 |
- } |
|
| 2286 |
- |
|
| 2287 |
- for i := 0; i < iterCnt; i++ {
|
|
| 2288 |
- parallelJoin(t, sb, ep, thrNumber) |
|
| 2289 |
- parallelLeave(t, sb, ep, thrNumber) |
|
| 2290 |
- } |
|
| 2291 |
- |
|
| 2292 |
- debugf("\n")
|
|
| 2293 |
- |
|
| 2294 |
- err = sb.Delete() |
|
| 2295 |
- if err != nil {
|
|
| 2296 |
- t.Fatal(err) |
|
| 2297 |
- } |
|
| 2298 |
- if thrNumber == first {
|
|
| 2299 |
- for thrdone := range done {
|
|
| 2300 |
- select {
|
|
| 2301 |
- case <-thrdone: |
|
| 2302 |
- } |
|
| 2303 |
- } |
|
| 2304 |
- |
|
| 2305 |
- testns.Close() |
|
| 2306 |
- if err := net2.Delete(); err != nil {
|
|
| 2307 |
- t.Fatal(err) |
|
| 2308 |
- } |
|
| 2309 |
- } else {
|
|
| 2310 |
- err = ep.Delete(false) |
|
| 2311 |
- if err != nil {
|
|
| 2312 |
- t.Fatal(err) |
|
| 2313 |
- } |
|
| 2314 |
- } |
|
| 2315 |
-} |
|
| 2316 |
- |
|
| 2317 |
-func TestParallel1(t *testing.T) {
|
|
| 2318 |
- runParallelTests(t, 1) |
|
| 2319 |
-} |
|
| 2320 |
- |
|
| 2321 |
-func TestParallel2(t *testing.T) {
|
|
| 2322 |
- runParallelTests(t, 2) |
|
| 2323 |
-} |
|
| 2324 |
- |
|
| 2325 |
-func TestParallel3(t *testing.T) {
|
|
| 2326 |
- runParallelTests(t, 3) |
|
| 2327 |
-} |
|
| 2328 |
- |
|
| 2329 |
-func TestNullIpam(t *testing.T) {
|
|
| 2330 |
- _, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", "", libnetwork.NetworkOptionIpam(ipamapi.NullIPAM, "", nil, nil, nil)) |
|
| 2331 |
- if err == nil || err.Error() != "ipv4 pool is empty" {
|
|
| 2332 |
- t.Fatal("bridge network should complain empty pool")
|
|
| 2333 |
- } |
|
| 2334 |
-} |
| ... | ... |
@@ -1,13 +1,26 @@ |
| 1 |
-package netutils |
|
| 1 |
+// +build solaris |
|
| 2 | 2 |
|
| 3 |
-// Solaris: TODO |
|
| 3 |
+package netutils |
|
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "fmt" |
|
| 6 | 7 |
"net" |
| 8 |
+ "os/exec" |
|
| 9 |
+ "strings" |
|
| 7 | 10 |
|
| 8 | 11 |
"github.com/docker/libnetwork/ipamutils" |
| 12 |
+ "github.com/vishvananda/netlink" |
|
| 13 |
+) |
|
| 14 |
+ |
|
| 15 |
+var ( |
|
| 16 |
+ networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error) |
|
| 9 | 17 |
) |
| 10 | 18 |
|
| 19 |
+// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes |
|
| 20 |
+func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
|
| 21 |
+ return nil |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 11 | 24 |
// ElectInterfaceAddresses looks for an interface on the OS with the specified name |
| 12 | 25 |
// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist, |
| 13 | 26 |
// it chooses from a predifined list the first IPv4 address which does not conflict |
| ... | ... |
@@ -15,18 +28,75 @@ import ( |
| 15 | 15 |
func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
|
| 16 | 16 |
var ( |
| 17 | 17 |
v4Net *net.IPNet |
| 18 |
- err error |
|
| 19 | 18 |
) |
| 20 | 19 |
|
| 21 |
- v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) |
|
| 20 |
+ out, err := exec.Command("/usr/sbin/ipadm", "show-addr",
|
|
| 21 |
+ "-p", "-o", "addrobj,addr").Output() |
|
| 22 | 22 |
if err != nil {
|
| 23 |
+ fmt.Println("failed to list interfaces on system")
|
|
| 23 | 24 |
return nil, nil, err |
| 24 | 25 |
} |
| 26 |
+ alist := strings.Fields(string(out)) |
|
| 27 |
+ for _, a := range alist {
|
|
| 28 |
+ linkandaddr := strings.SplitN(a, ":", 2) |
|
| 29 |
+ if len(linkandaddr) != 2 {
|
|
| 30 |
+ fmt.Println("failed to check interfaces on system: ", a)
|
|
| 31 |
+ continue |
|
| 32 |
+ } |
|
| 33 |
+ gw := fmt.Sprintf("%s_gw0", name)
|
|
| 34 |
+ link := strings.Split(linkandaddr[0], "/")[0] |
|
| 35 |
+ addr := linkandaddr[1] |
|
| 36 |
+ if gw != link {
|
|
| 37 |
+ continue |
|
| 38 |
+ } |
|
| 39 |
+ _, ipnet, err := net.ParseCIDR(addr) |
|
| 40 |
+ if err != nil {
|
|
| 41 |
+ fmt.Println("failed to parse address: ", addr)
|
|
| 42 |
+ continue |
|
| 43 |
+ } |
|
| 44 |
+ v4Net = ipnet |
|
| 45 |
+ break |
|
| 46 |
+ } |
|
| 47 |
+ if v4Net == nil {
|
|
| 48 |
+ v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) |
|
| 49 |
+ if err != nil {
|
|
| 50 |
+ return nil, nil, err |
|
| 51 |
+ } |
|
| 52 |
+ } |
|
| 25 | 53 |
return v4Net, nil, nil |
| 26 | 54 |
} |
| 27 | 55 |
|
| 28 | 56 |
// FindAvailableNetwork returns a network from the passed list which does not |
| 29 | 57 |
// overlap with existing interfaces in the system |
| 30 | 58 |
func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
|
| 31 |
- return list[0], nil |
|
| 59 |
+ out, err := exec.Command("/usr/sbin/ipadm", "show-addr",
|
|
| 60 |
+ "-p", "-o", "addr").Output() |
|
| 61 |
+ |
|
| 62 |
+ if err != nil {
|
|
| 63 |
+ fmt.Println("failed to list interfaces on system")
|
|
| 64 |
+ return nil, err |
|
| 65 |
+ } |
|
| 66 |
+ ipaddrs := strings.Fields(string(out)) |
|
| 67 |
+ inuse := []*net.IPNet{}
|
|
| 68 |
+ for _, ip := range ipaddrs {
|
|
| 69 |
+ _, ipnet, err := net.ParseCIDR(ip) |
|
| 70 |
+ if err != nil {
|
|
| 71 |
+ fmt.Println("failed to check interfaces on system: ", ip)
|
|
| 72 |
+ continue |
|
| 73 |
+ } |
|
| 74 |
+ inuse = append(inuse, ipnet) |
|
| 75 |
+ } |
|
| 76 |
+ for _, avail := range list {
|
|
| 77 |
+ is_avail := true |
|
| 78 |
+ for _, ipnet := range inuse {
|
|
| 79 |
+ if NetworkOverlaps(avail, ipnet) {
|
|
| 80 |
+ is_avail = false |
|
| 81 |
+ break |
|
| 82 |
+ } |
|
| 83 |
+ } |
|
| 84 |
+ if is_avail {
|
|
| 85 |
+ return avail, nil |
|
| 86 |
+ } |
|
| 87 |
+ } |
|
| 88 |
+ return nil, fmt.Errorf("no available network")
|
|
| 32 | 89 |
} |
| 4 | 6 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,24 @@ |
| 0 |
+package osl |
|
| 1 |
+ |
|
| 2 |
+// NewSandbox provides a new sandbox instance created in an os specific way |
|
| 3 |
+// provided a key which uniquely identifies the sandbox |
|
| 4 |
+func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
|
| 5 |
+ return nil, nil |
|
| 6 |
+} |
|
| 7 |
+ |
|
| 8 |
+// GenerateKey generates a sandbox key based on the passed |
|
| 9 |
+// container id. |
|
| 10 |
+func GenerateKey(containerID string) string {
|
|
| 11 |
+ maxLen := 12 |
|
| 12 |
+ |
|
| 13 |
+ if len(containerID) < maxLen {
|
|
| 14 |
+ maxLen = len(containerID) |
|
| 15 |
+ } |
|
| 16 |
+ |
|
| 17 |
+ return containerID[:maxLen] |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+// InitOSContext initializes OS context while configuring network resources |
|
| 21 |
+func InitOSContext() func() {
|
|
| 22 |
+ return func() {}
|
|
| 23 |
+} |
| ... | ... |
@@ -1,11 +1,9 @@ |
| 1 | 1 |
package portallocator |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "bufio" |
|
| 5 | 4 |
"errors" |
| 6 | 5 |
"fmt" |
| 7 | 6 |
"net" |
| 8 |
- "os" |
|
| 9 | 7 |
"sync" |
| 10 | 8 |
) |
| 11 | 9 |
|
| ... | ... |
@@ -106,26 +104,6 @@ func newInstance() *PortAllocator {
|
| 106 | 106 |
} |
| 107 | 107 |
} |
| 108 | 108 |
|
| 109 |
-func getDynamicPortRange() (start int, end int, err error) {
|
|
| 110 |
- const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range" |
|
| 111 |
- portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
|
|
| 112 |
- file, err := os.Open(portRangeKernelParam) |
|
| 113 |
- if err != nil {
|
|
| 114 |
- return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)
|
|
| 115 |
- } |
|
| 116 |
- |
|
| 117 |
- defer file.Close() |
|
| 118 |
- |
|
| 119 |
- n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end) |
|
| 120 |
- if n != 2 || err != nil {
|
|
| 121 |
- if err == nil {
|
|
| 122 |
- err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
|
|
| 123 |
- } |
|
| 124 |
- return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err)
|
|
| 125 |
- } |
|
| 126 |
- return start, end, nil |
|
| 127 |
-} |
|
| 128 |
- |
|
| 129 | 109 |
// RequestPort requests new port from global ports pool for specified ip and proto. |
| 130 | 110 |
// If port is 0 it returns first free port. Otherwise it checks port availability |
| 131 | 111 |
// in proto's pool and returns that port or error if port is already busy. |
| 132 | 112 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,27 @@ |
| 0 |
+package portallocator |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bufio" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "os" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func getDynamicPortRange() (start int, end int, err error) {
|
|
| 9 |
+ const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range" |
|
| 10 |
+ portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
|
|
| 11 |
+ file, err := os.Open(portRangeKernelParam) |
|
| 12 |
+ if err != nil {
|
|
| 13 |
+ return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)
|
|
| 14 |
+ } |
|
| 15 |
+ |
|
| 16 |
+ defer file.Close() |
|
| 17 |
+ |
|
| 18 |
+ n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end) |
|
| 19 |
+ if n != 2 || err != nil {
|
|
| 20 |
+ if err == nil {
|
|
| 21 |
+ err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
|
|
| 22 |
+ } |
|
| 23 |
+ return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err)
|
|
| 24 |
+ } |
|
| 25 |
+ return start, end, nil |
|
| 26 |
+} |
| ... | ... |
@@ -7,8 +7,6 @@ import ( |
| 7 | 7 |
"net" |
| 8 | 8 |
"os" |
| 9 | 9 |
"os/exec" |
| 10 |
- "strconv" |
|
| 11 |
- "syscall" |
|
| 12 | 10 |
"time" |
| 13 | 11 |
) |
| 14 | 12 |
|
| ... | ... |
@@ -25,36 +23,6 @@ type proxyCommand struct {
|
| 25 | 25 |
cmd *exec.Cmd |
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
-func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
|
|
| 29 |
- path := proxyPath |
|
| 30 |
- if proxyPath == "" {
|
|
| 31 |
- cmd, err := exec.LookPath(userlandProxyCommandName) |
|
| 32 |
- if err != nil {
|
|
| 33 |
- return nil, err |
|
| 34 |
- } |
|
| 35 |
- path = cmd |
|
| 36 |
- } |
|
| 37 |
- |
|
| 38 |
- args := []string{
|
|
| 39 |
- path, |
|
| 40 |
- "-proto", proto, |
|
| 41 |
- "-host-ip", hostIP.String(), |
|
| 42 |
- "-host-port", strconv.Itoa(hostPort), |
|
| 43 |
- "-container-ip", containerIP.String(), |
|
| 44 |
- "-container-port", strconv.Itoa(containerPort), |
|
| 45 |
- } |
|
| 46 |
- |
|
| 47 |
- return &proxyCommand{
|
|
| 48 |
- cmd: &exec.Cmd{
|
|
| 49 |
- Path: path, |
|
| 50 |
- Args: args, |
|
| 51 |
- SysProcAttr: &syscall.SysProcAttr{
|
|
| 52 |
- Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies |
|
| 53 |
- }, |
|
| 54 |
- }, |
|
| 55 |
- }, nil |
|
| 56 |
-} |
|
| 57 |
- |
|
| 58 | 28 |
func (p *proxyCommand) Start() error {
|
| 59 | 29 |
r, w, err := os.Pipe() |
| 60 | 30 |
if err != nil {
|
| 61 | 31 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,38 @@ |
| 0 |
+package portmapper |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net" |
|
| 4 |
+ "os/exec" |
|
| 5 |
+ "strconv" |
|
| 6 |
+ "syscall" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
|
|
| 10 |
+ path := proxyPath |
|
| 11 |
+ if proxyPath == "" {
|
|
| 12 |
+ cmd, err := exec.LookPath(userlandProxyCommandName) |
|
| 13 |
+ if err != nil {
|
|
| 14 |
+ return nil, err |
|
| 15 |
+ } |
|
| 16 |
+ path = cmd |
|
| 17 |
+ } |
|
| 18 |
+ |
|
| 19 |
+ args := []string{
|
|
| 20 |
+ path, |
|
| 21 |
+ "-proto", proto, |
|
| 22 |
+ "-host-ip", hostIP.String(), |
|
| 23 |
+ "-host-port", strconv.Itoa(hostPort), |
|
| 24 |
+ "-container-ip", containerIP.String(), |
|
| 25 |
+ "-container-port", strconv.Itoa(containerPort), |
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 28 |
+ return &proxyCommand{
|
|
| 29 |
+ cmd: &exec.Cmd{
|
|
| 30 |
+ Path: path, |
|
| 31 |
+ Args: args, |
|
| 32 |
+ SysProcAttr: &syscall.SysProcAttr{
|
|
| 33 |
+ Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies |
|
| 34 |
+ }, |
|
| 35 |
+ }, |
|
| 36 |
+ }, nil |
|
| 37 |
+} |
| 0 | 38 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,34 @@ |
| 0 |
+package portmapper |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net" |
|
| 4 |
+ "os/exec" |
|
| 5 |
+ "strconv" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
|
|
| 9 |
+ path := proxyPath |
|
| 10 |
+ if proxyPath == "" {
|
|
| 11 |
+ cmd, err := exec.LookPath(userlandProxyCommandName) |
|
| 12 |
+ if err != nil {
|
|
| 13 |
+ return nil, err |
|
| 14 |
+ } |
|
| 15 |
+ path = cmd |
|
| 16 |
+ } |
|
| 17 |
+ |
|
| 18 |
+ args := []string{
|
|
| 19 |
+ path, |
|
| 20 |
+ "-proto", proto, |
|
| 21 |
+ "-host-ip", hostIP.String(), |
|
| 22 |
+ "-host-port", strconv.Itoa(hostPort), |
|
| 23 |
+ "-container-ip", containerIP.String(), |
|
| 24 |
+ "-container-port", strconv.Itoa(containerPort), |
|
| 25 |
+ } |
|
| 26 |
+ |
|
| 27 |
+ return &proxyCommand{
|
|
| 28 |
+ cmd: &exec.Cmd{
|
|
| 29 |
+ Path: path, |
|
| 30 |
+ Args: args, |
|
| 31 |
+ }, |
|
| 32 |
+ }, nil |
|
| 33 |
+} |
| 0 | 34 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,45 @@ |
| 0 |
+package libnetwork |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "os" |
|
| 4 |
+ "testing" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/libkv/store" |
|
| 7 |
+ "github.com/docker/libnetwork/datastore" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func TestBoltdbBackend(t *testing.T) {
|
|
| 11 |
+ defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address)
|
|
| 12 |
+ testLocalBackend(t, "", "", nil) |
|
| 13 |
+ defer os.Remove("/tmp/boltdb.db")
|
|
| 14 |
+ config := &store.Config{Bucket: "testBackend"}
|
|
| 15 |
+ testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config) |
|
| 16 |
+ |
|
| 17 |
+} |
|
| 18 |
+ |
|
| 19 |
+func TestNoPersist(t *testing.T) {
|
|
| 20 |
+ cfgOptions, err := OptionBoltdbWithRandomDBFile() |
|
| 21 |
+ if err != nil {
|
|
| 22 |
+ t.Fatalf("Error creating random boltdb file : %v", err)
|
|
| 23 |
+ } |
|
| 24 |
+ ctrl, err := New(cfgOptions...) |
|
| 25 |
+ if err != nil {
|
|
| 26 |
+ t.Fatalf("Error new controller: %v", err)
|
|
| 27 |
+ } |
|
| 28 |
+ nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false))
|
|
| 29 |
+ if err != nil {
|
|
| 30 |
+ t.Fatalf("Error creating default \"host\" network: %v", err)
|
|
| 31 |
+ } |
|
| 32 |
+ ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...)
|
|
| 33 |
+ if err != nil {
|
|
| 34 |
+ t.Fatalf("Error creating endpoint: %v", err)
|
|
| 35 |
+ } |
|
| 36 |
+ store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore() |
|
| 37 |
+ if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists {
|
|
| 38 |
+ t.Fatalf("Network with persist=false should not be stored in KV Store")
|
|
| 39 |
+ } |
|
| 40 |
+ if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists {
|
|
| 41 |
+ t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store")
|
|
| 42 |
+ } |
|
| 43 |
+ store.Close() |
|
| 44 |
+} |
| ... | ... |
@@ -3,7 +3,6 @@ package libnetwork |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"io/ioutil" |
| 6 |
- "os" |
|
| 7 | 6 |
"testing" |
| 8 | 7 |
|
| 9 | 8 |
"github.com/docker/libkv/store" |
| ... | ... |
@@ -31,15 +30,6 @@ func testNewController(t *testing.T, provider, url string) (NetworkController, e |
| 31 | 31 |
return New(cfgOptions...) |
| 32 | 32 |
} |
| 33 | 33 |
|
| 34 |
-func TestBoltdbBackend(t *testing.T) {
|
|
| 35 |
- defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address)
|
|
| 36 |
- testLocalBackend(t, "", "", nil) |
|
| 37 |
- defer os.Remove("/tmp/boltdb.db")
|
|
| 38 |
- config := &store.Config{Bucket: "testBackend"}
|
|
| 39 |
- testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config) |
|
| 40 |
- |
|
| 41 |
-} |
|
| 42 |
- |
|
| 43 | 34 |
func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Config) {
|
| 44 | 35 |
cfgOptions := []config.Option{}
|
| 45 | 36 |
cfgOptions = append(cfgOptions, config.OptionLocalKVProvider(provider)) |
| ... | ... |
@@ -82,33 +72,6 @@ func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Con |
| 82 | 82 |
} |
| 83 | 83 |
} |
| 84 | 84 |
|
| 85 |
-func TestNoPersist(t *testing.T) {
|
|
| 86 |
- cfgOptions, err := OptionBoltdbWithRandomDBFile() |
|
| 87 |
- if err != nil {
|
|
| 88 |
- t.Fatalf("Error creating random boltdb file : %v", err)
|
|
| 89 |
- } |
|
| 90 |
- ctrl, err := New(cfgOptions...) |
|
| 91 |
- if err != nil {
|
|
| 92 |
- t.Fatalf("Error new controller: %v", err)
|
|
| 93 |
- } |
|
| 94 |
- nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false))
|
|
| 95 |
- if err != nil {
|
|
| 96 |
- t.Fatalf("Error creating default \"host\" network: %v", err)
|
|
| 97 |
- } |
|
| 98 |
- ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...)
|
|
| 99 |
- if err != nil {
|
|
| 100 |
- t.Fatalf("Error creating endpoint: %v", err)
|
|
| 101 |
- } |
|
| 102 |
- store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore() |
|
| 103 |
- if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists {
|
|
| 104 |
- t.Fatalf("Network with persist=false should not be stored in KV Store")
|
|
| 105 |
- } |
|
| 106 |
- if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists {
|
|
| 107 |
- t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store")
|
|
| 108 |
- } |
|
| 109 |
- store.Close() |
|
| 110 |
-} |
|
| 111 |
- |
|
| 112 | 85 |
// OptionBoltdbWithRandomDBFile function returns a random dir for local store backend |
| 113 | 86 |
func OptionBoltdbWithRandomDBFile() ([]config.Option, error) {
|
| 114 | 87 |
tmp, err := ioutil.TempFile("", "libnetwork-")
|
| 115 | 88 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,25 @@ |
| 0 |
+// +build solaris |
|
| 1 |
+ |
|
| 2 |
+package testutils |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "os" |
|
| 6 |
+ "testing" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// SetupTestOSContext joins a new network namespace, and returns its associated |
|
| 10 |
+// teardown function. |
|
| 11 |
+// |
|
| 12 |
+// Example usage: |
|
| 13 |
+// |
|
| 14 |
+// defer SetupTestOSContext(t)() |
|
| 15 |
+// |
|
| 16 |
+func SetupTestOSContext(t *testing.T) func() {
|
|
| 17 |
+ return func() {
|
|
| 18 |
+ } |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+// RunningOnCircleCI returns true if being executed on libnetwork Circle CI setup |
|
| 22 |
+func RunningOnCircleCI() bool {
|
|
| 23 |
+ return os.Getenv("CIRCLECI") != ""
|
|
| 24 |
+} |