Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle ip route showing mask-less IP addresses #1374

Merged
merged 3 commits into from Aug 5, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 25 additions & 12 deletions network.go
Expand Up @@ -93,20 +93,29 @@ func iptables(args ...string) error {
return nil
}

func checkRouteOverlaps(dockerNetwork *net.IPNet) error {
output, err := ip("route")
if err != nil {
return err
}
utils.Debugf("Routes:\n\n%s", output)
for _, line := range strings.Split(output, "\n") {
func checkRouteOverlaps(routes string, dockerNetwork *net.IPNet) error {
utils.Debugf("Routes:\n\n%s", routes)
for _, line := range strings.Split(routes, "\n") {
if strings.Trim(line, "\r\n\t ") == "" || strings.Contains(line, "default") {
continue
}
if _, network, err := net.ParseCIDR(strings.Split(line, " ")[0]); err != nil {
return fmt.Errorf("Unexpected ip route output: %s (%s)", err, line)
} else if networkOverlaps(dockerNetwork, network) {
return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork.String(), line)
_, network, err := net.ParseCIDR(strings.Split(line, " ")[0])
if err != nil {
// is this a mask-less IP address?
if ip := net.ParseIP(strings.Split(line, " ")[0]); ip == nil {
// fail only if it's neither a network nor a mask-less IP address
return fmt.Errorf("Unexpected ip route output: %s (%s)", err, line)
} else {
_, network, err = net.ParseCIDR(ip.String() + "/32")
if err != nil {
return err
}
}
}
if err == nil && network != nil {
if networkOverlaps(dockerNetwork, network) {
return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork, line)
}
}
}
return nil
Expand Down Expand Up @@ -142,7 +151,11 @@ func CreateBridgeIface(ifaceName string) error {
if err != nil {
return err
}
if err := checkRouteOverlaps(dockerNetwork); err == nil {
routes, err := ip("route")
if err != nil {
return err
}
if err := checkRouteOverlaps(routes, dockerNetwork); err == nil {
ifaceAddr = addr
break
} else {
Expand Down
19 changes: 19 additions & 0 deletions network_test.go
Expand Up @@ -383,3 +383,22 @@ func TestNetworkOverlaps(t *testing.T) {
//netX starts and ends before netY
AssertNoOverlap("172.16.1.1/25", "172.16.2.1/24", t)
}

func TestCheckRouteOverlaps(t *testing.T) {
routes := `default via 10.0.2.2 dev eth0
10.0.2.0 dev eth0 proto kernel scope link src 10.0.2.15
10.0.3.0/24 dev lxcbr0 proto kernel scope link src 10.0.3.1
10.0.42.0/24 dev testdockbr0 proto kernel scope link src 10.0.42.1
172.16.42.0/24 dev docker0 proto kernel scope link src 172.16.42.1
192.168.142.0/24 dev eth1 proto kernel scope link src 192.168.142.142`

_, netX, _ := net.ParseCIDR("172.16.0.1/24")
if err := checkRouteOverlaps(routes, netX); err != nil {
t.Fatal(err)
}

_, netX, _ = net.ParseCIDR("10.0.2.0/24")
if err := checkRouteOverlaps(routes, netX); err == nil {
t.Fatalf("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't")
}
}
4 changes: 4 additions & 0 deletions testing/README.rst
Expand Up @@ -40,6 +40,10 @@ Deployment
export SMTP_USER=xxxxxxxxxxxx
export SMTP_PWD=xxxxxxxxxxxx

# Define docker registry functional test credentials
export REGISTRY_USER=xxxxxxxxxxxx
export REGISTRY_PWD=xxxxxxxxxxxx

# Checkout docker
git clone git://github.com/dotcloud/docker.git

Expand Down
4 changes: 3 additions & 1 deletion testing/Vagrantfile
Expand Up @@ -29,7 +29,9 @@ Vagrant::Config.run do |config|
"chown #{USER}.#{USER} /data; cd /data; " \
"#{CFG_PATH}/setup.sh #{USER} #{CFG_PATH} #{ENV['BUILDBOT_PWD']} " \
"#{ENV['IRC_PWD']} #{ENV['IRC_CHANNEL']} #{ENV['SMTP_USER']} " \
"#{ENV['SMTP_PWD']} #{ENV['EMAIL_RCP']}; "
"#{ENV['SMTP_PWD']} #{ENV['EMAIL_RCP']}; " \
"#{CFG_PATH}/setup_credentials.sh #{USER} " \
"#{ENV['REGISTRY_USER']} #{ENV['REGISTRY_PWD']}; "
# Install docker dependencies
pkg_cmd << "apt-get install -q -y python-software-properties; " \
"add-apt-repository -y ppa:dotcloud/docker-golang/ubuntu; apt-get update -qq; " \
Expand Down
5 changes: 5 additions & 0 deletions testing/buildbot/credentials.cfg
@@ -0,0 +1,5 @@
# Credentials for tests. Buildbot source this file on tests
# when needed.

# Docker registry credentials. Format: 'username:password'
export DOCKER_CREDS=''
20 changes: 18 additions & 2 deletions testing/buildbot/master.cfg
Expand Up @@ -19,6 +19,7 @@ TEST_USER = 'buildbot' # Credential to authenticate build triggers
TEST_PWD = 'docker' # Credential to authenticate build triggers
BUILDER_NAME = 'docker'
GITHUB_DOCKER = 'github.com/dotcloud/docker'
BUILDBOT_PATH = '/data/buildbot'
DOCKER_PATH = '/data/docker'
BUILDER_PATH = '/data/buildbot/slave/{0}/build'.format(BUILDER_NAME)
DOCKER_BUILD_PATH = BUILDER_PATH + '/src/github.com/dotcloud/docker'
Expand All @@ -41,23 +42,27 @@ c['db'] = {'db_url':"sqlite:///state.sqlite"}
c['slaves'] = [BuildSlave('buildworker', BUILDBOT_PWD)]
c['slavePortnum'] = PORT_MASTER


# Schedulers
c['schedulers'] = [ForceScheduler(name='trigger', builderNames=[BUILDER_NAME,
'coverage'])]
'registry','coverage'])]
c['schedulers'] += [SingleBranchScheduler(name="all",
change_filter=filter.ChangeFilter(branch='master'), treeStableTimer=None,
builderNames=[BUILDER_NAME])]
c['schedulers'] += [Nightly(name='daily', branch=None, builderNames=['coverage'],
c['schedulers'] += [Nightly(name='daily', branch=None, builderNames=['coverage','registry'],
hour=0, minute=30)]


# Builders
# Docker commit test
factory = BuildFactory()
factory.addStep(ShellCommand(description='Docker',logEnviron=False,usePTY=True,
command=["sh", "-c", Interpolate("cd ..; rm -rf build; export GOPATH={0}; "
"go get -d {1}; cd {2}; git reset --hard %(src::revision:-unknown)s; "
"go test -v".format(BUILDER_PATH,GITHUB_DOCKER,DOCKER_BUILD_PATH))]))
c['builders'] = [BuilderConfig(name=BUILDER_NAME,slavenames=['buildworker'],
factory=factory)]

# Docker coverage test
coverage_cmd = ('GOPATH=`pwd` go get -d github.com/dotcloud/docker\n'
'GOPATH=`pwd` go get github.com/axw/gocov/gocov\n'
Expand All @@ -69,6 +74,17 @@ factory.addStep(ShellCommand(description='Coverage',logEnviron=False,usePTY=True
c['builders'] += [BuilderConfig(name='coverage',slavenames=['buildworker'],
factory=factory)]

# Registry Functionaltest builder
factory = BuildFactory()
factory.addStep(ShellCommand(description='registry', logEnviron=False,
command='. {0}/master/credentials.cfg; '
'{1}/testing/functionaltests/test_registry.sh'.format(BUILDBOT_PATH,
DOCKER_PATH), usePTY=True))

c['builders'] += [BuilderConfig(name='registry',slavenames=['buildworker'],
factory=factory)]


# Status
authz_cfg = authz.Authz(auth=auth.BasicAuth([(TEST_USER, TEST_PWD)]),
forceBuild='auth')
Expand Down
1 change: 1 addition & 0 deletions testing/buildbot/requirements.txt
Expand Up @@ -4,3 +4,4 @@ buildbot==0.8.7p1
buildbot_slave==0.8.7p1
nose==1.2.1
requests==1.1.0
flask==0.10.1
17 changes: 17 additions & 0 deletions testing/buildbot/setup_credentials.sh
@@ -0,0 +1,17 @@
#!/bin/bash

# Setup of test credentials. Called by Vagrantfile
export PATH="/bin:sbin:/usr/bin:/usr/sbin:/usr/local/bin"

USER=$1
REGISTRY_USER=$2
REGISTRY_PWD=$3

BUILDBOT_PATH="/data/buildbot"
DOCKER_PATH="/data/docker"

function run { su $USER -c "$1"; }

run "cp $DOCKER_PATH/testing/buildbot/credentials.cfg $BUILDBOT_PATH/master"
cd $BUILDBOT_PATH/master
run "sed -i -E 's#(export DOCKER_CREDS=).+#\1\"$REGISTRY_USER:$REGISTRY_PWD\"#' credentials.cfg"
11 changes: 11 additions & 0 deletions testing/functionaltests/test_registry.sh
@@ -0,0 +1,11 @@
#!/bin/sh

# Cleanup
rm -rf docker-registry

# Get latest docker registry
git clone https://github.com/dotcloud/docker-registry.git

# Configure and run registry tests
cd docker-registry; cp config_sample.yml config.yml
cd test; python -m unittest workflow