mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Gracefully handle network bridge without IP association at startup
Addresses #8444 Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
This commit is contained in:
parent
77dcab133c
commit
1262b5f605
2 changed files with 49 additions and 7 deletions
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -104,8 +105,8 @@ func InitDriver(job *engine.Job) engine.Status {
|
|||
if !usingDefaultBridge {
|
||||
return job.Error(err)
|
||||
}
|
||||
// If the iface is not found, try to create it
|
||||
if err := createBridge(bridgeIP); err != nil {
|
||||
// If the bridge interface is not found (or has no address), try to create it and/or add an address
|
||||
if err := configureBridge(bridgeIP); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
|
@ -251,10 +252,12 @@ func setupIPTables(addr net.Addr, icc, ipmasq bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
|
||||
// and attempts to configure it with an address which doesn't conflict with any other interface on the host.
|
||||
// If it can't find an address which doesn't conflict, it will return an error.
|
||||
func createBridge(bridgeIP string) error {
|
||||
// configureBridge attempts to create and configure a network bridge interface named `ifaceName` on the host
|
||||
// If bridgeIP is empty, it will try to find a non-conflicting IP from the Docker-specified private ranges
|
||||
// If the bridge `ifaceName` already exists, it will only perform the IP address association with the existing
|
||||
// bridge (fixes issue #8444)
|
||||
// If an address which doesn't conflict with existing interfaces can't be found, an error is returned.
|
||||
func configureBridge(bridgeIP string) error {
|
||||
nameservers := []string{}
|
||||
resolvConf, _ := resolvconf.Get()
|
||||
// we don't check for an error here, because we don't really care
|
||||
|
@ -295,7 +298,10 @@ func createBridge(bridgeIP string) error {
|
|||
log.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
|
||||
|
||||
if err := createBridgeIface(bridgeIface); err != nil {
|
||||
return err
|
||||
// the bridge may already exist, therefore we can ignore an "exists" error
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(bridgeIface)
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
@ -92,3 +93,38 @@ func TestDaemonStartIptablesFalse(t *testing.T) {
|
|||
|
||||
logDone("daemon - started daemon with iptables=false")
|
||||
}
|
||||
|
||||
// Issue #8444: If docker0 bridge is modified (intentionally or unintentionally) and
|
||||
// no longer has an IP associated, we should gracefully handle that case and associate
|
||||
// an IP with it rather than fail daemon start
|
||||
func TestDaemonStartBridgeWithoutIPAssociation(t *testing.T) {
|
||||
d := NewDaemon(t)
|
||||
// rather than depending on brctl commands to verify docker0 is created and up
|
||||
// let's start the daemon and stop it, and then make a modification to run the
|
||||
// actual test
|
||||
if err := d.Start(); err != nil {
|
||||
t.Fatalf("Could not start daemon: %v", err)
|
||||
}
|
||||
if err := d.Stop(); err != nil {
|
||||
t.Fatalf("Could not stop daemon: %v", err)
|
||||
}
|
||||
|
||||
// now we will remove the ip from docker0 and then try starting the daemon
|
||||
ipCmd := exec.Command("ip", "addr", "flush", "dev", "docker0")
|
||||
stdout, stderr, _, err := runCommandWithStdoutStderr(ipCmd)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to remove docker0 IP association: %v, stdout: %q, stderr: %q", err, stdout, stderr)
|
||||
}
|
||||
|
||||
if err := d.Start(); err != nil {
|
||||
warning := "**WARNING: Docker bridge network in bad state--delete docker0 bridge interface to fix"
|
||||
t.Fatalf("Could not start daemon when docker0 has no IP address: %v\n%s", err, warning)
|
||||
}
|
||||
|
||||
// cleanup - stop the daemon if test passed
|
||||
if err := d.Stop(); err != nil {
|
||||
t.Fatalf("Could not stop daemon: %v", err)
|
||||
}
|
||||
|
||||
logDone("daemon - successful daemon start when bridge has no IP association")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue