Compare commits

...
1885 Commits
Author SHA1 Message Date
Bryan Boreham 851b58cca8 Add release v1.9.0 2017-02-02 11:01:34 +00:00
Bryan Boreham cb48ebc399 Bump alpine version to 3.5 for arm64
Since 3.4 doesn't exist, and the package repo seems ok for ulogd now
2017-02-02 10:43:29 +00:00
Martynas Pumputis 5278eb7ebc Merge pull request #2747 from weaveworks/issues/2689-npc-mcast-simple
Add rule to allow multicast at top level
2017-02-01 18:20:38 +00:00
Bryan Boreham 418c256689 Allow traffic to forward off the weave bridge 2017-02-01 15:01:18 +00:00
Bryan Boreham 4eeb846507 Add tests for connectivity to the world 2017-02-01 15:01:18 +00:00
Bryan Boreham 7529f5f9af Raise ping timeout to reduce false negatives 2017-02-01 15:01:18 +00:00
Michal Rostecki 8506e57482 Pin alpine container version
Alpine 3.5 doesn't provide PCAP plugin with ulogd, so until
we investigate the problem upstream, we need to pin to 3.4
version.

Fixes #2732
2017-02-01 12:05:31 +00:00
Adam Harrison b1d09305e4 Merge pull request #2687 from weaveworks/issues/1644-fastdp-crypto
Fastdp crypto
2017-02-01 10:28:24 +00:00
Martynas Pumputis 07892bff7d Reduce the default MTU 2017-01-31 17:21:01 +00:00
Martynas Pumputis 50985dee90 Enable ESN in fastdp-crypto 2017-01-31 17:21:01 +00:00
Martynas Pumputis 60323d0960 Add fastdp crypto 2017-01-31 17:21:01 +00:00
Bryan Boreham a9cef6327f Update information about Weaveworks products 2017-01-31 12:43:53 +00:00
Bryan Boreham fdeb9010ba Merge pull request #2757 from weaveworks/upgrade-build-tools
Upgrade to latest 'common' and 'build-tools'.
2017-01-31 12:17:31 +00:00
Marc CARRE ee659d4033 Replace weave/common/mflagext with common/mflagext.
Removes duplication between weave and common and reduces the amount of sources to compile.
2017-01-31 10:49:29 +00:00
Marc CARRE 8f9b2a36c0 Remove dep. on docker and use mflag from common.
This reduces the number of dependencies, and avoids having docker as a vendored dependency, which should speed the build up.
2017-01-31 10:30:12 +00:00
Bryan Boreham 6a83130685 Document multicast behaviour of weave-npc 2017-01-30 18:14:57 +00:00
Marc CARRE 77e6c6f886 Upgrade to latest 'common' and 'build-tools'.
If building against the latest 'build-tools', you would typically get:
tools/runner/runner.go:18:2: cannot find package github.com/weaveworks/common/mflag
This change fixes the issue by upgrading both dependencies.
2017-01-30 18:05:58 +00:00
Adam Harrison 8a5a15d5e9 Merge pull request #2753 from weaveworks/mv-signal-to-common
Move signal handling loop to common.
2017-01-30 12:38:23 +00:00
Bryan Boreham bcc8c73f59 Fix build of manifest_tool in 'make publish' 2017-01-30 11:02:11 +00:00
Bryan Boreham e22c6375c9 Fix build of manifest_tool 2017-01-27 18:09:22 +00:00
Marc Carré 22ae0d200c Merge pull request #2752 from weaveworks/makefile-cleanup
Makefile cleanup after multiarch merge
2017-01-27 16:51:44 +00:00
Bryan Boreham 7231bd00f8 Remove .weavedb.uptodate file when we remove the weavedb image in 'make clean-bin' 2017-01-27 16:26:05 +00:00
Tom Wilkie 590a151bde Move signal handling loop to common. 2017-01-26 17:55:19 +00:00
Martynas Pumputis f5dfefef75 Merge pull request #2749 from weaveworks/shfmt-ignore
Upgrade Weave Net to latest version of build-tools, skipping bash scripts when lint-ing.
2017-01-26 10:55:36 +00:00
Marc CARRE 8e6cb5e24d Print files we currently do not lint.
Makes what the build does explicitly and helps for potential debugging.
Also reminds us that we are skipping these files, so that we ultimately shfmt them and stop lint-ignoring them.
2017-01-25 17:14:48 +00:00
Marc CARRE ed629d420d Pass additional options to ./tools/test to revert to previous behaviour.
Previous commit upgrades Weave Net to the latest version of `build-tools`.
However, `./tools/test`'s default behaviour has changed, so we need to explicitly pass new options/arguments, in order to keep it behaving like before fd568682c3.
2017-01-25 17:14:05 +00:00
Marc CARRE fd568682c3 Upgrade Weave Net to latest version of build-tools, skipping bash scripts when lint-ing.
Lint-ing all of Weave Net is currently not desirable because:

* it would create conflicts on many branches,
* it would pollute the git history,
* etc.

and because `lint` currently lints all files except `./vendor`, this breaks Weave Net's build.
As a result, Weave Net is not using the latest commit in `build-tools`'s `master` branch, which is also source of problems:

* it limits standardisation of projects across Weaveworks,
* it limits the ability to use the latest features of `build-tools`,
* it complexifies merging changes in `build-tools` (e.g. #53 and weaveworks/weave#2694 for weaveworks/weave#2647),
* etc.

This change:

* brings Weave Net to the latest version of `build-tools` (which now supports `.lintignore` files),
* adds such a `.lintignore` file to skip all bash scripts (in order to avoid breaking the build).

`GLOB`s in `.lintignore` can then, over time and as scripts are `shfmt`-ed, be relaxed and maybe even removed.
2017-01-25 16:50:32 +00:00
Bryan Boreham dbb9849b8c Remove whitespace from blank lines and comment lines
Principally because emacs complains about it, but also to remove the
overhead of firing up a shell process to ignore a comment in a recipe
2017-01-25 14:20:54 +00:00
Bryan Boreham 776af44782 Make manifest-tool using weave build container 2017-01-25 14:18:55 +00:00
Bryan Boreham 69dacd0594 Restrict CircleCI publishing to AMD64 2017-01-25 10:52:53 +00:00
Bryan Boreham f17a2a00b1 Merge pull request #2713 from luxaslabs/multiarch
Make Weave Net multi-architecture
2017-01-24 18:07:32 +00:00
Lucas Käldström 1a64420e01 Fix duplicate publish target 2017-01-24 17:38:44 +02:00
Bryan Boreham 49b9a2c8df Bump Docker to 1.10 2017-01-24 17:28:08 +02:00
Bryan Boreham 6c251417d5 Update 'docker inspect weavedb' format for Docker 1.10 2017-01-24 17:27:53 +02:00
Lucas Käldström 8c0c38c8b3 Add manifest-tool as a submodule 2017-01-24 17:27:30 +02:00
Lucas Käldström 29eee4e858 Fixing review feedback, adding checksums, etc 2017-01-24 17:24:04 +02:00
Lucas Käldström 454c6f713d Make Weave Net multi-architecture and add support for ARM and ARM 64-bit 2017-01-24 17:23:00 +02:00
Marc Carré dd715e18ec Merge pull request #2743 from weaveworks/fix-uuid
Don't fail if only half the system IDs are blank
2017-01-23 15:00:06 +00:00
Bryan Boreham f067c7d44e Add rule to allow multicast at top level 2017-01-23 12:11:44 +00:00
Bryan Boreham c1023eaf18 Hard-code repository name for weavebuild container
so we don't create a new one when testing publish to different DOCKERHUB_USER
2017-01-20 14:55:10 +00:00
Bryan Boreham b091f59311 Merge pull request #2734 from Compositional/master
Add partial support for non-FHS host systems
2017-01-20 14:45:33 +00:00
Marc Carré f98ad822e3 Merge pull request #2740 from weaveworks/issues/2738-dedupe-surrogate
Update mesh lib to break cycle of old gossip
2017-01-20 12:36:08 +00:00
Bryan Boreham 917c1ddbad Update mesh lib to break cycle of old gossip 2017-01-20 12:05:55 +00:00
Marc Carré d81d2f691d Merge pull request #2742 from weaveworks/build-improvements
Build improvements
2017-01-20 11:26:18 +00:00
Bryan Boreham 1ad118a38f Merge branch '1.8' 2017-01-20 09:45:13 +00:00
Bryan Boreham 9d1648cee7 Merge pull request #2741 from weaveworks/document-mtu-with-weave-kube
Document WEAVE_MTU in weave-kube config options
2017-01-20 09:40:57 +00:00
Bryan Boreham 929167366a Don't fail if only half the system IDs are blank 2017-01-19 15:57:21 +00:00
Bryan Boreham 353ccf5e6c Move build to 'dependencies' section
This means we don't spend time trying to run other tests if the build failed.
2017-01-19 10:59:16 +00:00
Bryan Boreham cfc1fa4fae Build test runner inside build container for consistency 2017-01-19 10:59:04 +00:00
Robert Hensing d881f47088 Add partial support for non-FHS host systems
Fixes weaveworks/weave#2733 partially, where <host>/etc/resolv.conf is not a
symlink
2017-01-18 23:28:49 +01:00
Bryan Boreham 84013c4452 Merge pull request #2735 from weaveworks/issues/2732-pin-alpine-version
Pin alpine container version
2017-01-18 16:49:04 +00:00
Adam Harrison d9dc1a988c Document WEAVE_MTU in weave-kube config options 2017-01-18 15:11:41 +00:00
Marc CARRE 5fd14348aa Fix broken link to 'Building Weave Net' documentation. 2017-01-17 17:49:17 +00:00
Adam Harrison 57a250a20b Pin alpine container version 2017-01-16 12:27:53 +00:00
Adam Harrison 81add75258 Merge pull request #2711 from weaveworks/issues/2427-unique-ids
Better machine unique IDs
2017-01-13 09:40:18 +00:00
Bryan Boreham 0145282a10 Merge pull request #2728 from weaveworks/issues/2653-ulogd-pdeathsig
SIGKILL ulogd on weave-npc exit
2017-01-11 17:31:18 +00:00
Adam Harrison ae0cb5d483 SIGKILL ulogd on weave-npc exit 2017-01-11 14:12:01 +00:00
Bryan Boreham e7eeecd762 Smoke test for peer names 2017-01-11 13:14:35 +00:00
Bryan Boreham 7d308a4ac5 Wire weaveutil unique-id into weave script
Also ensure the right host directories are mounted when create-bridge
is called from either the weave script or weave-kube.
2017-01-11 13:14:35 +00:00
Bryan Boreham ebcb7f6108 Use persisted peer name if it matches old-style ID 2017-01-11 13:14:35 +00:00
Bryan Boreham e03c7b1b7c Allow opening persistence file read-only 2017-01-11 13:13:19 +00:00
Bryan Boreham 70a20b4d26 Generate peer name / mac address in Go 2017-01-11 13:12:30 +00:00
Bryan Boreham d143470d77 Refactor: extract db filename to a constant 2017-01-11 13:05:25 +00:00
Bryan Boreham 30d6639a98 Refactor: move peer name identifier to DB package 2017-01-11 13:05:25 +00:00
Adam Harrison 92cfd3b4f9 Merge pull request #2725 from weaveworks/update-tools
Update tools submodule to avoid breaking on missing Docker mflag
2017-01-09 17:09:53 +00:00
Adam Harrison 7659ea21c7 Merge branch '1.8'
Fixes #2693.
2017-01-09 16:24:08 +00:00
Adam Harrison 4e740736e7 Merge pull request #2697 from weaveworks/issues/2693-npc-log-instructions
Fix instructions to view npc logs when >1 pod exists
2017-01-09 16:23:42 +00:00
Adam Harrison 4f44d9e25a Merge branch '1.8'
Fixes #2719.
2017-01-09 15:49:29 +00:00
Adam Harrison 2ae2d52289 Merge pull request #2722 from weaveworks/issues/2719-delete-pods
Warn not to delete all Weave Net pods
2017-01-09 15:48:48 +00:00
Adam Harrison 635191970f Merge pull request #2688 from weaveworks/issues/2684-exec-weaver
Exec weaver from weave-kube launch rather than running in background
2017-01-09 15:24:19 +00:00
Bryan Boreham e370443a3f Merge pull request #2699 from weaveworks/2647-parallelise-sanity-checks
Parallelise sanity checks in order to speed them up.
2017-01-09 12:57:44 +00:00
Bryan Boreham 738ff2b65f Update tools submodule to avoid breaking on missing Docker mflag 2017-01-09 12:50:18 +00:00
Bryan Boreham cef8c908d0 Merge pull request #2704 from weaveworks/2647-parallelise-setup
Parallelise setup.sh's individual tasks.
2017-01-09 12:30:53 +00:00
Marc CARRE edc0cdbc10 Sanity checks' output is now redirected to $CIRCLE_ARTIFACTS directly when running smoke tests in CircleCI.
Previously sanity checks' output was redirected to /tmp and then copied to $CIRCLE_ARTIFACTS, which is more "moving pieces".
2017-01-09 12:25:29 +00:00
Marc CARRE 89e116961c Now measure time spent in setup. 2017-01-09 12:03:13 +00:00
Marc CARRE 71180f97e7 Parallelise setup.sh. 2017-01-09 12:03:09 +00:00
Adam Harrison be8d9d88d8 Merge pull request #2724 from weaveworks/2647-remove-dependency-on-jq
Removed dependency on jq in test #175.
2017-01-09 10:59:52 +00:00
Bryan Boreham 35de3720e9 Merge pull request #2698 from weaveworks/2647-find-relative-dir
Finding and running tests no longer depends on current directory.
2017-01-09 10:34:07 +00:00
Marc CARRE 4a7e2054db Removed dependency on jq in test #175.
If the machine coordinating the test runs does not have jq, then test #175 fails with:
> test #1 "weave_on test-0.lon1.weave-net report | jq -r '.Router.Targets[] | tostring' | sort" failed:
>     expected "test-1.lon1.weave-net
> test-2.lon1.weave-net"
>     got nothing
This change completely removes the dependency on jq to make the test more robust and avoid potential confusion.
2017-01-09 10:16:05 +00:00
Marc CARRE fe75047988 weave-daemonset.yaml is now referred to using relative paths. 2017-01-09 10:08:38 +00:00
Marc CARRE f73fb5307f Redirect sanity checks' output to temporary files (and archive them as artifact files under CircleCLI).
This should make it easier to find and access relevant debugging information without polluting STDOUT and without any risk of log interleaving. See also:
- https://weaveworks.slack.com/archives/net/p1482154505001192
- https://weaveworks.slack.com/archives/net/p1482254780001493
2017-01-09 09:17:45 +00:00
Marc CARRE 172597a68d Now measure time spent in sanity checks. 2017-01-09 09:17:45 +00:00
Marc CARRE f05169e457 Initialise pids before using it, to avoid potential issues with previously set values. 2017-01-09 09:17:45 +00:00
Marc CARRE b171497466 Ensure sanity checks exit early in case of a ping failure. 2017-01-09 09:17:45 +00:00
Marc CARRE 61375fb785 Format ping output as one line. 2017-01-09 09:17:45 +00:00
Marc CARRE 04cc4edf26 Parallelise sanity checks in order to speed them up. 2017-01-09 09:17:45 +00:00
Marc CARRE 0101a12fba Undo 0dff07dc8b since current directory is already changed on previous line. 2017-01-09 09:16:53 +00:00
Marc CARRE e094fb1547 DOCKER_CERT_PATH is now set using a relative path. 2017-01-09 09:16:53 +00:00
Marc CARRE e0a44a901a Tests now source dependencies using relative paths (previously breaking make depending on current directory). 2017-01-09 09:16:53 +00:00
Marc CARRE d4f9abeefd Finding tests no longer depends on current directory. 2017-01-09 09:16:53 +00:00
Bryan Boreham 0338d4595b Fix instructions to view npc logs when >1 pod exists 2017-01-06 11:24:20 +00:00
Bryan Boreham 7328c3fe86 Comment about full build on first push 2017-01-06 10:54:13 +00:00
Bryan Boreham bf288ff6f5 Warn not to delete all Weave Net pods 2017-01-06 10:30:46 +00:00
Marc Carré ef4c4024bc Merge pull request #2720 from weaveworks/2647-fix-test-150
Fix ordering bug in test #150.
2017-01-05 15:29:58 +00:00
Marc CARRE 6f24cca4b1 Fix ordering bug in test #150.
Test hard-codes a string containing '\n' and then expects echo
to interpret it as a newline, which it does not without the -e option.

This fixes flaky test runs like the below:
>>> Running /root/src/github.com/weaveworks/weave/test/150_connect_forget_2_test.sh on [138.68.153.213 138.68.149.186]
>>> Test /root/src/github.com/weaveworks/weave/test/150_connect_forget_2_test.sh finished after 12.4 secs with error: exit status 1
test #5 "direct_peers 138.68.149.186 | sort" failed:
  expected "138.68.153.213\n138.68.149.186"
  got "138.68.149.186\n138.68.153.213"
2017-01-05 15:02:16 +00:00
Bryan Boreham bf59a003bb Exec weaver from weave-kube launch rather than running in background
So we only have one process running inside the container after all
set-up is finished
2017-01-04 15:00:52 +00:00
Bryan Boreham 2298a40327 Fix bug which was killing all smoke-tests
- only fail if there is no secret password
2017-01-04 14:53:43 +00:00
Adam Harrison 61d22bb8b4 Merge pull request #2686 from weaveworks/issues/2580-allow-ips
Allow docker bridge to have more than one IP address
2017-01-04 14:35:48 +00:00
Adam Harrison eb3bbff883 Merge pull request #2708 from weaveworks/weave-kube-mounts
Mount /etc under a different path for weave-kube
2017-01-04 10:15:54 +00:00
Adam Harrison 03c1379d1b Merge pull request #2716 from liubog2008/fix
fix a bug of updating network policy
2017-01-03 17:44:58 +00:00
liubog2008 1635093341 fix a bug of updating network policy 2016-12-28 14:12:06 +08:00
Bryan Boreham 93dcc4550a Merge pull request #2712 from luxaslabs/deprecate_maintainer_dockerfile
Remove the deprecated MAINTAINER field in Dockerfiles and change to "LABEL maintainer" instead
2016-12-23 16:06:41 +00:00
Bryan Boreham ab55da47b6 Check if we have secrets before decrypting or running smoke tests
And enable running CircleCI on forked pull requests
2016-12-23 16:06:20 +00:00
Lucas Käldström 17971a5a3a Remove the deprecated MAINTAINER field in Dockerfiles for LABEL maintainer instead
Also add https://microbadger.com/labels labels and remove LABEL fields where they already are inherited
2016-12-23 14:57:02 +02:00
Bryan Boreham e0b90e8f02 Inline single-line function docker_bridge_ip 2016-12-23 12:15:04 +00:00
Bryan Boreham ea014d1362 Reimplement docker_bridge_ip shell pipeline in Go 2016-12-23 12:10:26 +00:00
Bryan Boreham 6ef302b8a1 Extract FindBridgeIP to net package 2016-12-23 11:57:04 +00:00
Bryan Boreham 1e7afe3bec Merge branch '1.8' 2016-12-23 11:35:53 +00:00
Bryan Boreham 48508044d6 Merge pull request #2703 from weaveworks/issues/2700-ip-link
Docs: improve IP route links
2016-12-23 11:26:52 +00:00
Bryan Boreham a4ad66f1c8 Mount /etc under a different path for weave-kube
So we don't accidentally read or write the hosts's /etc.
Also move the other volumes under /host to be more consistent with
what the weave script expects.
2016-12-22 10:35:47 +00:00
Bryan Boreham 0f85a959bb Merge branch '1.8' 2016-12-21 11:15:04 +00:00
Bryan Boreham d9a8adda1d Merge pull request #2706 from weaveworks/issues/2638-segfault-dp
Do not segfault if the datapath exists
2016-12-21 11:12:19 +00:00
Marc Carré ef4a8648a9 Merge pull request #2707 from weaveworks/2647-fix-typo-in-sanity-checks
Fixed typo in sanity check of weave's version
2016-12-21 10:28:09 +00:00
Marc CARRE 8bb72aa175 Fixed typo in sanity check of weave's version (previously checking locally, now checking test host). 2016-12-21 10:03:05 +00:00
Martynas Pumputis fa05dcf6ee Do not segfault if the datapath exists
If the datapath exists when creating it, dpif.CreateDatapath
will return an empty handle which access will cause the segfault.
2016-12-20 18:16:16 +02:00
Martynas Pumputis 8affa26858 Merge pull request #2695 from weaveworks/issues/2692-consistent-npc-log
Change rest of npc to weave common logging

Fixes #2692
2016-12-19 16:41:27 +02:00
Martynas Pumputis 856cb48170 Merge pull request #2685 from weaveworks/issues/2480-correct-mac
Take peerName from weave bridge if not specified

Fixes #2480
2016-12-19 16:35:15 +02:00
Bryan Boreham 1239fca567 Docs: improve IP route links 2016-12-19 12:34:05 +00:00
Bryan Boreham 6592a9afc7 Merge branch '1.8' 2016-12-14 11:57:11 +00:00
Mathias Methner 7ffd96f425 Document how to publish prometheus metric endpoint on all interfaces
This is a combination of 4 commits.
 The first commit's message is:
2677 docu, how to publish prometheus metric endpoint on all interfaces

 This is the 2nd commit message:
2677 change docu on how to publish metrics, be more careful with publishing on all interfaces

 This is the 3rd commit message:
2677 fix spelling

 This is the 4th commit message:
2677 fix wrong port title and grammar
2016-12-14 11:54:56 +00:00
Bryan Boreham 906d9a47b1 Merge pull request #2696 from weaveworks/2647-import-using-absolute-paths
Scripts now source dependencies using relative paths
2016-12-13 17:00:58 +00:00
Marc CARRE 0dff07dc8b Scripts now source dependencies using relative paths (previously breaking make depending on current directory). 2016-12-13 16:00:37 +00:00
Bryan Boreham 9261d17dbe Fix option name 2016-12-13 14:59:45 +00:00
Bryan Boreham 7d8a18bd20 Change rest of npc to weave common logging 2016-12-13 13:52:48 +00:00
Bryan Boreham 29cb13cba6 Merge branch '1.8' 2016-12-13 13:34:03 +00:00
Martynas Pumputis 52f375ac1e Merge pull request #2663 from weaveworks/issues/2389-report-mtu
Add MTU to connection status

Fixes #2389
2016-12-13 11:53:39 +00:00
Bryan Boreham 73f184df7e Fix quotes in anchors 2016-12-13 11:42:20 +00:00
Bryan Boreham bbd631f08f weave-kube no longer needs to supply the peer address 2016-12-09 15:34:31 +00:00
Bryan Boreham cf315fb6ba Take peerName from weave bridge if not specified 2016-12-09 15:34:31 +00:00
Bryan Boreham c03a2caac2 Allow docker0 to have >1 IP address
and log the one we end up using
2016-12-09 15:22:49 +00:00
Bryan Boreham 9c2bc0b825 Add MTU to connection status 2016-12-09 13:59:49 +00:00
Martynas Pumputis fcda8985fb Remove bin/setup-ci-secrets
It was used by Travis CI which we do not use anymore.
2016-12-08 16:22:12 +00:00
Martynas Pumputis 14082f9332 Merge branch '1.8' 2016-12-08 15:44:40 +00:00
Martynas Pumputis 83401eb245 Update release-process.md
git.io/weave-kube does not point to the weave-kube repo anymore.
2016-12-08 15:35:54 +00:00
Martynas Pumputis 022a98d4a4 Add release v1.8.2 2016-12-08 15:11:21 +00:00
Bryan Boreham bb1cca713d Merge branch '1.8' 2016-12-08 12:27:40 +00:00
Bryan Boreham 1d80a8d676 Merge pull request #2674 from weaveworks/issues/2650-fix-looping-flows
Detect looping flows
2016-12-08 12:27:15 +00:00
Martynas Pumputis aa9c032176 Add sanity check to detect when receiving own packets 2016-12-08 11:38:37 +00:00
Martynas Pumputis baa8f229f7 Detect enabling of hairpin mode on vethwe-bridge
Enabled hairpin mode on vethwe-bridge was one of the root causes
for installing looping flows in the fastdp mode.

Also, it confused the weave custom L2 bridge, as the bridge treats
a bounced back packet, e.g. ARP brodcast request, as a local one
(the case for "Captured a packet associated with remote host").
2016-12-08 11:37:52 +00:00
Martynas Pumputis ab1b99a4d9 Update vishvananda/netlink vendored dependency
The updated version includes parsing of IFLA_PROTINFO
which is needed to get info about hairpin mode when
subscribing to link updates.
2016-12-08 10:33:22 +00:00
Adam Harrison 11ff1880e5 Merge pull request #2666 from weaveworks/issues/2633-json-events
Log objects via JSON for better debugging
2016-12-07 17:25:55 +00:00
Bryan Boreham 71bf040715 Add --log-level option, default to debug 2016-12-07 11:53:40 +00:00
Bryan Boreham 6a04c6c7bd Change to weave common logging 2016-12-07 11:53:31 +00:00
Bryan Boreham 8530528dd5 Drop pod log messages to Debug level 2016-12-07 11:51:53 +00:00
Adam Harrison e1d8992ec5 Merge branch '1.8'
Fixes #2673.
2016-12-07 11:24:13 +00:00
Adam Harrison b03311e99d Merge pull request #2683 from weaveworks/issues/2673-expose-again
Re-add expose to ensure it gets run on all nodes
2016-12-07 11:23:52 +00:00
Adam Harrison 0c1138ee60 Merge pull request #2662 from weaveworks/issues/2594-setup-cni
Unify weave and launch.sh CNI setup
2016-12-07 11:21:25 +00:00
Bryan Boreham 8a45292e24 Log objects via JSON for better debugging 2016-12-06 17:40:17 +00:00
Bryan Boreham d1712e9589 Re-add expose to ensure it gets run on all nodes
Previous change in a07e3301b1 meant that if there are no pods on
this node then the 'expose' never gets run.
2016-12-06 14:58:31 +00:00
Bryan Boreham ec21afb426 Unify weave and launch.sh CNI setup
Test 830 has to run CNI plugin under sudo now
2016-12-06 11:52:09 +00:00
Bryan Boreham 882bff292e Fix test invocation of weave again
Previous fix in b4a43f1b85 did not work
when built with code coverage.

Running a test script with -v causes `weave_on` to output progress
messages, so we don't want to use those commands inside `$()`
2016-12-06 11:48:48 +00:00
Adam Harrison f3843a6b18 Merge branch '1.8' 2016-12-06 11:41:45 +00:00
Adam Harrison 597c6c111d Merge pull request #2657 from weaveworks/remove-bridge-on-error
Remove weave bridge if something goes wrong when creating it
2016-12-06 11:41:29 +00:00
Adam Harrison ac4957e15c Merge branch '1.8' 2016-12-06 11:30:32 +00:00
Adam Harrison f3915592b2 Merge pull request #2679 from weaveworks/expose-loop
Run iptables commands in a loop
2016-12-06 11:30:20 +00:00
Bryan Boreham 8a292fd9f3 Merge pull request #2678 from weaveworks/issues/2593-remove-cni-from-plugin
Remove CNI support from Docker plugin
2016-12-06 02:51:23 -08:00
Bryan Boreham f34936d9be Merge branch '1.8' 2016-12-06 10:39:50 +00:00
Bryan Boreham d4367457a9 Merge pull request #2671 from weaveworks/document-env-vars
Document env-var configuration for weave-kube
2016-12-06 02:39:20 -08:00
Bryan Boreham b4a43f1b85 Fix test running with -v flag
Running a test script with -v causes `weave_on` and `docker_on` to
output progress messages, so we don't want to use those commands
inside `$()`
2016-12-05 16:12:15 +00:00
Bryan Boreham 3674808244 Remove weave bridge and associated devices if something goes wrong when creating it
Otherwise it is left in a half-created state and the user has to run `weave reset` to continue.
2016-12-05 15:11:47 +00:00
Bryan Boreham 44cc978a94 Update CNI information 2016-12-05 14:29:07 +00:00
Bryan Boreham f441ec2644 Document env-var configuration for weave-kube
E.g. how to configure the IP allocation range
2016-12-05 13:55:33 +00:00
Martynas Pumputis 0ae13a2650 Detect hairpin flows
The introduced "isHairpinFlow" detects whether a flow has been
created due to enabled hairpin mode.
2016-12-05 12:42:24 +00:00
Bryan Boreham ee6596e21c Run iptables commands in a loop
in case they get  "temporarily unavailable" exit
2016-12-05 11:11:20 +00:00
Anita Buehrle a63147beda Improve wording of kube-addon page 2016-11-30 16:15:30 +00:00
Adam Harrison cdcf5808db Remove CNI support from Docker plugin 2016-11-30 10:43:50 +00:00
Bryan Boreham d501c78795 Merge pull request #2659 from weaveworks/issues/2581-optional-bridge-nf
Optional bridge-nf detection
2016-11-28 18:09:40 -08:00
Adam Harrison e61ddc59c4 Merge branch '1.8'
Fixes #2669.
2016-11-28 11:54:03 +00:00
Adam Harrison 46e4f047de Merge pull request #2672 from weaveworks/issues/2669-iprange-clash
Check whether Weave's IP range overlaps something on the host already
2016-11-28 11:53:50 +00:00
Adam Harrison 9cff5f2c5e Merge branch '1.8' 2016-11-25 17:23:39 +00:00
Adam Harrison 5f031453d3 Remove backticks which are tripping up the markdown renderer 2016-11-25 16:55:22 +00:00
Marc CARRE 028216021f Fixed formatting of documentation about logging of connection blocked by Weave NPC. 2016-11-25 16:00:05 +00:00
Bryan Boreham d6544302d3 Check whether Weave's IP range overlaps something on the host already 2016-11-25 14:43:23 +00:00
Adam Harrison bc529c5d09 Merge branch '1.8'
Fixes #2667.
2016-11-25 13:10:29 +00:00
Adam Harrison 354d1ddd5c Merge pull request #2670 from weaveworks/issues/2667-firewall-rules
Run GCE test VMs on a locked-down network
2016-11-25 13:09:54 +00:00
Adam Harrison 28bf4e6e95 Optional bridge-nf detection 2016-11-25 12:40:20 +00:00
Marc Carré 33b7faa17d Merge pull request #2668 from weaveworks/fix-doc-formatting
Fix documentation's formatting.
2016-11-25 12:28:26 +00:00
Marc CARRE ac731c0ff7 Fixed formatting of documentation about logging of connection blocked by Weave NPC. 2016-11-25 12:19:53 +00:00
Bryan Boreham fd34dda6c1 Run test instances on a locked-down network
and open up a rule from the specific IP running the tests
2016-11-24 17:17:12 +00:00
Bryan Boreham 16fca913de Merge branch '1.8' 2016-11-24 15:27:36 +00:00
Bryan Boreham f989a82eb0 Merge pull request #2573 from weaveworks/2546-clarify-npc-packet-drop-no-link
Clarified and documented Weave NPC packet drops (w/o short URL).
2016-11-24 15:26:49 +00:00
Marc CARRE d410ecd34c Document logging of connection blocked by Weave NPC. 2016-11-24 14:04:43 +00:00
Marc CARRE 48569265e2 Add logging of connection blocked by Weave NPC. 2016-11-24 14:02:22 +00:00
Bryan Boreham ad43acf843 Merge branch '1.8' 2016-11-24 10:53:59 +00:00
Bryan Boreham 71782a6aa5 Merge pull request #2661 from weaveworks/fix-700-again
Wait up to 30s for version check error in logs
2016-11-24 10:52:47 +00:00
Adam Harrison 6df24d1a40 Merge branch '1.8' 2016-11-23 12:37:14 +00:00
Adam Harrison e283b0a1ce Add release v1.8.1 2016-11-23 12:25:07 +00:00
Adam Harrison fa15193011 Wait up to 30s for version check error in logs 2016-11-23 10:53:42 +00:00
Bryan Boreham dff14c19f8 Don't remove base CNI plugins in test 2016-11-23 10:38:23 +00:00
Adam Harrison 6103595b9c Merge branch '1.8' 2016-11-23 10:36:53 +00:00
Adam Harrison 01c436ae15 Merge pull request #2642 from weaveworks/fix-launch-version
Fix weave-kube launch.sh version usage
2016-11-23 10:36:16 +00:00
Adam Harrison c3a2539445 Merge branch '1.8' 2016-11-22 16:17:30 +00:00
Adam Harrison 664ba8735f Merge pull request #2643 from weaveworks/issues/2632-cni-no-check-alive
Don't release CNI-allocated IP address when container dies
2016-11-22 16:17:11 +00:00
Bryan Boreham 937036aa64 Simplify default version string 2016-11-22 15:43:17 +00:00
Bryan Boreham 47cdf2b755 Simplify version sed 2016-11-22 15:42:53 +00:00
Adam Harrison ef270764f3 Merge branch '1.8'
Fixes #2632.
2016-11-22 15:28:03 +00:00
Adam Harrison a6edd40de3 Merge pull request #2658 from weaveworks/issues/2632-use-pod-status
Make NPC only look at IP addresses on running pods
2016-11-22 15:27:48 +00:00
Bryan Boreham 4219c2c2ab Only look at IP addresses on pods that haven't finished 2016-11-22 13:49:28 +00:00
Bryan Boreham 4785de1a34 Merge branch '1.8' 2016-11-22 09:59:27 +00:00
Bryan Boreham cbec624cd8 Remove CNI files when tearing down Kubernetes 2016-11-21 16:08:50 +00:00
Bryan Boreham e7bde18f71 Merge pull request #2656 from weaveworks/add-jq-to-vagrantfile
Include jq in the build VM
2016-11-21 11:53:03 +00:00
Bryan Boreham e9eeaee520 Warn user on unknown gce util command 2016-11-21 09:49:41 +00:00
Bryan Boreham d5ec9fb38d Fix test 700 to use resolver override
instead of /etc/hosts override that didn't work in netgo mode
2016-11-18 20:42:15 +00:00
Adam Harrison 233a776c41 Include jq in the build VM
Required to run the tests.
2016-11-18 17:59:13 +00:00
Bryan Boreham d5f1c233bf Remove punctuation from the end of error messages
to placate the linter
2016-11-18 10:40:41 +00:00
Bryan Boreham af732d0495 Merge pull request #2529 from weaveworks/use-golang-171
Build container FROM golang:1.7.3
2016-11-17 15:04:12 +00:00
Marc Carré 04a87f951b Merge pull request #2644 from weaveworks/issues/2567-tighter-iprange
Better value for --ipalloc-range in attach-router
2016-11-17 11:38:12 +00:00
Bryan Boreham 9cc98919fa Adjust CNI smoke-test to cope with new plugin behaviour 2016-11-14 19:53:54 +00:00
Bryan Boreham e42600632f Don't release dead container's IP addresses if not asked to check it is alive. 2016-11-14 19:53:54 +00:00
Bryan Boreham 93aa3fed16 Merge branch '1.8' 2016-11-14 19:47:05 +00:00
Bryan Boreham 49e76d1486 Merge pull request #2645 from weaveworks/fix-test-700
Replace iptables block with resolver override
2016-11-14 19:44:26 +00:00
Adam Harrison 965bed7c4f Replace iptables block with resolver override 2016-11-14 17:11:17 +00:00
Bryan Boreham 317c6ba04c Better value for --ipalloc-range in attach-router
The previous regex matched a blank --ipalloc-range and the following
parameter, which defeated the whole point of the check.
2016-11-14 16:11:42 +00:00
Adam Harrison 41d127934b Remove redundant GO15VENDOREXPERIMENT setting 2016-11-14 15:13:19 +00:00
Adam Harrison 915638d17a Address linter failures 2016-11-14 15:13:19 +00:00
Adam Harrison f73355abcc Incorporate Docker's malformed host fix 2016-11-14 15:13:19 +00:00
Adam Harrison 8f9da95e5e Restore golint 2016-11-14 15:13:19 +00:00
Adam Harrison 0935aa9221 Build container FROM golang:1.7.3 2016-11-14 15:13:19 +00:00
Adam Harrison aaa073afed Merge branch '1.8'
Fixes #2617 and fixes #2570.
2016-11-14 15:11:57 +00:00
Adam Harrison 9b606fb823 Merge pull request #2637 from weaveworks/issues/2617-cni-expose
Remove 'weave expose' race in CNI plugin
2016-11-14 15:11:38 +00:00
Bryan Boreham 15d91c558b Quote version string which may contain spaces, etc 2016-11-14 12:49:00 +00:00
Bryan Boreham ffc5a78139 Add code-coverage options to weaver version call 2016-11-14 12:42:17 +00:00
Bryan Boreham f8693074a3 Move CNI config file to the end of launch script
So something waiting for the config (e.g. Kubernetes) doesn't try to
talk to Weave before then (this only helps on first install, but that
tends to be when things are busiest).
2016-11-14 12:37:42 +00:00
Bryan Boreham 1629f4f3f0 Loop round iptables commands on EAGAIN 2016-11-14 12:37:42 +00:00
Bryan Boreham 10baab38d3 Extend smoke-test to include pinging 2016-11-14 12:37:42 +00:00
Bryan Boreham e458c11e66 Weave script calls Go implementation of expose_nat 2016-11-14 12:37:42 +00:00
Bryan Boreham a07e3301b1 Add 'weave expose' NAT iptables rules inside CNI plugin
This avoids a race between the plugin and the script
2016-11-14 12:37:42 +00:00
Bryan Boreham 2b4d13c5b1 Don't error on bridge address already there 2016-11-14 12:37:42 +00:00
Bryan Boreham 755e42836c Merge branch '1.8' 2016-11-14 11:29:34 +00:00
Bryan Boreham ad743b0e96 Merge pull request #2577 from weaveworks/2548-fix-reclaim-after-using-cni
Fix reclaim after using CNI; Fixes #2548.
2016-11-14 11:28:42 +00:00
Marc CARRE 0544901357 Factorise "_" duplicates as a constant. 2016-11-11 17:00:26 +00:00
Marc CARRE bc94633180 Re-claim IP on start-up when an existing ID has been found.
- Rewrote conditions to keep c.ident immutable and hopefully makes
things clearer.
- Added a case to tolerate reclaim after we have used CNI (passed CID
is “_” and existing CID is a real container ID).
2016-11-11 17:00:26 +00:00
Marc CARRE 16415404c7 Added automated test reproducing the issue.
test #4 "[
3e52b548e6df304c61ea5bee0af4b3515e025e7e25152c65ecae3d03c71cf52d ==
Unable to claim: address 10.32.0.3/12 is already owned by
fbe411facc8b657c5850591ab56fc40fb56160d43db0d7363a29ba3edad61134
Unable to claim: address 10.32.0.1/12 is already owned by
cf16a2bcdee8dd1ef7e5f0a611127611e67ea734f45d7526678fc3b1fc0c6f5d
3e52b548e6df304c61ea5bee0af4b3515e025e7e25152c65ecae3d03c71cf52d ]"
failed:
	program terminated with code 2 instead of 0
1 of 6 tests failed in 6.499s.
2016-11-11 17:00:26 +00:00
Adam Harrison 702d12d801 Merge branch '1.8'
Fixes #2537.
2016-11-11 16:14:52 +00:00
Adam Harrison 46eb01604c Merge pull request #2565 from weaveworks/2537-fix-status-on-version-check-failures
Improve 'status' to handle cases when the checkpoint API is not available
2016-11-11 16:14:24 +00:00
Adam Harrison af36682a7e Merge branch '1.8' 2016-11-11 11:27:25 +00:00
Bryan Boreham 03d9e3db69 weaveutil now depends on plugin code 2016-11-10 17:04:10 +00:00
Marc CARRE b03b3fccc7 Fixes 2537: status now prints 'failed to check latest version' when the checkpoint API is not available (+test). 2016-11-09 17:46:52 +00:00
Marc Carré 9414e2979d Merge pull request #2599 from weaveworks/replace-kubectl-create-with-apply
Updated doc: replaced kubectl create with kubectl apply.
2016-11-07 16:31:31 +00:00
Marc CARRE 865664425b Updated doc: replaced kubectl create with kubectl apply. 2016-11-07 16:18:40 +00:00
Adam Harrison b060cf30f4 Add release v1.8.0 2016-11-04 15:49:36 +00:00
Marc Carré 5352ed837a Merge pull request #2598 from weaveworks/cni-setup-remove-symlink
Clean up CNI symlinks from weave-kube
2016-11-04 15:28:44 +00:00
Adam Harrison d4d54a1ff5 Clean up CNI symlinks from weave-kube 2016-11-04 14:41:34 +00:00
Adam Harrison ea82a6715f Merge pull request #2569 from weaveworks/weave-kube-smoke-test
weave-kube smoke test
2016-11-04 12:58:20 +00:00
Martynas Pumputis d356e32bdf Merge pull request #2588 from weaveworks/kube-npc-docs
Document k8s addon & prometheus metrics
2016-11-04 12:50:41 +00:00
Martynas Pumputis 6193d22d2e Merge pull request #2595 from weaveworks/change-npc-metrics-port
Change default NPC metrics port
2016-11-04 12:41:25 +00:00
Adam Harrison 50c9568073 Document Prometheus metrics endpoints 2016-11-04 12:33:06 +00:00
Adam Harrison 9d05ed41b2 Change default NPC metrics port 2016-11-04 12:31:01 +00:00
Adam Harrison e3f7e0a23a Merge pull request #2590 from weaveworks/issues/2586-/opt/cni/bin-never-upgraded
Add support for atomic and versioned upgrades of CNI plugin.
2016-11-04 12:27:48 +00:00
Marc CARRE da2f0803ce Add support for atomic and versioned upgrades of CNI plugin. 2016-11-04 11:54:22 +00:00
Bryan Boreham 6dde5e5ee9 Add code-coverage options to weaver start 2016-11-04 10:52:36 +00:00
Bryan Boreham 494df21bdf Disable imagePullPolicy so we test the image we just built 2016-11-04 10:52:36 +00:00
Bryan Boreham e44bbbec63 Add smoke-test for weave-kube 2016-11-04 10:52:36 +00:00
Bryan Boreham c19f49a284 Install Kubernetes packages and pre-pull images
Bump template version too
Note that we disable kubelet in the image, so you have to start it if
you want to use it.
2016-11-04 10:52:36 +00:00
Adam Harrison d3f2c110e4 Merge pull request #2589 from weaveworks/issues/2587-cni-weaveutil
Fix CNI plugin calling weaveutil
2016-11-04 10:47:38 +00:00
Bryan Boreham 09628178e4 Weave-kube doesn't need to depend on plugin repo any more 2016-11-03 17:42:39 +00:00
Bryan Boreham 5630a01a8c Implement CNI plugin via weaveutil 2016-11-03 17:42:39 +00:00
Adam Harrison 40b3a49c90 Merge pull request #2563 from weaveworks/update-test-template
Update CI VMs to Ubuntu 16.04 and Docker 1.11
2016-11-03 17:35:21 +00:00
Adam Harrison 431b87b94a Merge pull request #2591 from weaveworks/reset-npc
Have 'weave reset' remove NPC rules
2016-11-03 15:22:46 +00:00
Adam Harrison 828c3d21d2 Recommend using the k8s addon from the CNI docs 2016-11-03 15:13:50 +00:00
Adam Harrison f0e75481d5 Add network policy to features 2016-11-03 15:13:50 +00:00
Adam Harrison 8bb7e1cf24 Document Kubernetes Addon 2016-11-03 15:13:50 +00:00
Bryan Boreham e117a6bd04 Have 'weave reset' remove NPC rules 2016-11-03 14:24:26 +00:00
Adam Harrison ac44fa63c8 Fix breakage caused by #2574 2016-11-03 11:52:58 +00:00
Martynas Pumputis bb639dbf32 Merge pull request #2585 from weaveworks/merge-weave-npc
Merge weave npc
2016-11-02 11:58:43 +00:00
Bryan Boreham 64c890005a Merge pull request #2583 from damoon/fixup-74b477ac82e1ae267cf8501519f52e1f71a782dc
weaveworks/weave-kube:latest broken - fixup! allow to not run NPC: do not create iptables rules for NPC
2016-11-02 11:58:02 +00:00
Adam Harrison 19088ba8bc Import from weave-npc repo 2016-11-02 11:28:59 +00:00
Martynas Pumputis ec5f7033a4 Merge pull request #2579 from weaveworks/issues/2557-improve-metric-naming
Improve metric naming
2016-11-02 11:02:23 +00:00
Bryan Boreham eb60f68df2 Report metrics on all connection states 2016-11-02 09:51:13 +00:00
David Sauer d72e671d8b fixup! allow to not run NPC: do not create iptables rules for NPC 2016-11-02 10:10:33 +01:00
Martynas Pumputis 3462357481 Merge pull request #2578 from weaveworks/issues/2576-metrics-on
Serve metrics by default, on port 6782
2016-11-02 09:08:13 +00:00
Bryan Boreham 2b4da35b1c Remove 'total' DNS entries; let the caller add them up 2016-11-01 18:03:35 +00:00
Bryan Boreham 86d68c9875 Move total IPs in range from a state to a separate metric 2016-11-01 18:03:35 +00:00
Bryan Boreham cfff8ee8be Merge pull request #2568 from weaveworks/rename-conn-term-prom-metric
Rename weave_connection_termination_count metric
2016-11-01 18:02:55 +00:00
Bryan Boreham af10cef5f0 Set --status-addr for metrics by default 2016-11-01 17:04:04 +00:00
Bryan Boreham a1a42736ed Fix hard-coded http address 2016-11-01 16:53:37 +00:00
Adam Harrison b533a11bee Update client-go
weave-npc needs some fixes from client-go master (specifically the
unversioned.LabelSelector change)
2016-11-01 16:19:43 +00:00
Bryan Boreham afed9e9646 Merge pull request #2574 from pondohva/fix_weave_static_pod
allow to not run NPC: do not create iptables rules for NPC
2016-11-01 15:35:49 +00:00
Artur Gadelshin 74b477ac82 allow to not run NPC: do not create iptables rules for NPC 2016-11-01 17:32:41 +03:00
Bryan Boreham bf74c8f108 Add dependency of weave-kube on launch.sh 2016-11-01 10:46:25 +00:00
Bryan Boreham 04c7f5283e Reconfigure and restart docker for systemctl 2016-10-31 17:33:33 +00:00
Bryan Boreham d1d53ba45c Pre-install more stuff in the image.
Install bc and jq in the image rather than on every build.
Also pre-pull some Docker images
2016-10-31 17:33:33 +00:00
Bryan Boreham dfadb8f189 Upgrade to Ubuntu 16.04 and Docker 1.11
Using Docker 1.11 since there isn't a Docker-supplied package for 1.10 on Xenial
2016-10-31 17:33:33 +00:00
Bryan Boreham 5335c133a3 Update deprecated gcloud syntax 2016-10-31 17:33:33 +00:00
Adam Harrison 8fcb5daedf Merge pull request #2551 from weaveworks/weave-kube
Merge weave-kube into the Weave Net repo
2016-10-31 17:12:03 +00:00
Martynas Pumputis ede70a78d6 Rename weave_connection_termination_count metric
To make it follow the Prometheus naming conventions:
https://prometheus.io/docs/practices/naming/
2016-10-31 13:23:12 +00:00
Bryan Boreham 23056cbb45 Temporarily release weave-daemonset.yaml to weave-kube repo 2016-10-31 10:59:15 +00:00
Bryan Boreham 29e9e70ac9 Add weave-kube to release script 2016-10-31 10:59:15 +00:00
Bryan Boreham d0b711513e Add weave-daemonset.yaml 2016-10-31 10:59:15 +00:00
Bryan Boreham 7dbee74e85 Add weave-kube image 2016-10-31 10:59:15 +00:00
Bryan Boreham 4e7a3b1805 Add kube-peers program 2016-10-31 10:59:15 +00:00
Bryan Boreham 3c7b244f18 Change image layering - plugin builds on weaver & weaver builds on weaveexec 2016-10-31 10:59:13 +00:00
Bryan Boreham e50f5c52c5 Make templating of Dockerfiles more generic 2016-10-31 10:56:18 +00:00
Bryan Boreham baf91658d6 Fix static linking flags 2016-10-28 14:51:26 +01:00
Adam Harrison fda035d8d6 Merge branch '1.7' 2016-10-28 14:29:26 +01:00
Adam Harrison a4a53e1a11 Fix broken link 2016-10-28 14:08:54 +01:00
Martynas Pumputis aad3e52d72 Merge pull request #2564 from weaveworks/improved-dh-org-override-fix
Improve Dockerfile template substitution
2016-10-28 10:24:28 +01:00
Adam Harrison cb778a9af5 Improve Dockerfile template substitution 2016-10-27 11:43:41 +01:00
Marc CARRE 3af9732c84 Merge branch '1.7' 2016-10-26 16:49:58 +01:00
Marc Carré 00e754ed9f Merge pull request #2562 from weaveworks/build-test-runner-with-vendoring
Use vendoring when building test runner & Vagrantfile improvements
2016-10-26 16:44:15 +01:00
Marc CARRE d893f44833 Vagrantfile now copies SSH key required to run smoke tests from host to guest. 2016-10-26 16:09:09 +01:00
Marc CARRE 4839f41809 Improve resolution of Dockerfile since used in both Vagrantfile and test/Vagrantfile. 2016-10-26 16:09:09 +01:00
Marc CARRE c801409c94 Set VM's memory to 2048 MB by default. 2016-10-26 16:09:09 +01:00
Marc CARRE 1c4a01d52c Read Go version from Dockerfile in order to keep things 'DRY'. 2016-10-26 16:09:09 +01:00
Adam Harrison 880b0a883a Use vendoring when building test runner 2016-10-26 16:09:09 +01:00
Adam Harrison 4b77662e3b Merge pull request #2561 from weaveworks/issues/2560-fix-dns-ipam-metrics
Do not expose IPAM or DNS metrics if weave does not run IPAM or DNS
2016-10-26 14:24:43 +01:00
Adam Harrison a5ff7ab8df Merge pull request #2475 from weaveworks/issues/2419-withnetns
Add a safer version of WithNetNS*
2016-10-26 13:50:34 +01:00
Adam Harrison 04a6e6d13b Merge branch '1.7' 2016-10-26 13:47:05 +01:00
Martynas Pumputis 5c2e878c64 Do not expose IPAM or DNS metrics when weave does not run IPAM or DNS
Otherwise, GET /metrics will crash weaver.
2016-10-25 16:54:35 +01:00
Adam Harrison f9bada5af8 Merge pull request #2558 from weaveworks/fix-broken-url-in-doc
Fixed broken link to plugin.md to weave-docker-api.md.
2016-10-24 16:57:07 +01:00
Marc CARRE 80d66f8f68 Fixed broken link to plugin.md to weave-docker-api.md. 2016-10-24 16:37:55 +01:00
Martynas Pumputis 98b35b87a9 Fix weave_connection_termination_count
Do not count terminations caused by connect-to-ourselves.
2016-10-24 11:37:15 +01:00
Martynas Pumputis b1d6605e8f Remove inaccurate Prometheus metrics
The metrics include:
- weave_packets_total
- weave_bytes_total

The problem with those metrics is that fastdp periodically flushes
flows including their stats thus makes the current implementation
of the metrics unreliable.
2016-10-24 11:23:10 +01:00
Martynas Pumputis 2cd3bde348 Merge pull request #2555 from weaveworks/forget-immediately
Recompute targets immediately after 'weave forget'
2016-10-24 10:52:14 +01:00
Bryan Boreham f2454775b9 Merge pull request #2552 from weaveworks/issues/2550-fix-make-dockerhub-user
Ensure Dockerfiles obey DOCKERHUB_USER
2016-10-24 09:59:38 +01:00
Bryan Boreham a53d1e00ee Recompute targets immediately after 'weave forget' 2016-10-21 18:02:25 +01:00
Martynas Pumputis 523a964ac8 Merge pull request #2547 from weaveworks/prometheus-metrics
Prometheus metrics
2016-10-21 14:57:42 +01:00
Adam Harrison f8cf7a1054 Ensure Dockerfiles obey DOCKERHUB_USER 2016-10-21 14:45:10 +01:00
Bryan Boreham 4d8a40c0b5 Reduce metrics mechanism to just support fastdp 2016-10-21 14:44:12 +01:00
Martynas Pumputis 9754da15d6 Encode "list-netdevs" output in JSON 2016-10-20 18:18:57 +01:00
Bryan Boreham 0458d32089 Serve metrics on a different socket to the main API
Serve metrics+status on status socket and api+status+metrics on api
socket; the reasoning is that metrics or status are read-only hence
may be scraped from an off-machine connection, while we don't want to
open the control port up unprotected.
2016-10-20 16:25:16 +01:00
Bryan Boreham ee4e8eb994 Pull in updated mesh lib 2016-10-20 16:25:16 +01:00
Bryan Boreham b8d619dde7 Add Prometheus http handler for metrics
Metrics are: connection counts, active IP addresses, DNS addresses,
FastDP flow metrics, connection termination count
2016-10-20 16:25:16 +01:00
Bryan Boreham 00c86fed42 Expose overlay metrics from fastdp
and allow them to pass through OverlaySwitch
2016-10-20 16:25:16 +01:00
Bryan Boreham 6d5af85eee Report count of active IP addresses in status 2016-10-20 14:04:41 +01:00
Bryan Boreham 1ae2d33714 Remove old-style 'expvar' metrics 2016-10-20 13:54:42 +01:00
Bryan Boreham 71d550260f Extract countDNSEntries function 2016-10-20 13:54:42 +01:00
Bryan Boreham 1092bae05c Refactor: move 'unreachable' logic out of printing function 2016-10-20 13:54:42 +01:00
Martynas Pumputis e611f04f41 Move NetDev utils from common/ to net/ 2016-10-19 17:03:30 +01:00
Martynas Pumputis 3492cd93d0 Use safe version of WithNetNS 2016-10-19 16:15:59 +01:00
Martynas Pumputis 947ae11fee Refactor NetDev utilities
- Make them safe by using the safe version of WithNetNS.
- Improve naming.
2016-10-19 16:07:53 +01:00
Martynas Pumputis cdd6ed548c Add netdev subcommands to weaveutil
The subcommands are going to be used with WithNetNS wrapper.
2016-10-19 16:07:53 +01:00
Martynas Pumputis fc940d0017 Merge pull request #2549 from weaveworks/log-drops-via-nflog
Log dropped policy controller traffic via NFLOG
2016-10-19 11:02:28 +01:00
Bryan Boreham b38a55ca7c Include more context in error messages from CNI operations 2016-10-18 17:45:09 +01:00
Adam Harrison 8e739d5240 Log dropped policy controller traffic via NFLOG
Send blocked NEW connection attempts to NFLOG group 86 for accounting by
the weave-npc process.
2016-10-14 15:59:15 +01:00
Adam Harrison 71f8bb7e9a Merge branch '1.7' 2016-10-11 17:02:00 +01:00
Adam Harrison ebfaf11f4a Add release v1.7.2 2016-10-11 11:07:18 +01:00
Matthias Radestock 4a6cec3ecc Merge branch '1.7' 2016-10-07 12:47:04 +01:00
Matthias Radestock 1abce148a3 Merge pull request #2543 from weaveworks/issues/2527-remote-addr
Update Weave Mesh to bring in two fixes

Fixes #2481 via weaveworks/mesh#57
Fixes #2527 via weaveworks/mesh#60
2016-10-07 12:45:51 +01:00
Adam Harrison e0cc7f17b2 Merge branch '1.7'
Fixes #2540
2016-10-07 12:24:11 +01:00
Adam Harrison 264e5c9979 Merge pull request #2541 from weaveworks/issues/2540-withnetns
Change namespace via nsenter, for plugin arp-config step
2016-10-07 12:20:47 +01:00
Bryan Boreham a6a1ce5c9e Update Weave Mesh to bring in fix of panic 2016-10-07 12:13:49 +01:00
Bryan Boreham 6ac7ab162f Merge branch '1.7' 2016-10-06 16:42:07 +01:00
Bryan Boreham 5e660311d2 Merge pull request #2538 from weaveworks/2506-uts-release-bytes
inline (u)int8 array to string conversion
2016-10-06 16:41:26 +01:00
Martynas Pumputis 4a49ff3083 Replace usage of WithNetNSUnsafe in plugin/net/watcher.go with safer version
Unsafe version was in ConfigureARPforVeths; replacement is via `weaveutil configure-arp`
2016-10-06 15:25:05 +01:00
Martynas Pumputis 7f92c8c4c6 Add a safer version of WithNetNS*
The introduced functions are executing the work function via
a process which executes "nsenter --net=path weaveutil ...".
2016-10-06 15:25:05 +01:00
Matthias Radestock 85ac8177ad inline (u)int8 array to string conversion
so that the code compiles regardless of the uts.Release array type,
which varies across platforms.

Fixes #2506
2016-10-06 08:57:12 +01:00
Adam Harrison 03bd1fb91d Merge branch '1.7' 2016-10-05 16:49:33 +01:00
Adam Harrison eb5b16614c Add release v1.7.1 2016-10-05 15:23:25 +01:00
Adam Harrison a5873a3970 Merge branch '1.7' 2016-10-05 15:18:26 +01:00
Adam Harrison e48ca80dee Disable golint as it no longer builds with 1.5.x 2016-10-05 15:16:23 +01:00
Bryan Boreham e7c9e22350 Merge pull request #2274 from weaveworks/issues/2273-improve-doc-ci
Improve doc CI
2016-10-03 15:34:39 +01:00
Adam Harrison b8e7d83f19 Rename SKIP_TESTS 2016-10-03 14:07:57 +01:00
Adam Harrison 4c304c0013 Extract install-wordepress 2016-10-03 14:01:15 +01:00
Adam Harrison 7249350757 Merge pull request #2531 from weaveworks/process-addrs
Add weaveutil process-addrs
2016-09-30 10:28:59 +01:00
Bryan Boreham 50a8dc1383 Add weaveutil process-addrs
Fetches addresses for every veth that is in a network namespace and
attached to the specified bridge.  Works by iterating over every process.
2016-09-29 14:16:05 +01:00
Bryan Boreham 71491138aa Extract function to return all current process ids
This implementation should be more efficient because it only uses the
names under /proc, whereas the previous implementation fetched the
full directory entry for each one, and sorted them too.
2016-09-29 14:12:02 +01:00
Bryan Boreham ca87f8ada3 Improve comments 2016-09-29 14:06:43 +01:00
Adam Harrison 835b3f3d67 Improve script names 2016-09-29 13:01:18 +01:00
Adam Harrison 263dffeedc Extract shared function 2016-09-29 11:45:28 +01:00
Adam Harrison e1063944f6 Comment on GitHub PR with site changes 2016-09-29 11:45:28 +01:00
Adam Harrison 2380018457 Skip tests if PR contains only site changes 2016-09-29 11:45:28 +01:00
Adam Harrison a9db631836 Add toggle for skipping tests 2016-09-29 11:35:01 +01:00
Adam Harrison b45f138ff1 Propagate state between scripts 2016-09-29 11:25:34 +01:00
Adam Harrison b239694d34 Move circle commands into shell scripts 2016-09-29 11:25:34 +01:00
Adam Harrison 0c2774f367 Add release v1.7.0 2016-09-27 14:46:35 +01:00
Bryan Boreham ea4647bc74 Merge pull request #2524 from weaveworks/expect-npc
Implement `--expect-npc` flag to `create-bridge`
2016-09-27 13:41:22 +01:00
Adam Harrison 6ec21d3a58 Implement --expect-npc flag to create-bridge
Add a private flag for weave-kube to steer overlay traffic via the
network policy engine chain.
2016-09-27 09:23:19 +01:00
Adam Harrison 44a4a56024 Merge branch '1.6' 2016-09-21 17:14:07 +01:00
Adam Harrison 0aac614c08 Add release v1.6.2 2016-09-21 16:18:03 +01:00
Adam Harrison 2ea027d3a8 Merge branch '1.6' 2016-09-21 11:15:49 +01:00
Adam Harrison cd4cbed5a0 Merge pull request #2501 from weaveworks/issues/2495-filter-empty-peers
Reject empty peers
2016-09-21 11:12:10 +01:00
Adam Harrison 69b688b357 Merge pull request #2509 from weaveworks/issues/2503-persist-peers-fix
Create restart.sentinel after storing the peer list
2016-09-21 10:09:05 +01:00
Adam Harrison 7a81bc2ddc Merge pull request #2510 from weaveworks/issues/2329-fix-830-flakiness
Enable unsolicited ARPs in 830 test suite
2016-09-20 17:17:19 +01:00
Martynas Pumputis cdeae04238 Create restart.sentinel after storing peer list
Otherwise, we risk to lose peer list when any failure happens after
the creation but before storing the list and as a consequence,
the weave container gets restarted.
2016-09-20 17:07:48 +01:00
Martynas Pumputis 6df2782d73 Update weaveworks/mesh submodule 2016-09-20 17:03:38 +01:00
Adam Harrison 3fc7efa536 Merge pull request #2498 from weaveworks/broken-link
fixed broken link to command line args
2016-09-20 16:40:06 +01:00
Adam Harrison a556deec78 Merge branch '1.6' 2016-09-20 16:26:48 +01:00
Adam Harrison 71e43c2023 Merge pull request #2511 from weaveworks/issues/2340-make-640-less-flaky
Filter out netns of non-existing containers
2016-09-20 15:52:54 +01:00
Bryan Boreham 370f258c3a Fix outdated option ipam-seed 2016-09-16 15:53:43 -07:00
Martynas Pumputis 9b32bc2ab3 Close opened netns 2016-09-14 16:47:40 +01:00
Martynas Pumputis fd5e1970e1 Return nil netdev if netns of container cannot be found
The change applies to GetNetDevsWithPredicate. The function calls
FindNetDevs which already does the same filtering.

The change prevents from "container-addrs" (weaveutil) returning
"unable to open X process namespace" error which happens when
a container dies while the cmd is being executed.
2016-09-14 16:47:16 +01:00
Martynas Pumputis a1de7f3eef Enable unsolicited ARPs in 830 test case
Otherwise, ping (c1->c3) after the address reuse might time out.
2016-09-14 11:05:00 +01:00
Matthias Radestock 06a63db4cf Merge branch '1.6' 2016-09-08 12:55:05 +01:00
Matthias Radestock c720ebec02 Merge pull request #2502 from weaveworks/issues/2469-supply-subnet
Pass in default subnet when creating 'weave' plugin network.

Fixes #2469.
2016-09-08 12:49:01 +01:00
Matthias Radestock 6a528409ab Merge pull request #2504 from weaveworks/check-tx-off
Check current tx value before trying to set it
2016-09-08 12:32:15 +01:00
Bryan Boreham c69e140e9e Check current tx value before trying to set it 2016-09-08 10:20:35 +01:00
Anita Buehrle 8ed0c13645 removed broken link 2016-09-06 14:36:25 +01:00
Anita Buehrle b635f9a994 fixed broken link to command line args 2016-09-06 14:36:25 +01:00
Bryan Boreham ac4246e1f5 Pass in default subnet when creating 'weave' plugin network.
New behaviour in Docker 1.12 means it disregards a plugin-supplied
address pool that overlaps an existing route, which causes a hang as
noted in #2469. When we pass in the subnet, Docker believes we really
do want that address range and avoids the hang.
2016-09-06 12:05:51 +01:00
Martynas Pumputis 06a325a05f Use weaveworks/docker/pkg/mflag everywhere 2016-09-05 17:22:28 +03:00
Martynas Pumputis 68e9bbe350 Add github.com/weaveworks/docker submodule 2016-09-05 16:16:06 +03:00
Matthias Radestock 3bd9e369cd Merge branch '1.6' 2016-09-05 12:51:30 +01:00
Matthias Radestock 3d12e8088e Merge pull request #2491 from weaveworks/switch-ci-14.04
Switch CircleCI build VM to 14.04
2016-09-05 12:49:25 +01:00
Martynas Pumputis aee35b34fe Pin joffrey/docker-py image to 1.8.1 vsn
The latest image requires 1.12.x dockerd.
2016-09-05 14:30:49 +03:00
Martynas Pumputis c06ccb3b0d Change owner of /usr/local/go on build VM
Otherwise "go get -tags netgo" fails with the permission denied error.
2016-09-05 14:30:49 +03:00
Martynas Pumputis 268bb656fc Do not fetch Google Cloud SDK
As it is already installed on CircleCI 14.04 build VMs
2016-09-05 14:30:49 +03:00
Martynas Pumputis 57357a728c Merge branch '1.6' 2016-09-05 13:48:30 +03:00
Martynas Pumputis a335c419ec Fix typo 2016-09-05 13:27:49 +03:00
Martynas Pumputis e263295720 Revert "Do not fetch Google Cloud SDK"
This reverts commit f557835ad0.
2016-08-26 14:42:50 +01:00
Martynas Pumputis 0c854f2144 Merge pull request #2489 from weaveworks/fix-mflag-missing
Use mflag package from weaveworks fork until we find a better solution
2016-08-26 12:19:59 +01:00
Alfonso Acosta bdf4debdfd Use mflag package from weaveworks fork until we find a better solution 2016-08-26 11:07:21 +00:00
Martynas Pumputis f557835ad0 Do not fetch Google Cloud SDK
As it is already installed on CircleCI 14.04 build VMs
2016-08-26 11:38:37 +01:00
Martynas Pumputis 17a7391086 Remove unused functions 2016-08-26 10:15:27 +01:00
Martynas Pumputis e65293eb50 Merge branch '1.6' 2016-08-19 14:12:26 +01:00
Martynas Pumputis 48c9547943 Update CHANGELOG.md 2016-08-19 14:11:57 +01:00
Martynas Pumputis caa6c6c931 Merge branch '1.6' 2016-08-19 11:22:07 +01:00
Martynas Pumputis 11f56031f1 Add release v1.6.1 2016-08-18 17:39:46 +01:00
Adam Harrison 2e825242cd Merge branch '1.6' 2016-08-18 11:32:43 +01:00
Adam Harrison ebe4c5b8b7 Merge pull request #2478 from weaveworks/bridge-veth-setup
Refactor: move bridge veth creation into 'init_bridge'
2016-08-18 11:31:16 +01:00
Adam Harrison 027064cbdb Merge branch '1.6' 2016-08-18 10:56:03 +01:00
Adam Harrison 9fddb827f9 Merge pull request #2442 from weaveworks/cni-setup-fixes
CNI setup fixes
2016-08-18 10:55:46 +01:00
Bryan Boreham 3162009325 Refactor: move bridge veth creation into 'init_bridge' 2016-08-17 17:33:34 +01:00
Martynas Pumputis 060f6392c7 Merge branch '1.6' 2016-08-16 18:03:00 +01:00
Martynas Pumputis 8c8c6db7dd Increase sleep time in 830_cni_plugin_test
Fix #2329
2016-08-16 18:00:46 +01:00
Matthias Radestock cd94dd0088 setup CNI on weave launch[-router]
not just `setup[-cni]`

Fixes #2435
2016-08-16 14:18:55 +01:00
Matthias Radestock afc6f49e80 mount CNI_NETNS dir, in case it is some exotic location
Fixes #2394
2016-08-16 14:18:28 +01:00
Martynas Pumputis c509b6e5bb Revert "Derive the bridge MAC from concatenated multiple sources"
This reverts commit c2083cbce0.
2016-08-15 09:48:55 +01:00
Bryan Boreham a466f55d59 Merge pull request #2462 from weaveworks/note-proxy-file
added note about net flag
2016-08-12 16:55:57 +01:00
Bryan Boreham c79b6a8bd7 Merge pull request #2460 from weaveworks/issues/2427-detect-peerid-clashes
Detect and report peer name collisions
2016-08-12 16:52:56 +01:00
Martynas Pumputis c2083cbce0 Derive the bridge MAC from concatenated multiple sources
The sources include:

- /etc/machine-id (generated by "systemd-machine-id-setup") or
  /var/lib/dbus/machine-id (generated by "dbus-uuidgen").
- /sys/class/dmi/id/product_uuid.
- /sys/hypervisor/uuid.

The product of the concatenation should produce an unique identifier
which is stable across reboots.
2016-08-11 12:01:35 +01:00
Martynas Pumputis 4157d9298d Update vendored weaveworks/mesh 2016-08-11 12:01:20 +01:00
Adam Harrison f686408808 Merge branch '1.6' 2016-08-10 14:44:25 +01:00
Adam Harrison 432e10e19f Merge pull request #2474 from weaveworks/issues/2375-check-vxlan-udp-port
Check if a vxlan vport netdev is UP after its creation
2016-08-10 14:44:11 +01:00
Adam Harrison b8c57ef10f Merge branch '1.6' 2016-08-10 13:58:53 +01:00
Adam Harrison 601bda3176 Merge pull request #2457 from weaveworks/issues/2424-weaken-tls-check
Do not fail launching the proxy if unable to detect a running instance of docker daemon
2016-08-10 13:58:42 +01:00
Martynas Pumputis d9bde790c6 Check if a vxlan vport netdev is up after its creation
This bypasses a kernel bug when the creation of vxlan vport
completes successfully regardless whether an vxlan UDP port has been
bind (http://marc.info/?l=linux-netdev&m=147075637009483&w=2).
2016-08-10 13:34:44 +01:00
Adam Harrison 5cc0826ca0 Merge branch '1.6' 2016-08-10 13:16:24 +01:00
Adam Harrison 96f2eb3ecf Merge pull request #2471 from weaveworks/cni-bridge-ip
CNI plugin assigns an IP to the bridge by itself
2016-08-10 11:49:25 +01:00
Adam Harrison e703f2f3f2 Merge branch '1.6' 2016-08-10 11:48:31 +01:00
Adam Harrison 1c0ffbc177 Stop publishing historic versions 2016-08-10 11:12:23 +01:00
Adam Harrison f544da9e19 Merge branch '1.6' 2016-08-10 10:18:01 +01:00
Adam Harrison c0592ba1b3 Merge pull request #2470 from weaveworks/no-force-tag
Remove -f flag from 'docker tag' commands
2016-08-10 10:17:06 +01:00
Bryan Boreham 0cbf5ca130 Allow 'weave create-bridge', if the user insists.
For example this is used when setting up CNI for Kubernetes, in
an environment where we know none of the bad consequences apply.
2016-08-10 10:00:17 +01:00
Adam Harrison 472eab2acd Merge pull request #2466 from weaveworks/issues/2464-enable-create-bridge
Re-enable 'weave create-bridge' in fastdp mode.
2016-08-10 09:57:40 +01:00
Bryan Boreham 7a5d7fca6c Allow 'weave create-bridge', if the user insists.
For example this is used when setting up CNI for Kubernetes, in
an environment where we know none of the bad consequences apply.
2016-08-08 17:20:25 +01:00
Bryan Boreham 081b95dfd0 CNI plugin assigns an IP to the bridge by itself
No need to call `weave expose` before use.
2016-08-08 15:28:26 +01:00
Matthias Radestock faf5b14d8b make CNI setup work on recent Docker-for-Macs
Docker for Mac 1.12.0-rc3 (as of beta18) looks for mounted paths on VM
first, and when it doesn't find them there, it assumes they refer to
paths on the Mac OS host. At which point it will complain that the
paths don't exit.

So instead we mount / since that will always exist on the VM. It's
also what we used to do already when launching the router.

Fixes #2434.
2016-08-04 22:03:39 +01:00
Bryan Boreham 38958049f4 Remove -f flag from 'docker tag' commands
This flag was deprecated in Docker 1.10 and removed in Docker 1.12.
2016-08-04 17:03:35 +01:00
Bryan Boreham 589b45dace Merge branch '1.6' 2016-08-03 14:34:49 +01:00
Bryan Boreham 7ebf3d7a88 Don't crash when dockerCli is nil 2016-08-03 14:28:05 +01:00
Anita Buehrle 3273d13666 gave points numbers for clarity 2016-08-02 16:40:16 -05:00
abuehrle 5fdbbf3722 wording formatting 2016-08-02 16:38:41 -05:00
abuehrle 14350ff463 added anchor to attaching containers 2016-08-02 16:35:52 -05:00
abuehrle 0b49c961a7 reconfigured note to include additional method 2016-08-02 16:30:32 -05:00
abuehrle 39b80f26ed made terminology consistent 2016-08-02 13:15:17 -05:00
abuehrle 74b20265e4 fixed links and some titles 2016-08-02 12:59:27 -05:00
abuehrle 358fddb958 fixed broken link and title 2016-08-02 12:52:36 -05:00
abuehrle 5c8f6175b5 added note about net flag 2016-08-02 12:34:52 -05:00
Martynas Pumputis e8d823d66b Do not fail launching the proxy if unable to detect dockerd 2016-07-28 12:53:44 +01:00
Adam Harrison 83ce5875ee Merge branch '1.6' 2016-07-28 12:52:53 +01:00
Adam Harrison ed83efbceb Merge pull request #2450 from weaveworks/eval-considered-harmless
remove dire warnings about 'eval' when using plugin
2016-07-28 12:49:55 +01:00
Adam Harrison 223116c4bf Merge pull request #2393 from weaveworks/intro-ops-guide
intro to ops guide (#2387)
2016-07-28 12:32:34 +01:00
Matthias Radestock 8056a098a8 remove dire warnings about 'eval' when using plugin
since as of #2330 the proxy ignores containers started with specified
user networks.
2016-07-28 11:49:54 +01:00
abuehrle 15a2cba7f8 added anchors to concepts 2016-07-28 11:49:06 +01:00
Anita Buehrle b37bb02a8b intro to ops guide (#2387) 2016-07-28 11:49:06 +01:00
Adam Harrison 0c14e5135a Delint (spelling error) 2016-07-28 11:48:14 +01:00
Adam Harrison f5a30c790e Merge branch '1.6' 2016-07-28 11:30:47 +01:00
Adam Harrison b06ddeb962 Merge pull request #2445 from weaveworks/fix-weave-ps
Fix "weave ps" output when weave is not running
2016-07-28 11:30:31 +01:00
Martynas Pumputis 34415c3c17 Merge pull request #2422 from weaveworks/log-resolvconf-errors
Log errors arising from reading resolv.conf
2016-07-26 18:01:33 +01:00
Matthias Radestock 6387fa8bc9 Merge branch '1.6' 2016-07-20 07:30:56 +01:00
Matthias Radestock f6e6926171 cosmetic: fix wrapped quote
apparently our wp md renderer does not handle this correctly
2016-07-20 07:09:09 +01:00
Matthias Radestock 25e7868cd5 fix some indentation in docs block quote 2016-07-20 07:03:17 +01:00
Matthias Radestock 385e6ff9b8 Merge pull request #2446 from weaveworks/explicit-sudo-s
Make use of `sudo -s` more explicit
2016-07-20 06:45:50 +01:00
Matthias Radestock 3755906689 blockquote sudo-ing 2016-07-20 06:26:23 +01:00
Matthias Radestock 63cbb34dec Make use of sudo -s more explicit
since people keep tripping over that.

Also

- add new error message spat out by recent dockers correct the socket
- URLs - they had fallen victim to a 'docker'->'Docker' replacement
- shorten the note on using the plugin
2016-07-20 06:26:03 +01:00
Adam Harrison 8ec6b699b1 Merge branch '1.6' 2016-07-18 11:48:08 +01:00
Adam Harrison 369852a3a7 Merge pull request #2430 from weaveworks/remove-duplicate-no-dns
remove duplication of `--no-dns`
2016-07-18 11:47:48 +01:00
Matthias Radestock c82be57639 Merge pull request #2423 from philwinder/docs/cni-mesos
Refactor CNI documentation.
2016-07-18 09:58:00 +01:00
Phil Winder 092c3a17d1 Change title. 2016-07-18 09:22:24 +01:00
Martynas Pumputis fd0a7efa23 Fix "weave ps" output when weave is not running
The #2418 has changed a behaviour of "weave ps" which outputs
"Link not found" in the case of weave not running. The previous
behaviour was to output an empty line.
2016-07-14 15:15:14 +01:00
Matthias Radestock 551f164ec3 Merge branch '1.6' 2016-07-12 20:47:23 +01:00
Matthias Radestock acdd739deb Merge branch 'fix-broken-link' into 1.6 2016-07-12 20:46:52 +01:00
Paul Bellamy 45e3016c6a Fixing a broken link in docs 2016-07-12 20:44:57 +01:00
Bryan Boreham 88bf64722f Merge branch '1.6' 2016-07-12 10:33:38 +00:00
Bryan Boreham c1483dbf1f Merge pull request #2418 from weaveworks/issues/2388-weave-ps
Fix "weave ps"; fixes #2388
2016-07-12 11:04:00 +01:00
Matthias Radestock d9c998b5c4 Merge pull request #2386 from weaveworks/issues/354-multicast-isolation
Provide multicast isolation with in-container-netns iptables rules

Fixes #354.
2016-07-12 09:46:14 +01:00
Adam Harrison 170e19c283 Merge branch '1.6' 2016-07-12 09:39:45 +01:00
Adam Harrison bce07b7491 Merge pull request #2439 from weaveworks/restore-script-function-grouping
refactor: restore grouping of functions in script
2016-07-12 09:39:15 +01:00
Matthias Radestock 8b5741506d refactor: restore grouping of functions in script
Recent(ish) changes placed functions in the wrong sections. Fix that
and label the sections more clearly.
2016-07-11 21:38:07 +01:00
Bryan Boreham 7c47a8ffb7 Log errors arising from reading resolv.conf 2016-07-11 12:08:04 +01:00
Matthias Radestock 791ab55875 Merge branch '1.6' 2016-07-09 05:42:02 +01:00
Matthias Radestock e642f366f5 cosmetic 2016-07-09 05:41:37 +01:00
Bryan Boreham bd1a9d020c Merge branch '1.6' 2016-07-07 11:20:50 +00:00
pidster d794b203f7 Adds ipam option to help.
Fixes https://github.com/weaveworks/weave/issues/2425
2016-07-07 11:20:00 +00:00
Matthias Radestock 7ec68119a6 remove duplication of --no-dns
This was harmless, but annoying.
2016-07-06 23:21:42 +01:00
Martynas Pumputis 71fd3b6b2b Merge remote-tracking branch 'origin/1.6' 2016-07-05 17:37:50 +01:00
Martynas Pumputis 93c60395f6 Merge pull request #2417 from weaveworks/issues/1852-less-logging
Move 'ODP miss' log from every miss to specific places

Fixes #1852
2016-07-05 17:34:57 +01:00
Phil Winder af27aa04f2 Add Mesos instructions. Edit old links. 2016-07-05 16:01:01 +01:00
Martynas Pumputis 0861d05522 Address PR comments
- Do not re-enter the root netns when querying weave bridge.
- Enter the root netns when constructing the predicate.
2016-07-05 15:12:39 +01:00
Martynas Pumputis 89221f117b Denote WithNetNS* functions with unsafe
Please see https://github.com/weaveworks/weave/issues/2388#issuecomment-228365069
for more details.
2016-07-05 15:12:39 +01:00
Martynas Pumputis 7f5c37ef1e Fix "weave ps"
Make sure that any network namespace changes happens at the end of
the cmd invocation. Otherwise, we are risking to end up in a situation
in which OS scheduling threads are in a "wrong" namespace.

See WithNetNS for more details.
2016-07-05 15:12:39 +01:00
Martynas Pumputis 05baa566c6 Refactor common.GetBridgeNetDev
- Optimize. Use LinkByName instead of iterating over list of available
  links. Linux does not support interfaces with the same names.
- Remove unnecessary indirection in utility functions which return
  common.NetDev.
2016-07-05 15:12:39 +01:00
Bryan Boreham f8ac27a6cc Merge branch '1.6' 2016-07-05 13:22:25 +01:00
Bryan Boreham e5c23bf9f5 Don't crash if docker API is disabled by params 2016-07-05 13:02:59 +01:00
Matthias Radestock 954cd0b86a Merge branch '1.6' 2016-07-04 16:27:59 +01:00
Matthias Radestock 0635ed1854 highlight the need for weave expose in CNI/k8s (#2411)
* highlight the need for `weave expose` in CNI/k8s

Fixes #2405

* Extend error message

* rearranged the sentences

weave launch <peer hosts> seems a bit orphaned here maybe include the weave connect command as well, since it's being mentioned.
2016-07-04 16:27:11 +01:00
Matthias Radestock 9dedeadf15 Merge branch '1.6' 2016-07-04 16:22:42 +01:00
Matthias Radestock 4424e877f0 Merge branch '1710-lb-clarification' into 1.6 2016-07-04 16:21:54 +01:00
Matthias Radestock 6561272f8d Merge branch '1.6' 2016-07-04 16:20:37 +01:00
Matthias Radestock aa54d332c2 correct RFC3484 address selection caveat (#2407)
and move it to a more prominent location

Fixes #1710
2016-07-04 16:20:19 +01:00
Matthias Radestock 881e795db5 correct RFC3484 address selection caveat (#2407)
and move it to a more prominent location

Fixes #1710
2016-07-04 16:19:20 +01:00
Matthias Radestock 4216231ec7 Merge branch '1.6' 2016-07-04 14:30:03 +01:00
Matthias Radestock e5aeb4bd05 improve --trusted-subnets docs (#2415)
improve --trusted-subnets docs

Fixes #2211
2016-07-04 14:28:11 +01:00
Matthias Radestock 333d5f7511 Merge pull request #2412 from weaveworks/1803-plugin-create
Refactor plugin to create veths in CreateEndpoint



Fixes #1803.
2016-07-04 12:19:01 +01:00
Matthias Radestock 7be7945b29 Merge branch '1.6' 2016-07-04 10:08:43 +01:00
Matthias Radestock 566ed64607 Merge pull request #2413 from weaveworks/2347-document-host
document --host

Fixes #2347.
2016-07-04 10:07:48 +01:00
Anita Buehrle 83c358c8d2 edited sentence 2016-07-03 09:51:52 -05:00
Bryan Boreham afe882cd94 Use more chars from endpointID to reduce clashes in veth names
Import library to get max name length IFNAMSIZ
2016-07-01 16:05:02 +01:00
Matthias Radestock 5b8a359475 Merge branch '1.6' 2016-07-01 10:31:39 +01:00
Matthias Radestock ae95248499 Merge remote-tracking branch 'upstream/issues/2293-warn-router-down' into 1.6 2016-07-01 10:31:12 +01:00
Matthias Radestock df0af203f8 Merge pull request #2416 from weaveworks/issues/2293-warn-router-down
Check that weave router is running before launching plugin

Fixes #2293.
2016-07-01 10:24:15 +01:00
Bryan Boreham 53b8c804f2 Launch the whole of weave to avoid tripping over plugin-only test 2016-07-01 10:17:05 +01:00
Bryan Boreham 7d0aaea6e8 Move 'ODP miss' log from every miss to specific places
Added log lines for packets that we will broadcast;
Added log lines for flows we don't know how to handle;
Moved the line for when we expect to insert a flow down to the miss-handler;
Packets handled by the bridge already have their own logging via --pktdebug
2016-07-01 10:12:53 +01:00
Bryan Boreham 45a66ac517 Extend 'mac associated with other peer' error info 2016-06-30 18:02:39 +01:00
Bryan Boreham 087d948941 Check that weave router is running before launching plugin 2016-06-30 12:02:52 +01:00
Matthias Radestock 5b2a4ff614 Merge branch '1.6' 2016-06-29 20:12:58 +01:00
Matthias Radestock 72e92db96e document --host
and add some broader points about access control early on, since some
users will wonder about that right from the start.

Fixes #2347
2016-06-29 20:09:02 +01:00
Matthias Radestock 768414534f cosmetic: more logical order of args in usage 2016-06-29 20:00:47 +01:00
Bryan Boreham ceb5f8c714 Move endpoint creation into CreateEndpoint so we can return the MAC address 2016-06-29 17:38:07 +01:00
Bryan Boreham cc3359dfe5 Merge branch '1.6' 2016-06-29 14:42:17 +01:00
Bryan Boreham f1ca4854b8 Merge pull request #2409 from weaveworks/issues/2381-awsvpc-fix-attach-router
Fix re-attaching of weave router in awsvpc mode
2016-06-29 14:41:14 +01:00
Martynas Pumputis 6319860230 Change the order of awsvpc initialization
We want to setup the necessary arp settings as soon as possible
and before we re-insert DNS entries. Otherwise, the announced
containers might not be reachable.

Also, do not try to reclaim for weave:expose inside populate_router,
because we do expose before calling it.
2016-06-29 11:15:56 +01:00
Martynas Pumputis 58caf38f07 Fix re-attaching of weave router in awsvpc mode
In order to re-attach the router and make it work in awsvpc mode,
the following has to be done:

- expose_ip on the router
- adjusting arp settings
- restoring host routes

To detect that we run in awsvpc mode, we inspect cmd parameters
of the weave router instead of GET'ing /ipinfo/tracker. This is so,
because the HTTP server started by the router might not be running
at the time of restoration.
2016-06-29 11:15:49 +01:00
Matthias Radestock cb4b5fd143 correct RFC3484 address selection caveat
and move it to a more prominent location

Fixes #1710
2016-06-29 06:57:17 +01:00
Matthias Radestock cda6785f1d Merge remote-tracking branch 'upstream/master' 2016-06-29 05:58:29 +01:00
Matthias Radestock cb030be4ad Merge branch '1.6' 2016-06-29 05:57:01 +01:00
Matthias Radestock 7165414fc3 improve clock skew error message
Fixes #2174
2016-06-29 05:48:10 +01:00
Bryan Boreham b464ce86f7 Merge branch '1.6' 2016-06-28 13:36:10 +00:00
Bryan Boreham d72d3af36e Remove deprecated -awsvpc option 2016-06-28 13:35:47 +00:00
Adam Harrison 80b3514e24 Merge branch '1.6' 2016-06-20 16:29:29 +01:00
Adam Harrison f07ed7153b Remove link to non-existent blog post 2016-06-20 15:32:00 +01:00
Adam Harrison e33f56f9b0 Merge branch '1.6' 2016-06-20 14:53:03 +01:00
Adam Harrison 6c46af25cc Fix typo 2016-06-20 14:47:52 +01:00
Adam Harrison 5ad227a8b3 Add release v1.6.0 2016-06-20 13:50:19 +01:00
Matthias Radestock 67fe1e5daf clarify init-peer-count deprecation warning
Fixes #2355
2016-06-20 03:54:16 +01:00
Matthias Radestock 99b475056a Merge branch '1.5' 2016-06-20 03:25:10 +01:00
Martynas Pumputis 804f4ad971 Add check-datapath to weaveutil
The utility is used to check whether a datapath can be created.
2016-06-20 03:24:30 +01:00
Martynas Pumputis 24d9a00f47 Add check-datapath to weaveutil
The utility is used to check whether a datapath can be created.
2016-06-20 03:20:46 +01:00
Matthias Radestock b00e7d088e Merge pull request #2372 from weaveworks/issues/2310-more-checkpoint
Add kernel version, Docker version and awsvpc setting to checkpoint info

Fixes #2310
2016-06-20 03:15:25 +01:00
Bryan Boreham c12e909882 Document what is sent in checkpoint request 2016-06-20 03:13:10 +01:00
Anita Buehrle 6356fbc882 Ops edits (#2371) 2016-06-20 03:04:53 +01:00
Matthias Radestock ca7220b775 Merge branch '1.5' 2016-06-19 02:51:52 +01:00
Matthias Radestock 619a02eefb fix a couple of typos 2016-06-19 02:51:11 +01:00
Martynas Pumputis 85c1a31e5c Merge pull request #2383 from weaveworks/proxy-buffer
Use buffered writer for http headers
2016-06-17 17:29:39 +01:00
Adam Harrison f386548890 Maintain per-subnet ACCEPT rule for multicast ingress 2016-06-17 17:19:52 +01:00
Bryan Boreham f86ade6568 Squash up the code via 'defer' 2016-06-17 16:52:17 +01:00
Bryan Boreham 81fa4059df Use buffered writer for http headers 2016-06-17 16:52:17 +01:00
Adam Harrison c80d87554a Maintain per-interface DROP rule for multicast ingress 2016-06-17 16:10:13 +01:00
Matthias Radestock e77bf60d34 Merge branch '1.5' 2016-06-17 15:48:33 +01:00
Matthias Radestock 61cb5535db Merge pull request #2385 from weaveworks/2286-fix-check
Fix check before removing plugin sockets

Fixes the fix in #2292.
2016-06-17 15:47:48 +01:00
Bryan Boreham 63314beb2a Remove plugin sockets in 'weave reset' 2016-06-17 15:17:13 +01:00
Bryan Boreham 2d0be34a93 Fix check to see if plugin is running 2016-06-17 15:17:13 +01:00
Matthias Radestock 0abfdf4efb Merge branch '1.5' 2016-06-17 15:07:34 +01:00
Matthias Radestock b014de3f08 Merge pull request #2382 from weaveworks/issues/2379
Fix Docker 1.12 incompatibilities

Fixes #2379.
2016-06-17 15:06:55 +01:00
Bryan Boreham 56c275a9bf Copy Docker's response code through for raw stream.
This means when Docker says "101 UPGRADED" the proxy will say the
same, instead of "200 OK".  Docker 1.12 barfs if you do that.
2016-06-17 13:07:04 +01:00
Bryan Boreham ddd039761d Handle Docker daemon named 'dockerd' 2016-06-17 13:05:35 +01:00
Adam Harrison f4798fadf8 Merge pull request #2374 from weaveworks/issues/1726-plugin-arp
Perform arp configuration for plugin-connected containers
2016-06-17 10:19:53 +01:00
Bryan Boreham adda1c459c Fix plugin filter - truncate Docker ID to 12 chars 2016-06-16 18:03:45 +01:00
Matthias Radestock 979df93bff Merge pull request #2378 from weaveworks/issues/2364-observe-resolv-conf
Observe resolv.conf changes

Fixes #2364.
2016-06-16 17:13:10 +01:00
Adam Harrison 27e7ec08d4 Observe resolv.conf changes 2016-06-16 16:55:40 +01:00
Adam Harrison c6a777c4b0 Merge pull request #2366 from weaveworks/issues/2189-publish-weavedb
Publish weavedb container from release script
2016-06-16 11:03:27 +01:00
Bryan Boreham 7182ec0463 Merge pull request #2338 from weaveworks/awsvpc-docs
awsvpc docs
2016-06-15 16:59:54 +01:00
Bryan Boreham 425f17aab1 Mention that 'weave launch' now waits 2016-06-15 16:58:05 +01:00
Bryan Boreham 3494cc39c1 Expand description surrounding link to awsvpc mode 2016-06-15 16:58:05 +01:00
Bryan Boreham 2face0f318 Publish weavedb container from release script 2016-06-15 15:50:37 +01:00
Bryan Boreham bb203a2d18 Merge branch '1.5' 2016-06-15 13:50:47 +01:00
Bryan Boreham 95b42a532a Merge pull request #2367 from weaveworks/issues/2290-own-image
Use our own ubuntu image
2016-06-15 13:50:26 +01:00
Bryan Boreham 08e2c5c14e Fix link for 'docker run' docs 2016-06-15 13:48:25 +01:00
Bryan Boreham a4f3e763bb Use our own ubuntu image 2016-06-15 13:47:20 +01:00
Bryan Boreham 06feefe80f Merge branch '1.5' 2016-06-15 11:12:12 +01:00
Bryan Boreham 3dd7e13cc0 Merge pull request #2369 from weaveworks/issues/2335
Describe creating multiple networks using the plugin
2016-06-15 11:11:25 +01:00
Bryan Boreham fdf3afa935 Review feedback 2016-06-15 11:10:13 +01:00
Bryan Boreham 8bb8f70bb6 Perform arp configuration for plugin-connected containers 2016-06-14 17:53:34 +01:00
Bryan Boreham c71c630cf6 Use driver name to detect 'our' endpoints
so we don't have to remember all the endpoint IDs, or load them up
after a restart.
2016-06-14 17:52:45 +01:00
Matthias Radestock 179b6f7cf9 Merge pull request #2368 from weaveworks/small-doc-fixes
Small doc fixes
2016-06-14 16:26:17 +01:00
Bryan Boreham 1fe5c65fd4 Add kernel version, Docker version and awsvpc setting to checkpoint info 2016-06-14 12:24:37 +01:00
Bryan Boreham e1edce84d9 Extract checkForUpdates to its own file 2016-06-14 10:33:46 +01:00
Martynas Pumputis 73a393823a Merge pull request #2370 from weaveworks/awsvpc-clashes
Report a couple of options that are incompatible with --awsvpc
2016-06-14 10:12:37 +01:00
Bryan Boreham b32da8d69f Report a couple of options that are incompatible with --awsvpc 2016-06-13 16:53:27 +01:00
Bryan Boreham b993fd67ab Describe creating multiple networks using the plugin 2016-06-13 16:49:55 +01:00
Bryan Boreham e9770740d8 Use short name rather than long hex ID 2016-06-13 16:20:32 +01:00
Bryan Boreham 7abed164eb Clean up reference to 'above' 2016-06-13 16:11:01 +01:00
Matthias Radestock 7a1bd27a58 Merge branch '1.5' 2016-06-13 15:24:49 +01:00
Matthias Radestock aca34191da Merge pull request #2365 from weaveworks/issues/2283-validate-cidrs
Validate CIDRs in proxy before attaching a container

Fixes #2283
2016-06-13 15:15:48 +01:00
Martynas Pumputis df5508c0f3 Check CIDRs before attaching a container in proxy
If any cidr is invalid, a user will get the following error:
"docker: Error response from daemon: invalid WEAVE_CIDR: $CIDR".
2016-06-13 14:54:16 +01:00
Bryan Boreham e63fd0b38f Merge branch '1.5' 2016-06-13 12:00:46 +01:00
Bryan Boreham 47878cf5b6 Merge pull request #2362 from weaveworks/checkpoint-doc
Re-instate mention of checkpoint on install page
2016-06-13 11:13:16 +01:00
Anita Buehrle f0ea18171b tweaked the sentence a little 2016-06-13 10:57:35 +01:00
Bryan Boreham aa3f40ec8d Re-instate mention of checkpoint on install page lost in d1e004dedc 2016-06-13 10:57:19 +01:00
Bryan Boreham bf8c8833e5 Merge pull request #2356 from weaveworks/issues/2322-awsvpc-enhance
Transfer IPAM ranges to UnknownPeer if no peer is found during Shutdown
2016-06-10 14:00:36 +01:00
Martynas Pumputis 8569cbd4a3 Force transferring of IPAM ranges in a case of Shutdown
If no peer for transfer is found, we transfer them to
mesh.UnknownPeerName to notify the ring update tracker.

Makes the awsvpc tracker to remove local entries from
the VPC route table when the last peer calls "weave reset".
2016-06-10 11:51:31 +01:00
Adam Harrison adcb1018df Merge pull request #2345 from weaveworks/issues/2344-persist-more
Fix ring persistence after free space update
2016-06-09 16:37:57 +01:00
Adam Harrison f4b9a9b66c Merge pull request #2352 from weaveworks/issues/2318-moar-help
Print usage on --help argument to any command
2016-06-09 16:02:35 +01:00
Bryan Boreham 52d911c8c1 Merge branch '1.5' 2016-06-09 13:06:41 +00:00
Bryan Boreham d1314dd248 Fix broken link 2016-06-09 13:05:39 +00:00
Bryan Boreham 5db7a2bae1 Print usage on --help argument to any command 2016-06-09 12:44:37 +00:00
Bryan Boreham 71540e6c6d Clarify IAM role and policy 2016-06-09 10:41:34 +00:00
Anita Buehrle 3c45ba09f9 A few edits to improve awsvpc docs.
Fixed up the notes with spaces and bolding
Fixed some awkwardness in first paragraph
Fixed a couple of other sentences
2016-06-09 10:40:46 +00:00
Bryan Boreham cf87a84bd9 Merge pull request #2341 from weaveworks/issues/2017-awsvpc
Add AWSVPC. Fixes #2017
2016-06-08 17:24:55 +01:00
Bryan Boreham c77b2e8fb3 Tell the proxy that multicast is off in awsvpc mode.
Otherwise it will use the regular weavewait program which wait for the
multicast route to be added.
2016-06-08 16:44:54 +01:00
Bryan Boreham 37fd54f20b Perform AWSVPC checks for attach in script rather than in weaveutil 2016-06-08 16:44:54 +01:00
Martynas Pumputis fb9b4ddec0 Enable AWSVPC
This requires the following additional steps:

- Setting proxy_arp on on the bridge, because that's how we do
  the routing (check the comment at the place where we set it on).
- Disable ARP requests queueing, because it introduces unnecessary
  delay for the first ARP request resulting in a high latency of
  the first packet (on t2.micro machines I've encountered ~700ms
  latency). Also, the queue is bounded, so we might risking to drop
  the requests.
2016-06-08 16:44:54 +01:00
Martynas Pumputis 7670fed72c Add AWSVPC setup routines to the attach script
When running in the AWSVPC mode, we need to do the following:

- Keep the HW TX offloading on.
- Check that the allocated address belongs to the default subnet,
  because only one subnet is allowed and it should be the default one.

If it is not possible to determine whether AWSVPC is on, we ignore
all the steps, because the attachment routines have to work
regardless whether the router is running and the AWSVPC detection
is done by querying the /ipinfo/tracker endpoint served by
the router.
2016-06-08 16:44:54 +01:00
Martynas Pumputis de2a70861c Add GET /ipinfo/tracker
The endpoint returns the name of tracker. It is used to determine
whether the router is running a tracker.
2016-06-08 16:44:54 +01:00
Martynas Pumputis 9fc7be83c8 Create a Tracker when starting the router
The tracker's HandleUpdate method is called by the ring update routines.

In addition, we add a dummy overlay for AWSVPC to make `weave (status|
report)` to produce reasonable reports which includes AWS hosts
connection state.
2016-06-08 16:44:54 +01:00
Martynas Pumputis c260536429 Add AWSVPC Tracker
The tracker is responsible for managing the AWSVPC route tables
which is used to implement the underlay routing based on VPC.
2016-06-08 16:44:54 +01:00
Martynas Pumputis 59b3a3c8c5 Add the Tracker interface
An instance of the interface must implement the HandleUpdate method
which (in the future) will be called when any change to the IPAM ring
occurs.
2016-06-08 16:44:54 +01:00
Martynas Pumputis 49f2e208c3 Make ClaimForPeers to claim CIDR-aligned ranges 2016-06-08 16:44:54 +01:00
Martynas Pumputis 2266868648 Add the range.CIDRs functions 2016-06-08 16:44:54 +01:00
Bryan Boreham d1bba977f3 Don't stop reporting free space at the first unchanged range 2016-06-08 11:53:35 +01:00
Bryan Boreham e2bee6e8c6 Persist ring after updates caused by reportFreeSpace() 2016-06-08 11:52:38 +01:00
Bryan Boreham 6062627582 Merge branch '1.5' 2016-06-08 11:00:57 +01:00
Anita Buehrle efee8e73c6 minor edits also added link to guide 2016-06-08 11:00:33 +01:00
Bryan Boreham 37f820a168 Fail the script if any of the background tasks fails 2016-06-07 14:37:43 +01:00
Bryan Boreham c41ca708f3 Add AWS-VPC diagram 2016-06-07 13:58:22 +01:00
Bryan Boreham 73d7812dc5 Check that latest version of weave image exists
The smoke-tests are meant to be run in a context where you have just
uploaded a build. If that upload failed and we don't do this check
then we will download the 'latest' images from DockerHub.
2016-06-07 13:29:44 +01:00
Bryan Boreham 6a410a7749 Minor improvements 2016-06-07 13:01:42 +01:00
Adam Harrison 843a993600 Merge pull request #2332 from weaveworks/issues/2326-warn-rmpeer
Warn on 'weave reset' if DELETE fails
2016-06-06 16:56:38 +01:00
Bryan Boreham 0fc59a831c Initial awsvpc docs 2016-06-06 16:47:23 +01:00
Matthias Radestock 7ffbeead8d Merge pull request #2327 from weaveworks/issues/1960-mcast-option
Add an option to disable multicast route per-network

Fixes #1960.
2016-06-06 15:49:09 +01:00
Bryan Boreham 9a17439e2f Warn on 'weave reset' if weave container is not running 2016-06-06 15:46:30 +01:00
Bryan Boreham ab74d7b438 Improve plugin multicast docs 2016-06-06 15:41:21 +01:00
Adam Harrison d4de48aeee Merge branch '1.5'
Closes #2302
2016-06-06 15:21:54 +01:00
Adam Harrison eaa4bd1a6c Merge pull request #2333 from weaveworks/issues/2302-symlink-loop
Check if socket is identical to weave socket after trimming prefix.
2016-06-06 15:20:23 +01:00
Bryan Boreham c380a6f4ee Improve handling of build container
- Only mention the need for it on the one rule where it gets used.
- Don't delete it in `make clean-bin`.
2016-06-06 14:04:33 +01:00
Matthias Radestock faef371a8c Merge branch '1.5' 2016-06-06 11:51:19 +01:00
Bryan Boreham 39ba706a9b Run just one container to build all exes 2016-06-06 11:43:08 +01:00
Matthias Radestock aa4980bbda remove plugin cluster store section
it served no purpose and was misleading
2016-06-06 11:36:18 +01:00
Matthias Radestock 7f5bf67d33 cosmetic: fix some styling in plugin docs 2016-06-06 11:33:38 +01:00
Matthias Radestock e7e27796e4 eliminate some duplication in the plugin docs 2016-06-06 11:32:57 +01:00
Matthias Radestock 2491f49243 tweak plugin config docs 2016-06-06 11:32:15 +01:00
Matthias Radestock c25281e827 remove dead link 2016-06-06 11:30:10 +01:00
Matthias Radestock a4cd4d5a2f tweak plugin pitch 2016-06-06 11:22:07 +01:00
Bryan Boreham c6d1adf220 Revert "Do a build before the 'go test'"; it doesn't look like this goes faster after all
This reverts commit bd7e5d6921.
2016-06-05 14:56:05 +01:00
Bryan Boreham 5dd7590e5c Merge pull request #1978 from weaveworks/weave-1.5-doc-updates
Operational guide. Fixes #726, fixes #1102
2016-06-03 17:30:06 +01:00
Adam Harrison e092a517aa Operational guide 2016-06-03 17:12:29 +01:00
Adam Harrison 9b6154cf63 Merge pull request #2331 from weaveworks/issues/2320-plugin-warning
Augment warning on active plugin endpoints
2016-06-03 16:17:31 +01:00
Adam Harrison 1e4d86775f Merge pull request #2330 from weaveworks/issues/1988-proxy-plugin
Proxy shouldn't weave-attach containers which are using a network plugin
2016-06-03 15:48:35 +01:00
Bryan Boreham 2728bc0f9d Merge pull request #2305 from weaveworks/issues/2186-peer-list-persistence
Peer list persistence; Fixes #2186.
2016-06-03 14:31:01 +01:00
Bryan Boreham dac2124cd1 Don't weave-attach containers which are using a network plugin
Particularly intended for cases where the user has configured the
proxy and also said --net=weave, but will catch any other plugin
similarly
2016-06-03 14:11:15 +01:00
Anita Buehrle 37f5a17953 Update docs 2016-06-03 13:53:07 +01:00
Adam Harrison f9dd763774 Peer list persistence smoke test 2016-06-03 13:53:07 +01:00
Adam Harrison 4b758dd130 Implement weave launch --resume 2016-06-03 13:53:07 +01:00
Adam Harrison 5e03c0fe25 Revert #1967 (container reuse) 2016-06-03 13:53:07 +01:00
Adam Harrison 166d4afad8 Use persisted peer list on Docker restart 2016-06-03 13:53:07 +01:00
Bryan Boreham 153ed601be Check if socket is identical to weave socket after trimming prefix.
This allows us to run 'weave proxy -H /var/run/weave/weave.sock'
2016-06-03 13:34:43 +01:00
Bryan Boreham cbf4a0facd Move warning on plugin active into Go code 2016-06-02 17:19:51 +01:00
Bryan Boreham a1c3cba363 Invert multicast option in plugin
Now it's off by default, and there is an option to enable the
multicast route per-network.
We turn it on for the `weave` network created when we start the plugin.
2016-06-02 12:52:30 +01:00
Bryan Boreham 1d91c1a23b Cleanup: change ring test from 255 to 256 in length, which is more realistic 2016-06-01 17:51:21 +01:00
Martynas Pumputis f50fbc002e Change ipam Universe from Range to CIDR
There was no code to initialize it as anything else, and this lets us
bake in an assumption that it will always be a CIDR.
2016-06-01 17:06:31 +01:00
Adam Harrison dbc8b4fe1a Updated badges 2016-06-01 14:43:23 +01:00
Matthias Radestock b1fa417381 Merge branch '1.5' 2016-05-27 19:34:51 +01:00
Matthias Radestock 912e8fe119 Merge pull request #2323 from weaveworks/name-tests-properly
Name tests so they are picked up by runner
2016-05-27 19:33:34 +01:00
Bryan Boreham e2294482a6 Refactor: extract functional parts of weave export so they can be called from elsewhere 2016-05-27 16:52:53 +01:00
Adam Harrison b4fda4c98e Name tests so they are picked up by runner 2016-05-27 16:47:47 +01:00
Bryan Boreham d9da08792f Merge branch '1.5' 2016-05-27 13:40:29 +01:00
Bryan Boreham bf040105da Speed up smoke-tests by reducing timeout on 'docker stop' 2016-05-27 13:15:32 +01:00
Bryan Boreham e8ca085758 Merge branch '1.5' 2016-05-26 16:30:26 +00:00
Bryan Boreham 7300c33793 Add release v1.5.2 2016-05-26 16:10:07 +00:00
Bryan Boreham f5cd7b5073 Remove 'make update' from release process now we vendor dependencies 2016-05-26 16:10:07 +00:00
Adam Harrison f02b78ed73 Merge branch '1.5'
Closes #2282
2016-05-26 16:16:54 +01:00
Adam Harrison b3379df53d Merge pull request #2321 from weaveworks/issues/2282-check-subnets
Check validity of IP subnets
2016-05-26 16:16:39 +01:00
Adam Harrison c9525532ea Merge branch '1.5'
Closes #2300
2016-05-26 16:08:14 +01:00
Adam Harrison 654a811ef0 Merge pull request #2319 from weaveworks/issues/2300-spot-gateway
Don't release fake gateway address in plugin
2016-05-26 16:07:39 +01:00
Bryan Boreham cda1084777 Check validity of IP subnets
Be more consistent about this - check in the same way whether at startup
or during allocation.
2016-05-26 14:31:17 +00:00
Bryan Boreham fd257f43d1 Don't release fake gateway address
Watch out for Docker releasing the fake gateway address we create when
the network is set up, and don't pass it on to Weave IPAM.
2016-05-26 12:30:03 +00:00
Bryan Boreham 8ff814d976 Plugin and weaveutil depend on networking code 2016-05-26 11:35:10 +00:00
Bryan Boreham 7c819e7f5c Merge branch 'issues/1940-remove-proxy-attach-dep' 2016-05-26 11:33:37 +00:00
Bryan Boreham b417696c66 Wait 1ms before sending gratuitous arp 2016-05-26 11:17:04 +00:00
Martynas Pumputis f0109c1920 Merge pull request #2307 from weaveworks/issues/1940-remove-proxy-attach-dep
Move container attachment from sh to Go
2016-05-26 10:11:02 +01:00
Bryan Boreham 6dd109a5bb Only do ethtool tx off in bridged (pcap) mode.
Detect the bridge type in the same way the weave script does.
2016-05-25 17:34:13 +01:00
Bryan Boreham 2702b85ee5 Improve veth name construction; use a constant instead of "ethwe" 2016-05-25 17:34:13 +01:00
Bryan Boreham 8717fd15ed Use 'peer' and 'veth' instead of 'guest' and 'local', after review comments 2016-05-25 17:34:13 +01:00
Bryan Boreham 161446d55d Move error detection for attach() into Go 2016-05-25 17:34:13 +01:00
Bryan Boreham ac14b19db8 Move attach() and detach() from shell script to Go 2016-05-25 17:34:13 +01:00
Adam Harrison e3ef473cd3 Utility function to disable tx checksum offload 2016-05-25 17:29:45 +01:00
Bryan Boreham 4fc2835d92 Extract AddRoute function 2016-05-25 17:29:45 +01:00
Bryan Boreham 85023e0a76 Extract AttachContainer() function
Also move netlink and netns code from common to net

Creates interface if not already there
Adds addresses
Move the set link 'up' to after addresses are added
2016-05-25 17:29:45 +01:00
Bryan Boreham 0257274aa8 Extract basic veth setup 2016-05-25 17:23:49 +01:00
Bryan Boreham 9aaa7f19fd initialize via sub-function 2016-05-25 17:17:19 +01:00
Bryan Boreham 9f8b94645d Obtain IP address before setting up veth 2016-05-25 17:17:19 +01:00
Bryan Boreham c458deaf80 Slight cleanup 2016-05-25 17:17:19 +01:00
Bryan Boreham d59c170cd5 Remove veth on error 2016-05-25 17:17:19 +01:00
Bryan Boreham f11d91badf Extract veth creation and LinkSetUp to net package 2016-05-25 17:17:19 +01:00
Martynas Pumputis c63619bf7d Merge remote-tracking branch 'origin/1.5' 2016-05-25 17:09:48 +01:00
Martynas Pumputis d9d1956e0c Merge pull request #2313 from weaveworks/cni-gratuitous-arp
Send out arp update from CNI plugin
2016-05-25 17:06:10 +01:00
Bryan Boreham f695b3fd17 Smoke-test CNI arp update 2016-05-25 12:05:20 +01:00
Bryan Boreham ede00047db Send out arp update from CNI plugin 2016-05-25 12:05:20 +01:00
Adam Harrison 52377df340 Merge branch '1.5' 2016-05-24 17:10:52 +01:00
Adam Harrison 424d331a32 Merge pull request #2314 from weaveworks/disable-doc-previews
Temporarily disable doc previews
2016-05-24 17:10:28 +01:00
Adam Harrison fbbbb924a3 Temporarily disable doc previews 2016-05-24 16:46:41 +01:00
Matthias Radestock caeff127c9 Merge branch '1.5' 2016-05-24 11:27:42 +01:00
Bryan Boreham 56145ba518 Merge pull request #2311 from weaveworks/issues/2306-proxy-swarm-pending
Flush chunked response header immediately; fixes #2306.
2016-05-24 10:36:09 +01:00
Adam Harrison 885b6195f6 Flush chunked response header immediately 2016-05-24 08:28:24 +01:00
Bryan Boreham df3ccd362a Merge branch '1.5' 2016-05-19 15:58:55 +01:00
Bryan Boreham 5ed18994cd Send error messages about incompatible bridge settings to stderr 2016-05-19 15:58:15 +01:00
Adam Harrison 4dca07c9ff Merge pull request #2296 from weaveworks/issues/2284-die-another-way
Move kill-on-failure responsibility to caller of weave script
2016-05-18 12:19:44 +01:00
Adam Harrison b16de0c71e Merge pull request #2299 from weaveworks/issues/fix-offset-abuse
Change the type of entry.Free to address.Count
2016-05-18 12:04:54 +01:00
Adam Harrison a131703b2d Merge remote-tracking branch 'origin/1.5' 2016-05-18 10:29:55 +01:00
Adam Harrison 78672db440 Merge pull request #2292 from weaveworks/issues/2286-hang-torpedoes
Protect against Docker hanging trying to talk to a non-existent plugin
2016-05-18 10:27:13 +01:00
Adam Harrison 5b4906f822 Merge branch '1.5' 2016-05-18 09:46:01 +01:00
Adam Harrison ee9f8eec1c Merge pull request #2291 from weaveworks/issues/refactor-check-attached
Refactor wait_for_{proxy,attached}
2016-05-18 09:44:15 +01:00
Adam Harrison dc0e25a420 Add .ackrc which excludes vendor/ and .pkg/ 2016-05-17 10:37:56 +01:00
Martynas Pumputis 85cea672d3 Change the type of entry.Free to address.Count
This change is backward compatible, because the underlying types of
address.Offset (the previous type) and address.Count are the same
and the Gob encoder does not require types to exactly correspond.
2016-05-16 15:03:05 +01:00
Bryan Boreham ff81ecfd41 Move kill-on-failure responsibility to caller of weave script 2016-05-16 13:38:22 +01:00
Martynas Pumputis ef5f80a05a Merge pull request #2287 from weaveworks/donate-cidr-aligned
Donate CIDR-aligned ranges instead of just slicing at the mid-point.
2016-05-16 12:40:17 +01:00
Bryan Boreham d551b6b0a8 Review feedback 2016-05-13 16:27:28 +01:00
Bryan Boreham 1ec2c0fb3f Use a CIDR-aligned CIDR in unit tests 2016-05-13 16:27:28 +01:00
Bryan Boreham d1e2aa6d36 Use quick.Check instead of many specific tests 2016-05-13 16:27:28 +01:00
Bryan Boreham 64dc7a1f69 Donate power-of-2-aligned ranges instead of just slicing at the mid-point.
Also fix up space tests to match.
2016-05-13 16:27:28 +01:00
Bryan Boreham bc79a9187f Protect against Docker hanging trying to talk to a non-existent plugin
Remove the Unix socket from the filesystem before doing volume
operations, if the plugin is not running.
2016-05-12 15:40:04 +00:00
Martynas Pumputis 02d9c090ed Add wait_for_attached 2016-05-12 12:25:59 +01:00
Martynas Pumputis 671ed724d5 Move wait_for_proxy to config.sh 2016-05-12 12:15:20 +01:00
Bryan Boreham f37e742536 Merge branch '1.5' 2016-05-12 11:00:14 +00:00
Bryan Boreham 6c7f860418 Merge pull request #2278 from weaveworks/issues/fix-320-claim-test
Fix 320_claim_3_test.sh
2016-05-12 11:59:14 +01:00
Bryan Boreham 79d78ae97b Merge branch '1.5' 2016-05-12 09:57:48 +00:00
Bryan Boreham 4ff574744e Use ubuntu:trusty to ensure 'nc' is available 2016-05-12 09:53:29 +00:00
Martynas Pumputis 7c3e937ae8 Fix 320_claim_3_test 2016-05-11 12:18:39 +01:00
Martynas Pumputis 178438c470 Merge branch '1.5' 2016-05-10 17:36:56 +01:00
Martynas Pumputis 632694472c Merge pull request #2281 from weaveworks/issues/2275-request-order
Ignore IPAM requests for space until we have a ring

Fixes #2275
2016-05-10 17:36:26 +01:00
Martynas Pumputis 14e1145972 Merge branch '1.5' 2016-05-10 17:34:08 +01:00
Martynas Pumputis 8df1aa48a5 Merge pull request #2280 from weaveworks/sleep-perchance
Move sleep on reset from IPAM Allocator to weave script
2016-05-10 17:33:30 +01:00
Bryan Boreham 16b75f899e Move sleep on reset from IPAM Allocator to weave script 2016-05-10 16:03:08 +01:00
Bryan Boreham c3abe4f7b2 If we don't have a ring, just ignore a request for space. 2016-05-10 15:33:13 +01:00
Bryan Boreham f800813031 Test claim as first operation 2016-05-10 15:32:15 +01:00
Martynas Pumputis f7bddab4cb Merge branch '1.5' 2016-05-10 15:27:15 +01:00
Martynas Pumputis c434345960 Fix typo 2016-05-10 15:24:38 +01:00
Martynas Pumputis f9157acced Fix logging 2016-05-10 15:18:10 +01:00
Bryan Boreham e49bbe176d Make clear that we want the same universe throughout the test 2016-05-10 13:32:56 +01:00
Adam Harrison 0e694ed6b4 Merge branch '1.5' 2016-05-09 16:37:05 +01:00
Adam Harrison 9dfd7004cc Document adding new version to checkpoint API 2016-05-09 16:36:32 +01:00
Bryan Boreham cf6d0c8126 Merge branch '1.5' 2016-05-09 15:48:20 +01:00
Bryan Boreham 3963d4453a Remove mention of obsolete branch latest_release_doc_updates 2016-05-09 15:48:05 +01:00
Bryan Boreham 99b0b949e8 Merge branch '1.5' 2016-05-09 15:40:12 +01:00
Bryan Boreham ce5d2a6dd0 Add release v1.5.1 2016-05-09 15:16:21 +01:00
Adam Harrison 801283267a Merge branch '1.5'
Closes #1876.
2016-05-09 14:58:28 +01:00
Bryan Boreham a2e301c648 Merge pull request #2263 from weaveworks/issues/1876-weave-status-ipam-docs
Document `weave status ipam`. Fixes #1876.
2016-05-09 14:56:59 +01:00
Bryan Boreham 2249c7c648 Merge branch '1.5' 2016-05-09 14:46:06 +01:00
Bryan Boreham 0425d5bf6a Removed duplicated 'name' 2016-05-09 14:45:43 +01:00
Bryan Boreham de9597b6fa Merge branch '1.5' 2016-05-09 14:38:00 +01:00
Bryan Boreham 2fa576f3c0 Merge pull request #2265 from weaveworks/issues/2232-block-claim
Make claim block if the IPAM ring is not established. Fixes #2232
2016-05-09 14:37:37 +01:00
Adam Harrison fa29a4b4af Document weave status ipam 2016-05-09 13:41:42 +01:00
Martynas Pumputis d698aefbfc Make Claim to block if the IPAM ring is not established 2016-05-09 12:48:41 +01:00
Matthias Radestock db1ac2a343 Merge branch '1.5' 2016-05-09 11:50:09 +01:00
Matthias Radestock a3b6380296 Merge pull request #2264 from weaveworks/issues/2123-die-another-way
Kill process instead of container, on container restart.

Fixes #2123
2016-05-09 11:47:58 +01:00
Bryan Boreham 469d456c8b Smoke-test for container restart with proxy attach failure 2016-05-09 11:19:19 +01:00
Matthias Radestock 438efcccda Merge branch '1.5' 2016-05-07 20:19:18 +01:00
Matthias Radestock daa369b86c refactor: extract a couple of helpers in allocator tests
to reduce repetition
2016-05-07 20:18:21 +01:00
Matthias Radestock c3a2ea3dd8 Merge branch '1.5' 2016-05-07 17:57:10 +01:00
Matthias Radestock c54f2959ad Merge pull request #2266 from weaveworks/issues/2233-peer-name-docs
Document peer name

Fixes #2233.
2016-05-07 17:56:39 +01:00
Matthias Radestock ac0f284c5f Merge branch '1.5' 2016-05-07 14:43:04 +01:00
Matthias Radestock bd06553ce0 Merge pull request #2262 from weaveworks/issues/2194-reclaim-plugin-addrs
Reclaim plugin addresses without warning

Fixes #2194
2016-05-07 14:41:03 +01:00
Adam Harrison 158fa9d8e5 Reclaim plugin addresses using container ID of '_' 2016-05-07 14:35:15 +01:00
Anita Buehrle d234ca6ab8 clarified sentence, cosmetic 2016-05-06 12:41:59 -05:00
Bryan Boreham 8d71467802 Kill process instead of container, on container restart.
When Docker restarts a container and something goes wrong attaching
the network, kill the process inside the container instead of killing
the container, so that Docker will restart it again
2016-05-06 18:02:11 +01:00
Adam Harrison 8c5cbc738a Document peer name 2016-05-06 17:47:34 +01:00
Bryan Boreham 01e3d1d81b Refactor: extract kill_container function 2016-05-06 15:45:54 +01:00
Matthias Radestock 5e297c366e Merge branch '1.5' 2016-05-06 15:13:19 +01:00
Matthias Radestock 39b0d2a0cb Merge pull request #2261 from weaveworks/readme-update
remove duplicate content in README

Fixes #2217
2016-05-06 15:10:59 +01:00
Adam Harrison 260b416cd7 Include interface name in container-addrs output 2016-05-06 14:12:50 +01:00
Adam Harrison ad5845b67f Fix echo_ips 2016-05-06 14:12:19 +01:00
Bryan Boreham b426973679 Merge branch '1.5' 2016-05-06 12:46:21 +01:00
Bryan Boreham 7fcd837277 Cosmetic 2016-05-06 12:45:54 +01:00
Bryan Boreham 5993b3e846 Refactor: extract function to look up waiting channel for container 2016-05-06 12:45:03 +01:00
Matthias Radestock cf7ea357de Merge branch '1.5' 2016-05-06 11:21:57 +01:00
Matthias Radestock 4e48b956d9 Merge pull request #2250 from weaveworks/issues/2245-document-log-level
Document --log-level

Fixes #2245
2016-05-06 11:21:20 +01:00
Matthias Radestock 5b5d9d833a Merge pull request #2219 from weaveworks/export-wider
Document adding a route on non-Weave hosts
2016-05-06 11:20:27 +01:00
Bryan Boreham e16a4aa97a Document adding a route on non-Weave hosts 2016-05-06 11:13:15 +01:00
Bryan Boreham 12fa345d10 Punctuation 2016-05-06 11:10:34 +01:00
Matthias Radestock d2ea7e046d make clear that this repo is for Weave Net
...and make the links more relevant and 'active'
2016-05-06 10:55:29 +01:00
Matthias Radestock 1b50285609 add link to Weave Net product when first mentioning it
just as we do for scope and flux
2016-05-06 10:55:29 +01:00
Matthias Radestock 658c910862 fix typo 2016-05-06 10:55:29 +01:00
Anita Buehrle e1ab6a9035 removed installing heading 2016-05-06 10:55:29 +01:00
abuehrle 8c8709e527 added overview links to install 2016-05-06 10:55:29 +01:00
abuehrle d1e004dedc removed duplicate content added links to website 2016-05-06 10:55:29 +01:00
Matthias Radestock 8a827bebc8 Merge branch '1.5' 2016-05-05 17:56:57 +01:00
Matthias Radestock 4fc232be61 Merge pull request #2259 from weaveworks/issues/2214-fix-plugin-readme-links
Plugin README links refer to latest release docs

Fixes #2214.
2016-05-05 17:56:28 +01:00
Adam Harrison df2868fcdd Plugin README links refer to latest release docs 2016-05-05 16:32:53 +01:00
Matthias Radestock 32ba82efaf Merge branch '1.5' 2016-05-05 14:50:00 +01:00
Matthias Radestock b1aa52b3ed Merge pull request #2238 from weaveworks/missing-persist
Persist the IPAM ring on `weave reset` and `weave rmpeer`
2016-05-05 14:41:53 +01:00
Bryan Boreham 11c368531a Add --log-level to weave usage message, and document it and a couple of
other options on the proxy.
2016-05-05 12:44:40 +00:00
Matthias Radestock e389c8bb06 Merge branch '1.5' 2016-05-05 13:33:54 +01:00
Adam Harrison 608da90dc7 Publish doc previews for all branches, not just those named issues/* (#2258) 2016-05-05 13:33:28 +01:00
Matthias Radestock d3ddb71557 Merge branch '1.5' 2016-05-05 12:07:12 +01:00
Bryan Boreham fbb6e58b4f Add a section explaining WEAVE_MTU for fastdp (#2253)
Add a section explaining WEAVE_MTU for fastdp

Fixes #2198
2016-05-05 12:06:13 +01:00
Adam Harrison 34b95ee36f Merge branch '1.5' 2016-05-05 10:11:50 +01:00
Adam Harrison 1283ba4f61 Merge pull request #2249 from weaveworks/issues/2209-depersist-on-range-change
Better deleting of persisted IPAM data
2016-05-05 10:11:22 +01:00
Tom Wilkie a0982cb5e5 Merge pull request #2005 from weaveworks/sudo
Autodetect if we talk to docker via tcp in the Makefile
2016-05-05 10:05:56 +01:00
Tom Wilkie 0314a86e03 Autodetect if we talk to docker via tcp in the Makefile 2016-05-04 16:28:28 +01:00
Bryan Boreham d9d038ae35 Merge branch '1.5' 2016-05-04 15:38:33 +01:00
Bryan Boreham 87b61419f3 Move plugin arguments from separate doc into main plugin doc and add table of contents with sub-heading anchors 2016-05-04 14:44:10 +01:00
Adam Harrison 5fb6df5219 Merge branch '1.5' 2016-05-04 13:34:06 +01:00
Matthias Radestock b6647741b5 Merge pull request #2162 from weaveworks/issues/2034-log-rest-api
Add LogHandler for logging REST API calls at server side

Fixes #2034
2016-05-04 12:39:11 +01:00
Adam Harrison 0b4f9dbcf9 Merge pull request #2255 from weaveworks/issues/wordepress-stable-urls
Upgrade release branch doc publishing to wordepress 1.0.0
2016-05-04 11:59:22 +01:00
Martynas Pumputis 9644ed3f29 Merge pull request #2196 from weaveworks/issues/2194-claim-addr
Improve handling of `claim _`
2016-05-04 11:22:04 +01:00
Adam Harrison 1d52615452 Pin all branches to Wordepress 1.0.0 2016-05-04 11:07:12 +01:00
Adam Harrison 327a6f6d61 Upgrade to Wordepress 1.0.0
Release docs will now also be available with a stable 'latest' URL.
2016-05-04 11:01:07 +01:00
Adam Harrison 7aee9ebf84 Merge pull request #2254 from weaveworks/issues/wordepress-stable-urls
Upgrade to Wordepress 1.0.0
2016-05-04 10:56:34 +01:00
Adam Harrison 8f6087cfec Upgrade to Wordepress 1.0.0
Release docs will now also be available with a stable 'latest' URL.
2016-05-04 10:30:18 +01:00
Matthias Radestock 6022ad467a Merge branch '1.5' 2016-05-03 17:56:46 +01:00
Matthias Radestock 05652c0a3c Merge pull request #2252 from weaveworks/issues/2244-dns-noerror
Blank DNS response to AAAA queries where we have an A record

Fixes #2244.
2016-05-03 17:55:37 +01:00
Bryan Boreham 503546d2a9 Return DNS no-error with empty answer if we have a matching name
but the query is for a record type we don't support.
2016-05-03 17:33:51 +01:00
Bryan Boreham 3252a25e00 Broadcast initial ring after persisting it, in case we die between those operations 2016-05-03 17:23:00 +01:00
Bryan Boreham 6847a3551d Persist the ring in Shutdown() and AdminTakeoverRanges().
Also make AdminTakeoverRanges cause pending ops to be retried.
2016-05-03 17:23:00 +01:00
Bryan Boreham 70bd0ade45 Identifier "_" is address, not cidr 2016-05-03 15:47:45 +01:00
Martynas Pumputis 9dd1fbba39 Add LoggingHTTPHandler for logging REST requests at the server-side 2016-05-03 15:40:37 +01:00
Bryan Boreham 8405e0759a Clarify the function of the periodic ticker.
- it either retries for consensus or retries operations we would have tried previously.
There is no point retrying pending operations if we are waiting for consensus.
2016-05-03 15:13:20 +01:00
Adam Harrison bcc9a85e29 Merge remote-tracking branch 'origin/1.5' 2016-05-03 14:27:51 +01:00
Adam Harrison be3b0aa976 Merge pull request #2247 from weaveworks/pin-wordepress-version
Pin wordepress version used to publish site
2016-05-03 14:13:03 +01:00
Bryan Boreham 5ac8cc74d3 Refactor nested if-statements as switch 2016-05-03 13:52:36 +01:00
Adam Harrison 68e5ed575f Pin wordepress version
Use specific versions of wordepress for live and dev publishing
2016-05-03 13:47:37 +01:00
Bryan Boreham f6966548eb Delete persisted data when IPAM range changes 2016-05-03 13:20:04 +01:00
Bryan Boreham fb3ed9c1a6 Re-organise checking of persisted data so the failure paths bail out
of the function first.
Also bail out if there is no persisted ring, since persisted 'owned'
data isn't meaningful in that state.
2016-05-03 13:20:04 +01:00
Bryan Boreham 61fc5d56fb Refactor: move initialisation in the case that we don't use persisted data
out from loadPersistedData().
2016-05-03 13:20:04 +01:00
Bryan Boreham e96b68f0aa Don't use persisted data until we are sure it matches 2016-05-03 13:20:04 +01:00
Bryan Boreham bd23c79823 Merge branch '1.5' 2016-04-29 21:11:12 +01:00
Bryan Boreham 393fa3a333 Remove obsolete option and add --no-restart option 2016-04-29 19:49:21 +00:00
Bryan Boreham 27bdd3b4ad Revert "Log the error when something goes wrong requesting a claimed address"
This reverts commit 14bc1c987e.
2016-04-29 16:03:41 +01:00
Bryan Boreham 14bc1c987e Log the error when something goes wrong requesting a claimed address 2016-04-29 16:01:21 +01:00
Bryan Boreham fd7fcc762e Clarify the function of the periodic ticker.
- it either retries for consensus or retries operations we would have tried previously.
There is no point retrying pending operations if we are waiting for consensus.
2016-04-29 13:59:25 +01:00
Matthias Radestock 03afb54cdd remove cruft 2016-04-29 10:03:23 +01:00
Bryan Boreham 50e114863d Merge branch '1.5' 2016-04-28 09:40:04 +00:00
Bryan Boreham 9ce229ba3a Merge pull request #2202 from weaveworks/issues/1482-update-test320
Update test 320 to cope with persistence
2016-04-28 10:21:57 +01:00
Adam Harrison e6f031a3c9 Merge pull request #2218 from weaveworks/1.6-upgradeathon
Upgrade vendored libs
2016-04-28 10:13:44 +01:00
abuehrle 8b432a4d3e fixed broken links 2016-04-27 15:16:45 -05:00
Matthias Radestock 818f3e284b Merge branch '1.5' 2016-04-27 20:29:38 +01:00
Matthias Radestock 560f38330e Merge pull request #2230 from weaveworks/tweak-using-titles
Tweak titles under "Using Weave Net"
2016-04-27 20:17:04 +01:00
Matthias Radestock 5771ba15dd Merge branch '1.5' 2016-04-27 19:37:22 +01:00
abuehrle 9243bc2b0a fixed broken links 2016-04-27 13:25:32 -05:00
Matthias Radestock df5d6972e1 Tweak titles under "Using Weave Net"
- strip "Weave" and "Weave Net"
- "Integrating a Host Network with Weave" -> "Integrating with the
  Host Network"
- "Configuring Weave to Explicitly Use an IP Range" -> "Allocating IPs
  in a Specific Range"
2016-04-27 19:21:02 +01:00
Matthias Radestock 380cb9b0fc Merge pull request #2228 from weaveworks/tweak-using-sections
tweak 'Using Weave Net' section order
2016-04-27 18:50:14 +01:00
Matthias Radestock bd3b3791c6 tweak 'Using Weave Net' section order
- move "Managing Services in Weave Net" up so it comes after
  "Integrating a Host Network with Weave Net", to which it is deeply
  related
- move "Adding and Removing Hosts Dynamically" down so it is adjacent
  to the other sections which talk about peer connectivity
2016-04-27 18:37:28 +01:00
Matthias Radestock 77ced2ac55 Merge branch '1.5' 2016-04-27 18:25:23 +01:00
Matthias Radestock 7decce690a Merge pull request #2227 from weaveworks/2207-dedup-service-export-docs
dedup service export docs

Fixes #2207.
2016-04-27 17:31:34 +01:00
Matthias Radestock 65ecac6f1a cosmetic: consistency 2016-04-27 11:54:23 +01:00
Matthias Radestock 14a3898371 remove service-export doc since it duplicates content
...and update links accordingly.
2016-04-27 11:53:03 +01:00
Matthias Radestock c012650476 make service export section match whats in the separate doc 2016-04-27 11:48:56 +01:00
Adam Harrison d5fd62393f Merge branch '1.5' 2016-04-27 10:00:21 +01:00
Adam Harrison 789a6192f2 Merge pull request #2221 from weaveworks/issues/2216-fix-link
Fix broken link
2016-04-27 09:32:26 +01:00
Matthias Radestock 298fdc3d58 Merge branch '1.5' 2016-04-27 08:40:58 +01:00
Matthias Radestock 019a065d03 refactor: more logical question ordering 2016-04-27 08:40:07 +01:00
Matthias Radestock de1304d424 fix typo 2016-04-27 08:39:23 +01:00
Matthias Radestock ef915ca58f cosmetic: consistent formatting of FAQ questions 2016-04-27 08:36:25 +01:00
Matthias Radestock 72e134605c refactor: move pure code outside actor 2016-04-26 20:02:47 +01:00
Matthias Radestock 7cc2a1fe38 refactor: more descriptive function name 2016-04-26 17:33:04 +01:00
Adam Harrison 5de090999c Fix broken link 2016-04-26 17:29:34 +01:00
Adam Harrison 8ea5d999c2 Disable dry run mode 2016-04-26 17:29:26 +01:00
Adam Harrison 671dddf761 Merge pull request #2212 from weaveworks/issues/2114-wordepress-circleci
Incrementally publish 1.5 branch doc updates directly to live
2016-04-26 17:06:14 +01:00
Adam Harrison f4a117a8fc Enable dry run mode 2016-04-26 16:46:04 +01:00
Bryan Boreham 8fdbaf5745 Merge branch '1.5' 2016-04-26 15:43:12 +01:00
Bryan Boreham 0e655a2bbd Remove plugin-connected containers before end of test, to avoid delaying later cleanup.
Also use a shorter sequence to exclude the plugin when removing other containers.
2016-04-26 15:42:35 +01:00
Bryan Boreham 15054393fb Update profile package to latest version 2016-04-26 14:57:04 +01:00
Bryan Boreham f56d001703 Updated vendored libraries:
vendor/github.com/Sirupsen/logrus          to latest release 0.10.0
vendor/github.com/appc/cni                 to latest master
vendor/github.com/boltdb/bolt              to latest release 1.2.0
vendor/github.com/coreos/go-iptables       to latest release 0.1.0
vendor/github.com/fsouza/go-dockerclient   to latest master
vendor/github.com/docker/docker            to latest release 1.11.0
vendor/github.com/docker/libnetwork        to v0.7.0-dev.6 matching docker 1.11.0
vendor/github.com/docker/machine           to latest release v0.7.0
vendor/github.com/google/gopacket          to latest master
vendor/github.com/gorilla/context          to latest release 1.1
vendor/github.com/gorilla/mux              to latest release 1.1
vendor/github.com/hashicorp/go-cleanhttp   to latest master
vendor/github.com/miekg/dns                to latest master
vendor/github.com/opencontainers/runc      to latest release 0.1.0
vendor/github.com/stretchr/testify         unchanged at 1.1.3
vendor/github.com/vishvananda/netlink      to latest master
vendor/github.com/vishvananda/netns        to latest master
vendor/github.com/weaveworks/go-checkpoint unchanged; already at latest on master
vendor/github.com/weaveworks/go-odp        to latest master
vendor/github.com/weaveworks/mesh          to latest master
vendor/golang.org/x/crypto                 to latest master
2016-04-26 14:19:29 +01:00
Matthias Radestock 6ac248bfbf Merge branch '1.5' 2016-04-26 14:08:21 +01:00
Matthias Radestock a5739e8753 make plugin README link to other docs on github rather than website
until we have stable (non-version-specific) links for the latter.

Stop-gap for #2214.
2016-04-26 14:06:40 +01:00
Adam Harrison 79f2324d2b Update release process 2016-04-26 12:04:28 +01:00
Anita Buehrle c1a3ea925d Updated IPAM title and added punctuation 2016-04-26 10:10:41 +01:00
Adam Harrison 062c7a6fdc Minor doc fixes for incremental publish 2016-04-25 17:30:51 +01:00
Adam Harrison 6cc7f37dbb Publish /site from CI 2016-04-25 17:30:51 +01:00
Bryan Boreham 76601fed09 Fix up merge in unit test 2016-04-25 12:28:47 +01:00
Bryan Boreham 88a044f7f9 Merge pull request #2184 from weaveworks/2181-excessive-ring-frag
prevent excessive ring fragmentation due to repeated space requests. Fixes #2181
2016-04-25 11:54:12 +01:00
Matthias Radestock 03fcbbceb9 add CONTRIBUTING.md 2016-04-24 19:55:23 +01:00
Matthias Radestock cec88f154e Merge pull request #2205 from weaveworks/issues/2057-gc-nicknames
Add allocator.PeerGone

Fixes #2057
2016-04-22 17:42:43 +01:00
Martynas Pumputis 849edb1768 Add allocator.PeerGone
The function is registered within the mesh gc and it is responsible
for removing gone nicknames (#2057).
2016-04-22 17:29:27 +01:00
Bryan Boreham 981b78f680 Merge pull request #2203 from weaveworks/issues/2197-add-equals
Add equals sign to --dns arg, for consistency
2016-04-22 14:39:18 +01:00
Bryan Boreham ee75d91756 Merge branch '1.5' 2016-04-22 14:37:25 +01:00
Bryan Boreham d2450aae1c Merge pull request #2204 from weaveworks/issues/2193-dns-leak
Fixes #2123: Use ContainerID when restarting a container
2016-04-22 14:36:17 +01:00
Bryan Boreham b4f35f1d38 Add equals sign to --dns arg, for consistency 2016-04-22 11:16:58 +01:00
Matthias Radestock 9326775718 remove cruft 2016-04-21 18:59:28 +01:00
Bryan Boreham 76f9afb59c Removed errant spaces on bullets 2016-04-21 17:45:52 +01:00
Bryan Boreham 192fbe3a53 Update test 320 to cope with persistence 2016-04-21 16:19:59 +01:00
Martynas Pumputis 427b6d2902 Use ContainerID when restarting a container
Otherwise, we are risking to leak DNS entries which happens when
ContainerName is passed to `weave reset` and subsequent internal call
to nameserver creates a new entry instead of replacing the old one.
The ContainerID of the new entry is set to ContainerName and in such case
stopping the container will not remove the new entry.
2016-04-21 16:12:02 +01:00
Bryan Boreham 2f5a3f4513 Remove db-prefix now that persistence is in a volume 2016-04-21 14:32:45 +01:00
Bryan Boreham c984ec1e86 Fix port number in docs, and add to FAQ 2016-04-20 12:41:54 +01:00
Bryan Boreham 061d2b123f Add weavedb to the images pulled by 'weave setup' 2016-04-20 11:53:10 +01:00
Adam Harrison 07780fa10c Merge pull request #2188 from weaveworks/doc-improvements
Minor improvements to docs
2016-04-19 15:37:23 +01:00
Adam Harrison a6b7f0a9d4 Merge pull request #2185 from weaveworks/change-titles
Restructure docs
2016-04-19 15:34:53 +01:00
Bryan Boreham 5b72142aa3 Fix broken fastdp links 2016-04-19 15:21:49 +01:00
Bryan Boreham 476d2fee09 Update plugin docs for restarts 2016-04-19 15:09:53 +01:00
Bryan Boreham b95c559564 Document --no-restart 2016-04-19 15:09:31 +01:00
Bryan Boreham cfdba71f90 Document IPAM persistence
Remove statement that nothing is persisted in IPAM
2016-04-19 13:45:49 +01:00
Bryan Boreham 8ac90c693d Move video up, fix guide link and remove stray bracket 2016-04-19 13:45:21 +01:00
Bryan Boreham 74546578ac Move 'using weave' netcat example up a level 2016-04-19 13:45:21 +01:00
Bryan Boreham 88c6c17767 Minor improvements to docs 2016-04-19 13:38:10 +01:00
Bryan Boreham f5223d754a Add release v1.5.0 2016-04-19 12:03:44 +01:00
Bryan Boreham 278f7d8381 Move CNI up to top level 2016-04-18 18:15:32 +01:00
Adam Harrison 2dddc58754 Remove unnecessary title from building doc 2016-04-18 18:01:18 +01:00
Bryan Boreham d454e610f1 Move encryption out of top level 2016-04-18 18:00:09 +01:00
Bryan Boreham 4d06069138 Move IP Addressing overview under how-it-works and Configuring IP under Using Weave 2016-04-18 17:58:07 +01:00
Bryan Boreham 3f0a5d9e5d Move systemd page out of top level 2016-04-18 17:55:00 +01:00
Bryan Boreham 85bda72038 Move fastdp pages out of top level 2016-04-18 17:54:51 +01:00
Bryan Boreham 1c7df2958a Merge branch '1.4' 2016-04-18 17:15:37 +01:00
Bryan Boreham 302d412530 Merge pull request #2158 from weaveworks/issues/2147-dont-nat-cast
Add iptables rule excluding multicast from NAT on 'weave expose'
2016-04-18 17:14:29 +01:00
Bryan Boreham ca2e54c361 Renamed 'router-topology' to 'how-it-works' 2016-04-18 16:53:39 +01:00
Adam Harrison b9706e456a Strip erroneous extra backtick from code fences 2016-04-18 15:10:37 +01:00
Adam Harrison e1478eefd4 Remove language spec from code fences 2016-04-18 15:10:37 +01:00
Adam Harrison 3a2452baf6 Style FAQ questions with emphasis 2016-04-18 15:10:37 +01:00
Adam Harrison 82c9a88aa2 Update titles and menu order 2016-04-18 15:10:37 +01:00
Adam Harrison 7ef007bbf5 Copy linked screencast image into /site 2016-04-18 14:26:42 +01:00
Bryan Boreham d32fc495c8 Merge branch '1.4' 2016-04-18 14:08:04 +01:00
Bryan Boreham d3635eed77 Need to mock-gossip from the end of the chain 2016-04-18 14:06:38 +01:00
Adam Harrison a16b48d8f3 Restore submodule dependency broken by f3dbebd467 2016-04-18 13:04:21 +01:00
Adam Harrison 6ad9dac71a Merge pull request #2165 from weaveworks/issues/2164-less-deleting
Store 'checkAlive' flag in IPAM, so we don't delete non-container IDs
2016-04-18 11:49:50 +01:00
Adam Harrison a921f77258 Merge pull request #2172 from weaveworks/disable-peer-persistence
Disable persistence of peer lists
2016-04-18 11:48:46 +01:00
Bryan Boreham 8253d17529 Merge branch '1.4' 2016-04-18 10:58:39 +01:00
Bryan Boreham d3be3d8912 Remove outdated comment 2016-04-18 10:53:55 +01:00
Bryan Boreham a6e0226189 Merge pull request #2182 from weaveworks/2180-test-transfer-1.4
fix simulation of periodic gossip in TestTransfer
2016-04-18 10:52:28 +01:00
Adam Harrison f3dbebd467 Remove obsolete Jekyll raw directives 2016-04-18 10:36:43 +01:00
Bryan Boreham b7b9322e33 Merge pull request #2178 from weaveworks/2177-multiweave-persistence
name db container after weave container
2016-04-18 10:31:09 +01:00
Bryan Boreham 5e4ab7f307 Plumb isContainer through Claim calls 2016-04-18 10:16:54 +01:00
Bryan Boreham 2b159b0c75 Pass checkAlive flag through as isContainer in Allocate 2016-04-18 10:16:54 +01:00
Bryan Boreham 984ba8a377 Extend 'owned' structure to store IsContainer flag 2016-04-18 10:13:09 +01:00
Bryan Boreham 01be916c37 Add test to expose problem deleting non-container IPs
and check dead containers are removed
2016-04-18 10:13:09 +01:00
Matthias Radestock c1d98ba59c refactor: extract a helper 2016-04-17 12:40:34 +01:00
Matthias Radestock a1823af745 refactor: make error returns less onerous 2016-04-17 12:40:34 +01:00
Matthias Radestock 4a01d23025 refactor: extract entry merging from ring merging 2016-04-17 12:40:34 +01:00
Matthias Radestock 27632b118f prevent excessive ring fragmentation due to repeated space requests
Merging a ring now indicates whether the ring has been updated. This
prevents excessive allocation retries, which in turn can result in
repeated space requests - i.e. if an allocation cannot proceed due to
lack of space - which in turn can result in excessive ring
fragmentation since many of the requests will result in the creation
of a new ring entries, due to the need to split ranges.

Fixes #2181.
2016-04-17 12:40:18 +01:00
Matthias Radestock 0e54de63cc cosmetic 2016-04-17 09:33:52 +01:00
Matthias Radestock c0c5906d07 fix simulation of periodic gossip in TestTransfer
`GossipBroadcast` in the `TestRouter` only goes one hop. In
`TestTransfer` the three peers are connected in a chain, and hence we
need to take extra care to ensure propagation to all peers.

Fixes #2180.
2016-04-16 10:11:06 +01:00
Matthias Radestock f6f4ee708a Merge remote-tracking branch 'upstream/master' 2016-04-16 09:13:44 +01:00
Matthias Radestock 8f54f83285 refactor: align test allocator names with indices
for easier debugging
2016-04-16 09:12:49 +01:00
Matthias Radestock e393b4aaa6 name db container after weave container
...so that we can start multiple weaves on a machine w/o them sharing
a single db container and tripping over each other as a result.

Unbreaks multiweave.

Fixes #2177
2016-04-16 03:09:45 +01:00
Anita Buehrle 8822aa4ece fixed link and formatting 2016-04-15 17:03:54 -05:00
Anita Buehrle 3e83897752 fixed a link 2016-04-15 16:21:57 -05:00
Anita Buehrle 1d7cdfae5d moved full stop 2016-04-15 16:16:46 -05:00
Anita Buehrle 0e71b7c01d moved full stop 2016-04-15 16:15:14 -05:00
Anita Buehrle 3c8bff70df moved full stop to outside of link 2016-04-15 16:13:17 -05:00
Anita Buehrle 6de0c06ada missing link and punctuation 2016-04-15 15:54:25 -05:00
Anita Buehrle 4ede0ac923 fixed up missing punctuation 2016-04-15 15:50:34 -05:00
Anita Buehrle fa3f1b277f removed bash formatting 2016-04-15 15:42:13 -05:00
Anita Buehrle 5ade5cca03 fixed links and formatting 2016-04-15 15:38:25 -05:00
Anita Buehrle 99a5b4aed3 fixed links and formatting 2016-04-15 15:36:55 -05:00
Anita Buehrle 07026bc7a9 removed bash formatting 2016-04-15 15:30:45 -05:00
Anita Buehrle 0ed9694199 fixed broken links and added missing punctuation 2016-04-15 15:28:43 -05:00
Bryan Boreham 098be788ae Merge pull request #2166 from weaveworks/optional-restart-policy
Optional restart policy
2016-04-15 17:45:54 +01:00
Adam Harrison c6609bd248 Smoke test --no-restart 2016-04-15 15:04:29 +01:00
Adam Harrison cadc3869b3 Launch observes --no-restart 2016-04-15 15:04:29 +01:00
Bryan Boreham 4669da6074 Disable persistence of peer lists 2016-04-15 14:49:50 +01:00
Matthias Radestock 439c9143af Merge pull request #2173 from weaveworks/reword-ipam-status
Improve IPAM status wording
2016-04-15 14:00:30 +01:00
Adam Harrison b9340ada3e Improve IPAM status wording 2016-04-15 13:39:55 +01:00
Adam Harrison 88e2761b18 Improve wording 2016-04-15 09:53:33 +01:00
Bryan Boreham 02516361c7 Merge pull request #2155 from weaveworks/issues/2065-rationalise-ipam-concepts
Rationalise IPAM concepts
2016-04-14 17:33:27 +01:00
Adam Harrison 31ca8f9dbf Merge pull request #2135 from weaveworks/issues/2031-persistence-volume
Use a data volume container for persistence of IPAM etc.
2016-04-14 13:21:22 +01:00
Adam Harrison a657e25a81 Update documentation 2016-04-14 12:46:04 +01:00
Adam Harrison e355e50c0d Tests prefer --ipalloc-init 2016-04-14 12:46:03 +01:00
Adam Harrison af8f590646 Deprecate --init-peer-count 2016-04-14 12:46:03 +01:00
Adam Harrison c3ecbc9d48 Implement unified --ipalloc-init parameter 2016-04-14 12:46:03 +01:00
Adam Harrison a09986baa2 Rename consense -> prime 2016-04-14 12:46:03 +01:00
Matthias Radestock e9ca0ffad1 Merge remote-tracking branch 'upstream/master' 2016-04-13 19:48:33 +01:00
Matthias Radestock aed6fd3fcc eliminate pcap cruft from docs
Fixes #2159
Fixes #1908
2016-04-13 19:47:33 +01:00
Matthias Radestock e77b2ae288 make clear that documented encapsulation is for sleeve 2016-04-13 19:46:53 +01:00
Matthias Radestock 828e5ba0b8 clearer reference to 'sleeve' in fastdp intro 2016-04-13 19:45:35 +01:00
Bryan Boreham 0eee97b988 Use regular persistence settings in test, since they now survive a restart 2016-04-13 16:08:41 +01:00
Bryan Boreham 358342aa4f Use a data volume container for BoltDB files.
We provide a very small image to use for this container.
Also we add an empty weavedata.db file to weave image so it doesn't crash when run without volume override
2016-04-13 16:07:55 +01:00
Bryan Boreham 6b08f97910 Merge pull request #2131 from weaveworks/issues/2089-vsn-check
2089: Add info about new available versions to the `weave status` report
2016-04-13 12:20:57 +01:00
Bryan Boreham 045edcca2f Add iptables rule excluding multicast from NAT on 'weave expose' 2016-04-13 12:05:24 +01:00
Matthias Radestock b4050276a9 Merge pull request #2154 from weaveworks/issues/2153-lock-testrouter
Lock round TestRouter map accesses

Fixes #2153
2016-04-13 07:51:22 +01:00
Bryan Boreham 6639353568 Lock round TestRouter map accesses, and copy the set where we may block. 2016-04-13 07:49:53 +01:00
Martynas Pumputis 928a693491 Extend version summary in the weave status report
The extended version summary includes info about a new available
version in the case the checkpoint is enabled.
2016-04-12 22:32:18 +01:00
Matthias Radestock f08148cabb proper systemd override for docker in test VMs
now you can

- run `vagrant provision` any time
- upgrade the base image with `vagrant box update`
- upgrade docker inside the VM w/o
...etc...

...without breaking things!
2016-04-12 11:22:32 +01:00
Matthias Radestock d1ca38e106 Merge pull request #2148 from weaveworks/issues/2146-cni-sock
Bind-mount the docker socket for CNI plugin

Fixes #2146
2016-04-11 16:03:14 +01:00
Bryan Boreham 15bdf6cd2d Rework CNI test so it uses the scriptlet 2016-04-11 16:00:49 +01:00
Matthias Radestock 4037c763c2 Merge branch '1.4' 2016-04-11 15:40:32 +01:00
Matthias Radestock d4fb739981 Merge pull request #2151 from weaveworks/issues/2140-fqdn-trailing-dot
Remove trailing dot from FQDN

Fixes #2140
2016-04-11 15:39:48 +01:00
Bryan Boreham 4bd6de5995 Extract out CNI setup so we can call it from a test 2016-04-11 15:28:11 +01:00
Bryan Boreham 61b0d0ba9e Merge pull request #2149 from weaveworks/stop-test-router
stop ipam tests from leaking routers
2016-04-11 13:34:21 +01:00
Matthias Radestock 56bfe15eca Merge pull request #2150 from weaveworks/issues/2139-zero-quorum
Don't try to form IPAM ring with a bogus quorum size

Fixes #2139.
2016-04-11 13:31:09 +01:00
Bryan Boreham c10d26cf02 Fix up TestBootstrap after consensus changes 2016-04-11 13:20:54 +01:00
Matthias Radestock 695babf7ba make Allocator.Stop() idempotent and non-blocking
So that tests don't have to be careful about ensuring that allocators
are stopped exactly once, or rely on the magic mesh.ChannelSize for
non-blocking behaviour.
2016-04-11 12:32:01 +01:00
Bryan Boreham ecf1887e5b Initialize Paxos quorum to 0 until this node needs to request consensus.
With a 0 quorum we will participate in voting, but will not actively
try to form a ring.
2016-04-11 11:42:24 +01:00
Bryan Boreham c6e8f54fe7 Add CNI plugin to description 2016-04-11 11:31:25 +01:00
Martynas Pumputis a4062bd15c Remove trailing dot from FQDN
As it is described in #2140, the trailing dot might appear
when starting a container via "weave run".
2016-04-11 11:17:36 +01:00
Matthias Radestock 4d352d6eb1 stop router created by makeNetworkOfAllocators
so that unit tests don't leave garbage behind
2016-04-10 11:22:57 +01:00
Bryan Boreham 737b0e0504 Two different configs; ensure weave-ipam driver works when named 2016-04-08 17:59:23 +01:00
Bryan Boreham 16e5032528 Merge branch '1.4' 2016-04-08 17:48:33 +01:00
Bryan Boreham 26bd1b5787 Specify /dev/null stdin for netcat, to avoid inconsistency in Docker 1.11 2016-04-08 17:48:08 +01:00
Bryan Boreham 13f3ff15bd Sanity-check ipam args to make diagnosis easier 2016-04-08 15:18:08 +01:00
Bryan Boreham e88e67f02c Bind-mount docker socket for CNI plugin scripts 2016-04-08 15:16:54 +01:00
Adam Harrison 9c7b27acf0 Merge pull request #2134 from weaveworks/issues/2063-observer-status
Better log and status messages for Paxos observer
2016-04-08 10:11:46 +01:00
Bryan Boreham aad5b4dd7e Document observer status 2016-04-07 13:16:15 +01:00
Bryan Boreham c12a52d20e Better log and status messages for Paxos observer 2016-04-07 12:50:52 +01:00
Bryan Boreham 0c59de40e7 Refactor Paxos status call to remove type assertion 2016-04-07 12:12:08 +01:00
Adam Harrison a897a7711c Merge pull request #2115 from weaveworks/issues/2114-docs-in-wordpress
Restructure `/site` to conform to Wordepress requirements
2016-04-07 11:22:40 +01:00
Adam Harrison fb8167c6f1 Fix broken link 2016-04-07 11:04:35 +01:00
Adam Harrison 0482d0716f Fix broken links 2016-04-07 10:56:56 +01:00
Adam Harrison f183cb491f Adjust section links 2016-04-07 10:51:47 +01:00
Adam Harrison 80770cc96e Restructure docs 2016-04-07 10:37:57 +01:00
Adam Harrison 21d061fa44 Remove Jekyll/Travis config 2016-04-07 10:36:10 +01:00
Matthias Radestock 7d27df0907 Merge pull request #2133 from weaveworks/issues/2081-broadcast-dns-overrides
Immediately broadcast DNS records that "re-assert a peer's authority"
2016-04-06 14:51:22 +01:00
Bryan Boreham 768e2a31fa Re-hide output coming from stop, since it's generally uninteresting 2016-04-06 13:54:12 +01:00
Bryan Boreham 487392b99c Immediately broadcast DNS records that "re-assert a peer's authority"
and enable test to check.
2016-04-06 13:35:07 +01:00
Matthias Radestock 50af75972a Merge pull request #2122 from weaveworks/issues/2081-gossip-to-restarted-peer
Update weaveworks/mesh to send gossip to restarted peer

Fixes #2085.
2016-04-06 12:01:38 +01:00
Matthias Radestock 88518ba278 Merge pull request #2130 from weaveworks/issues/2108-reboot-docs
Update reboot docs

Fixes #2108.
2016-04-06 10:30:38 +01:00
Bryan Boreham a83359da7d Update reboots section now we have --restart=always 2016-04-06 10:29:53 +01:00
Bryan Boreham 9c4b4ca35f Remove recursive link 2016-04-06 10:02:57 +01:00
Matthias Radestock 2e31087818 dump state on paxos test failure
to help diagnosis of #2132 and similar problems
2016-04-06 08:55:49 +01:00
Matthias Radestock 11e520e212 Merge pull request #2129 from weaveworks/fix-cov-collection
Do not fail during teardown of test suites if $COVERAGE is not set
2016-04-05 22:17:40 +01:00
Matthias Radestock 3254870899 cosmetic: tweak proxy intro to make more sense 2016-04-05 21:38:10 +01:00
Matthias Radestock 51210045f7 =1 is better than =true
though they both do the same thing
2016-04-05 20:16:15 +01:00
Matthias Radestock 9e6ae4422e tweak checkpoint description 2016-04-05 20:02:46 +01:00
Matthias Radestock ce431dd73f Merge pull request #2096 from weaveworks/issues/2052-http-errors
Report errors when weave script talks to weave component via http

Fixes #2052.
2016-04-05 19:35:01 +01:00
Bryan Boreham 934ec2467d Eliminate race from call_weave; call check_running only after curl fails 2016-04-05 17:54:18 +01:00
Bryan Boreham ff4d0dae70 Keep going if an IPAM claim errors 2016-04-05 17:54:18 +01:00
Matthias Radestock bac3d65ede refactor: use a 'case' for greater clarity 2016-04-05 17:54:18 +01:00
Bryan Boreham ecb180c0c5 Ignore 404 from IP address claim when IPAM is disabled 2016-04-05 17:54:18 +01:00
Bryan Boreham f01d91459b Make http_call send error messages to stderr and return error codes,
and fix up all uses of this function.
2016-04-05 17:54:18 +01:00
Matthias Radestock 3e07f03c87 Merge branch '1.4' 2016-04-05 17:26:01 +01:00
Matthias Radestock 28e0b14220 Merge pull request #2128 from weaveworks/issues/2109-skip-empty-json
Don't attempt to parse JSON payload if it is 0 bytes long.

Fixes #2109.
2016-04-05 17:24:37 +01:00
Matthias Radestock f82ef55c67 Merge branch '1.4' 2016-04-05 17:21:09 +01:00
Matthias Radestock 53ba2f0aff rename test so it actually gets run 2016-04-05 17:07:07 +01:00
Matthias Radestock 45b36b378d Merge branch '1.4' 2016-04-05 16:57:47 +01:00
Martynas Pumputis 41a5c6f523 Do not fail if $COVERAGE is not set
Also, stop weave in end_suite by using `weave stop` which does not
remove the weave container (#1939).
2016-04-05 16:53:01 +01:00
Matthias Radestock 4f1d87f893 Merge pull request #2126 from weaveworks/2090-delay-start
Delay notifying observers about 'start' events

Fixes #2090. Partially addresses #1775.
2016-04-05 16:48:20 +01:00
Bryan Boreham 66c92fe075 Don't attempt to parse JSON payload if it is 0 bytes long.
Also added a test to trigger this.
2016-04-05 16:47:11 +01:00
Bryan Boreham ebc5dcb4bb Delay notifying observers about 'start' events
...until the container has a pid, or we see the same container die.
This is to work around https://github.com/docker/docker/issues/18574

Fixes #2090. Partially addresses #1775.
2016-04-05 16:20:07 +01:00
Bryan Boreham afff92c248 Merge pull request #2124 from weaveworks/idempotent-tombstone
make DNS tombstoning idempotent
2016-04-05 17:15:53 +02:00
Matthias Radestock ead3518b4b make DNS tombstoning idempotent
so we avoid the unnecessary gossip, and delayed convergence, that
otherwise ensues.
2016-04-04 20:34:01 +01:00
Bryan Boreham c38dcb1d73 Adapt to logging changes in weaveworks/mesh 2016-04-04 16:01:58 +01:00
Bryan Boreham 00fe47ba62 Update weaveworks/mesh to send gossip to restarted peer 2016-04-04 15:29:36 +01:00
Bryan Boreham b7d49cdeb7 Merge pull request #2117 from weaveworks/2113-wait-for-dp
wait for datapath device to be ready
2016-04-01 12:13:21 +02:00
Matthias Radestock 495a35a6a6 work around fd re-use bug in vishvananda/netlink
Closing a subscription can cause the associated fd to be re-used while
the subscription goroutine is also still trying to use it. Which can
have disastrous consequences.

So as a work around we don't close subscriptions. This means we leak
an fd, some buffer space, and goroutine. The latter will eventually
block in a channel send of a subscription event, since nothing is left
reading ont the other end. So at least it won't be consuming cycles.
2016-04-01 11:07:19 +01:00
Bryan Boreham 9f13d28508 Merge pull request #2116 from weaveworks/plugin-coverage
add coverage to plugin
2016-04-01 12:01:25 +02:00
Matthias Radestock de4cc0ad54 eradicate last remaining wEaVeDnS misspellings 2016-03-31 06:39:41 +01:00
Anita Buehrle 7f4c527fc5 Merge pull request #2118 from weaveworks/weaveDNS-fix
fixes #2102
2016-03-30 17:02:04 -06:00
Anita Buehrle 8a305ee189 fixes #2102 2016-03-30 17:05:26 -06:00
Matthias Radestock 718e93bd23 add coverage to plugin 2016-03-30 17:40:32 +01:00
Matthias Radestock 254be128b0 cosmetic: consistency 2016-03-30 16:25:26 +01:00
Matthias Radestock 2c49cd1e0a refactor: s/DOCKERPLUGIN/PLUGIN
since it's also a CNI plugin now
2016-03-30 15:43:55 +01:00
Matthias Radestock ec167554c5 refactor: consistent order 2016-03-30 14:13:41 +01:00
Matthias Radestock f24f38be9c refactor: get rid of a superfluous fastdp member 2016-03-30 14:10:03 +01:00
Matthias Radestock 0f89f8562f refactor(ish): parameterise dp creation by iface, not name 2016-03-30 14:07:33 +01:00
Matthias Radestock 8eb52538de wait for datapath device
so that when the router container restarts after a reboot it waits for
the proxy to create the datapath device.

Fixes #2113
2016-03-30 14:01:57 +01:00
Matthias Radestock 90629bc6d3 add another cross reference. 2016-03-30 00:03:55 +01:00
Matthias Radestock c6fea4939e fix broken link 2016-03-30 00:02:30 +01:00
Anita Buehrle 0597162189 Merge pull request #2111 from weaveworks/app-isolation-fix
sorted out isolated apps files
2016-03-29 16:42:29 -06:00
Anita Buehrle 74e7d383c9 sorted out isolated apps files 2016-03-29 16:45:20 -06:00
Adam Harrison 051320e73c Merge branch '1.4' 2016-03-29 11:45:24 +01:00
Adam Harrison 6e04ccf677 Merge pull request #2101 from weaveworks/2099-no-dns
make `weave dns-args` and `weave run` work with `--no-dns`
2016-03-29 11:44:12 +01:00
Adam Harrison 436dc01f52 Merge pull request #2070 from weaveworks/issues/1721-quorum-callback
Use current target list to compute quorum
2016-03-29 11:11:30 +01:00
Adam Harrison a6bb02aca1 Merge pull request #2106 from weaveworks/patch-up-2103
Patch up #2103
2016-03-29 10:37:04 +01:00
Matthias Radestock ec5008c702 remove "quote of quote" 2016-03-29 10:31:36 +01:00
Matthias Radestock 3453972ac4 banish ~~~bash
Just use indenting, which is much easier on the eye.
2016-03-29 10:30:51 +01:00
Adam Harrison 7c37cd98dd Merge pull request #2074 from weaveworks/cleanup-plugin-logging
clean up plugin logging
2016-03-29 10:02:21 +01:00
Matthias Radestock a1eb940c51 restore ellipses around weave status output fragments 2016-03-29 05:40:50 +01:00
Matthias Radestock bd6359dcb1 Merge branch '1.4' 2016-03-29 05:38:35 +01:00
Matthias Radestock cc75b084d8 Merge branch 'latest_release_doc_updates' into 1.4 2016-03-29 05:36:59 +01:00
Matthias Radestock bd9314939b correct weave status proxy output 2016-03-29 05:36:11 +01:00
Anita Buehrle 2298927331 Merge pull request #2103 from weaveworks/spellcheck
fixed formatting for wp  and spellcheck
2016-03-28 16:27:24 -06:00
Anita Buehrle b3b93b28df fixed formatting for wp and spellcheck 2016-03-28 16:30:33 -06:00
Matthias Radestock d68c1a8187 correct tools submodule reference
This got broken in 18f678a3c8
2016-03-28 18:09:08 +01:00
Matthias Radestock 06a525456d remove bogus link 2016-03-28 17:59:16 +01:00
Matthias Radestock 9d19676ef1 cosmetic(ish): add reference to crypto overview from implementation 2016-03-28 17:58:43 +01:00
Matthias Radestock 540b55a35c cosmetic(ish): add some references to crypto docs 2016-03-28 17:53:41 +01:00
Matthias Radestock 2f435cfcce fix/add links to examples when referring to them 2016-03-28 17:44:43 +01:00
Matthias Radestock 18f678a3c8 Merge branch '1.4' 2016-03-28 17:32:22 +01:00
Matthias Radestock cc06a2d8ab Merge branch 'latest_release_doc_updates' into 1.4 2016-03-28 17:24:51 +01:00
Matthias Radestock 1dd2cdf7a9 fix dns load balancing example 2016-03-28 17:24:08 +01:00
Matthias Radestock 5944f069b6 cosmetic: quoting consistency 2016-03-28 16:55:19 +01:00
Matthias Radestock aade206f22 cosmetic(ish): ungarble example 2016-03-28 16:53:07 +01:00
Matthias Radestock 22c3582699 cosmetic: tweak example links 2016-03-28 16:27:21 +01:00
Matthias Radestock 2948deb210 cosmetic: tweak link 2016-03-28 16:25:12 +01:00
Matthias Radestock db9139a0cd correct weave attach example 2016-03-28 16:03:20 +01:00
Matthias Radestock bbcbb5f7b8 fix more doc typos 2016-03-28 15:56:27 +01:00
Matthias Radestock 1a872f3895 fix a bunch of typos 2016-03-28 15:45:05 +01:00
Matthias Radestock 095d7e54c3 fix typo 2016-03-28 15:24:17 +01:00
Matthias Radestock b2a484d5f0 refactor: inline 2016-03-28 14:17:54 +01:00
Matthias Radestock 8472272afe refactor(ish): bail early if weaveDNS is disabled 2016-03-28 14:10:31 +01:00
Matthias Radestock 648632d5ac add a test for working with --no-dns 2016-03-28 14:07:48 +01:00
Matthias Radestock ea3456756d make weave dns-args and weave run work with --no-dns
...rather than exploding

i.e. the former returns nothing and the latter leaves naming related
container settings untouched, just like happens in the proxy and
plugin.

Fixes #2099.
2016-03-28 14:04:07 +01:00
Matthias Radestock 0672a0858f Merge branch '1.4' 2016-03-28 12:52:31 +01:00
Matthias Radestock a1381fe0cf add --no-dns to usage
Closes #1687.
2016-03-28 12:49:31 +01:00
Matthias Radestock 3baf8058ed Merge branch 'latest_release_doc_updates' into 1.4 2016-03-28 12:48:36 +01:00
Matthias Radestock daf92d8e08 document --no-dns
Part of #1687.
2016-03-28 12:46:58 +01:00
Matthias Radestock c91b2c2907 Merge remote-tracking branch 'upstream/master' 2016-03-28 11:37:24 +01:00
Matthias Radestock 6e0aea233b Merge branch '1.4' 2016-03-28 11:36:18 +01:00
Matthias Radestock abd138026b cosmetic: identation 2016-03-28 11:10:36 +01:00
kpoplin 3b9847d5d9 Update README.md
Updated the "About Weaveworks" section to differentiate between our overall mission and a Weave Net-specific overview; also included brief descriptions of Weave Scope and Weave Flux. Corrected product names missed in last update.
2016-03-27 07:25:14 -07:00
kpoplin c4ec25bb14 Update README.md
Updated for consistent pronoun usage; corrected product and company references, following our standardized naming conventions; fixed other minor grammatical errors.
2016-03-27 06:49:28 -07:00
Matthias Radestock 0109bf0ac7 tiny refactor: make function & const name more meaningful 2016-03-26 21:23:23 +00:00
Matthias Radestock 4482d307bf tweak ipam plugin logging
- log requests at info  level instead of debug level
- log errors   at error level instead of debug level
2016-03-24 18:52:55 +00:00
Matthias Radestock 5aa2a7a14c refactor(ish) of ipam plugin logging
prefix all log entries with "[ipam]"

Also eliminate a dot import.
2016-03-24 18:52:55 +00:00
Matthias Radestock 984cad5b58 clean up network plugin logging
Consistency, consistency, consistency:

- prefix all log messages with "[net]" - important since the same
  process acts as both a network and ipam driver
- include the API function name in all log messages
- log request and response details at debug level
- log request summary at info level
- log ContainerStarted as a pseudo API function, but only at debug
  level (since it can be quite high volume)

And eliminate some dot imports.
2016-03-24 18:52:44 +00:00
Matthias Radestock de8c1d262f don't error log in 'createAndAttach'
It is a library function, so logging of any errors should be left to
the caller.

We also get rid of a logged warning which contained the complete data
structure returned by netlink.LinkByName.

So this function now does no logging at all. Which is how it should be.
2016-03-24 18:52:07 +00:00
Matthias Radestock 2d964bdc95 don't log in cni; just return errors
CNI is invoked from the command line; so there is no point in getting
clever about logging.
2016-03-24 18:51:34 +00:00
Matthias Radestock 91044ac0fa cosmetic: consistency 2016-03-24 18:51:08 +00:00
Matthias Radestock 98aeb674c4 cosmetic: more plugin error message/logging tweaks 2016-03-24 18:41:47 +00:00
Matthias Radestock ea11c5eedc cosmetic: some error logging message tweaks 2016-03-24 18:16:57 +00:00
Matthias Radestock c146ee142d Merge branch '1.4' 2016-03-24 17:26:00 +00:00
Bryan Boreham 88d115aab1 Merge pull request #2098 from weaveworks/2097-fail-on-attach-errors
fail plugin operation on bridge attachment error
2016-03-24 17:16:55 +00:00
Matthias Radestock fce954192c fail plugin operation on bridge attachment error
Fixes #2097.
2016-03-24 17:01:15 +00:00
Bryan Boreham aab86c38b7 Merge pull request #2093 from weaveworks/tools
Update tools to get misspell integration. Aho-Corasick FTW!
2016-03-24 14:09:45 +00:00
Bryan Boreham adc038d8d1 Merge pull request #2095 from berlic/berlic-plugin-docker-args
Support custom docker args for weave-plugin
2016-03-24 12:53:10 +00:00
Bryan Boreham cfa9b4f638 Assert that paxos quorum is set 2016-03-24 12:06:59 +00:00
Bryan Boreham e6fd970920 Exclude retry-never peers from quorum
Note: includes update to latest version of weaveworks/mesh library.
2016-03-24 12:06:59 +00:00
Bryan Boreham ad0a5477f9 Reverse order of 'start' and 'connect' in test so we don't hang waiting for consensus 2016-03-24 12:06:59 +00:00
Bryan Boreham 2b617633ae Compute quorum based on the dynamic number of target peers 2016-03-24 12:06:59 +00:00
Adam Harrison 7776e48a62 Merge branch '1.4' 2016-03-23 18:00:38 +00:00
Adam Harrison 6c0075ab82 Add release v1.4.6 2016-03-23 17:37:21 +00:00
Matthias Radestock 48534b1e30 unbreak tests
Broken in an attempt to help with #2090.
2016-03-23 17:22:40 +00:00
Matthias Radestock 8b6c5bdae4 unbreak things 2016-03-23 17:05:19 +00:00
Matthias Radestock b8abb22833 Merge branch '1.4' 2016-03-23 16:39:17 +00:00
Matthias Radestock ae0a4fef50 Merge pull request #2092 from weaveworks/issues/2083-error-not-panic
Change invariant fail on Merge() from panic to error

Fixes #2083.
2016-03-23 16:38:52 +00:00
Matthias Radestock 4dcec8265d Merge branch '1.4'
(but really replace all the changes, which were in 'mesh', with
vendoring the latest mesh)
2016-03-23 16:30:28 +00:00
Matthias Radestock 8360024e06 Merge pull request #2088 from weaveworks/issues/2087-leave-direct-targets
Don't delete targets that seem invalid if they are 'direct' targets

Fixes #2087.
2016-03-23 16:22:08 +00:00
Tom Wilkie 7a7867ae16 Fix spelling mistakes. 2016-03-23 16:09:43 +00:00
Tom Wilkie 43f8d073db Update tools for misspell. 2016-03-23 16:05:13 +00:00
Bryan Boreham 2e4d56efd6 Suspend connecting to targets that seem invalid, if they are 'direct' targets.
Introduce TargetSuspended state to reflect this.
2016-03-23 15:36:55 +00:00
Bryan Boreham 6bc199a8bc Change invariant fail on Merge() from panic to error 2016-03-23 15:26:26 +00:00
Konstantin Suvorov ad42f27e03 Support custom docker args for weave-plugin
WEAVEPLUGIN_DOCKER_ARGS environment variable is used to pass custom args when creating plugin container
2016-03-23 16:20:06 +03:00
Matthias Radestock c75cadf007 more correct sudo scoping
we want to know whether systemctl can be run when sudoing.

This shouldn't fix #2090, only give is a different error.
2016-03-23 13:00:04 +00:00
Matthias Radestock b080224072 Merge branch '1.4' 2016-03-22 16:28:53 +00:00
Matthias Radestock 537868008f make linter happy 2016-03-22 16:28:25 +00:00
Matthias Radestock 63a9f879fb Merge branch '1.4' 2016-03-22 14:13:24 +00:00
Matthias Radestock 1664fce9d1 Merge pull request #2081 from weaveworks/issues/2023-override-stale-dns
Override stale dns entries received via gossip

Fixes #1867 and #2023.
2016-03-22 13:47:17 +00:00
Bryan Boreham c2cf825cdf Smoke test for stale DNS entries 2016-03-22 12:57:07 +00:00
Bryan Boreham 38a79b7f59 Pick entry with newer tombstone to merge 2016-03-22 12:57:07 +00:00
Bryan Boreham 010766fe9e Check entries claiming to originate from us against our current data, and override if necessary 2016-03-22 12:57:07 +00:00
Adam Harrison c09dfe6b5a Merge pull request #2078 from weaveworks/reify-ipam-config
Reify ipam config
2016-03-21 16:12:11 +00:00
Matthias Radestock d177bb8a47 Merge remote-tracking branch 'upstream/master' 2016-03-21 16:00:19 +00:00
Adam Harrison a26dd1b1d7 Merge pull request #2072 from weaveworks/2071-ci-coverage-underreporting
collect coverage data from ci nodes before teardown
2016-03-21 15:58:03 +00:00
Matthias Radestock 34de08d649 Merge branch '1.4' 2016-03-21 15:56:56 +00:00
Adam Harrison 74d0b3b51e Merge pull request #2075 from weaveworks/2044-multi-rmpeer
make `weave rmpeer` accept a list of peers
2016-03-21 15:55:22 +00:00
Matthias Radestock 6b33f4215b Merge branch 'latest_release_doc_updates' into 1.4 2016-03-21 15:53:18 +00:00
Matthias Radestock cc43782d87 Merge pull request #2080 from weaveworks/issues/2061-correct-weave-status
Correct IPAM state docs

Fixes #2061.
2016-03-21 15:49:03 +00:00
Adam Harrison c2eb900dd3 Correct IPAM state docs 2016-03-21 15:33:37 +00:00
Matthias Radestock 915a72ad18 add a check for "--ipalloc-default-subnet requires --ipalloc-range" 2016-03-21 14:00:51 +00:00
Matthias Radestock 320a8ad15b extract IPAM config
and fix error handling - the "do we have an --ipalloc-range?" check
was not performed in all required cases
2016-03-21 12:03:51 +00:00
Matthias Radestock cf08b8b1aa cosmetic: tweak --observer usage text 2016-03-21 12:02:22 +00:00
Bryan Boreham 001322751f Don't hold Nameserver lock over call out via isKnownPeer 2016-03-21 11:52:13 +00:00
Matthias Radestock 0b3dd35624 cosmetic 2016-03-21 11:08:17 +00:00
Adam Harrison cdf3e4b98e Merge pull request #2073 from weaveworks/rmpeer-test
add 'rmpeer' test
2016-03-21 11:05:53 +00:00
Adam Harrison 0d10479e8a Add --observer to weave script help 2016-03-21 11:01:55 +00:00
Matthias Radestock 357d0e918a Merge pull request #2000 from weaveworks/issues/1998-specify-ipam-seed
Allow specification of initial IPAM ring via --ipam-seed

Fixes #1998.
2016-03-21 10:52:40 +00:00
Adam Harrison 3123418022 Merge pull request #2030 from weaveworks/issues/1992-cni-plugin
Implement CNI plugin
2016-03-21 10:51:19 +00:00
Adam Harrison dcc2d16408 Update mesh dependency for peer name shorthand 2016-03-21 10:27:32 +00:00
Adam Harrison e9081c6607 Allow specification of initial IPAM ring via --ipam-seed 2016-03-21 09:49:54 +00:00
Matthias Radestock 439e57ca56 make weave rmpeer accept a list of peers
This isn't as efficient as it could be. In particular we end up
broadcasting the ipam state for every peer listed. To avoid that we'd
have to change the HTTP API, and would no longer be able to use
'DELETE'. That is just not worth it.

Closes #2044.
2016-03-20 15:53:45 +00:00
Matthias Radestock 18ddf50b4c cosmetic 2016-03-20 15:46:05 +00:00
Matthias Radestock 6ebac90cb0 refactor: eliminate dot imports in main packages 2016-03-20 14:34:27 +00:00
Matthias Radestock 5e0231ec5e refactor(ish): unify logging in docker client wrapper
and get rid of some debug logging.

and eliminate a dot import in the process.
2016-03-20 10:40:26 +00:00
Matthias Radestock c25bfafcb2 refactor: make proxy log via a package-local var
which gets rid of a bunch of (dot) imports.
2016-03-20 08:31:23 +00:00
Matthias Radestock 6e4f025d9c refactor: reduce duplication in nameserver logging
and remove a dot import in the process
2016-03-20 08:19:15 +00:00
Matthias Radestock 07ea8a2613 add 'rmpeer' test 2016-03-20 07:16:01 +00:00
Matthias Radestock f9a0ba82a0 collect coverage data from ci nodes before teardown
Fixes #2071.
2016-03-19 22:43:17 +00:00
Matthias Radestock 4c0fe7b006 take advantage of restart=always in tests
This should have been done as part of #2029.
2016-03-19 17:43:49 +00:00
Matthias Radestock cddef7cae5 Merge remote-tracking branch 'upstream/master' 2016-03-19 17:36:38 +00:00
Matthias Radestock 197f4165a3 cosmetic: move IPAM tests into 3xx range 2016-03-19 17:35:18 +00:00
Bryan Boreham 4a2affabb5 Clean up so test will run again on same host 2016-03-19 16:35:45 +00:00
Matthias Radestock 211e527d3f Merge pull request #2069 from weaveworks/issues/2047-go-via-actor
Avoid data race in TestSpaceRequest

Fixes #2047.
2016-03-19 16:09:42 +00:00
Bryan Boreham 09a6c2eda0 Get the owned ranges for test purposes via the actor loop, so we don't set off the race detector 2016-03-19 15:29:34 +00:00
Bryan Boreham 71ec252298 Merge pull request #2066 from weaveworks/2058-idempotent-rmpeer
make 'rmpeer' report on size of transferred range, and not fail
2016-03-19 15:10:58 +00:00
Matthias Radestock 9f10b21c9c use Space.NumFreeAddresses for calculating transferred ip count
...rather than Space.NumFreeAddressesInRange; we don't care about the
universe.

Alternatively we could make Space.AddRanges return the count. But
AddRanges doesn't know whether the ranges overlap with existing free
space - that is only guaranteed by the context - so would have to do
much the same before/after calculation.

Another alternative would be to add the range sizes in
AdminTakeoverRanges. But that is more code and less clear.
2016-03-19 14:41:36 +00:00
Matthias Radestock 62d823850c make rmpeer report on size of transferred space, and not fail
Closes #2058.
2016-03-19 14:40:26 +00:00
Matthias Radestock c48eefa82d refactor(ish): extract allocator logging commonality
and add warnf
2016-03-19 14:32:54 +00:00
Matthias Radestock 65eff683dd Merge branch '1.4' 2016-03-19 14:30:38 +00:00
Bryan Boreham b1ec2b788a Bump template name so it will fetch latest Docker 2016-03-19 14:12:17 +00:00
Matthias Radestock f42e275884 broadcast ipam ring update after rmpeer
So that other peers notice the change more promptly.

Fixes #2068.
2016-03-19 13:57:20 +00:00
Matthias Radestock 8ce6d3863e Merge pull request #2067 from weaveworks/address-count
Add address.Count type
2016-03-19 12:04:02 +00:00
Bryan Boreham f11314ed3e Introduce 'Count' type to avoid abusing 'Offset' 2016-03-19 11:47:34 +00:00
Bryan Boreham e080f00354 Review feedback 2016-03-18 19:40:16 +00:00
Bryan Boreham b00f0aee65 Check errors on test for root namespace 2016-03-18 19:39:52 +00:00
Matthias Radestock 7b6364696c Merge branch '1.4' 2016-03-18 19:29:59 +00:00
Matthias Radestock 5dfd104728 reduce docker event subscription retry max interval 2016-03-18 19:29:21 +00:00
Bryan Boreham 88cb07203a Improve name of cni_volume_options and include them when running the CNI plugin inside a container 2016-03-18 19:02:28 +00:00
Matthias Radestock bc7539c4ad cosmetic: consistency 2016-03-18 11:56:10 +00:00
Matthias Radestock 0474227d6e Merge pull request #2062 from weaveworks/issues/2059-weave-ps-ignore-stopped
Protect container-addrs util_op against stopped containers

Fixes #2059.
2016-03-18 11:13:14 +00:00
Adam Harrison 04bbb14f59 Propagate container-addrs util_op failure 2016-03-18 10:56:10 +00:00
Adam Harrison f9f6e8ed26 Protect container-addrs against stopped containers 2016-03-18 10:46:30 +00:00
Matthias Radestock 9c2e9bab14 cosmetic(ish) refactor 2016-03-18 02:42:53 +00:00
Matthias Radestock 4539bde5f5 simplify weave consense explanation 2016-03-18 02:03:34 +00:00
Matthias Radestock 44db686ef3 don't mention the election
Fixes #2060.
2016-03-18 01:56:52 +00:00
Matthias Radestock 221ef4adca make a few more shell funs safe
...for calling in a context w/o 'set -e', even though right now they
always are.

Follow-on of #2054.
2016-03-17 21:32:08 +00:00
Matthias Radestock c1d4e34ed0 Merge pull request #2055 from weaveworks/cleanup_attach_router
Remove unnecessary netns change in attach_router
2016-03-17 20:50:03 +00:00
Bryan Boreham 4903c2b23c Remove unnecessary netns switch for router in attach_router,
and improve the name of the function which sends existing
container data into the router
2016-03-17 20:32:41 +00:00
Matthias Radestock cd9b7bfcda Merge pull request #2054 from weaveworks/issues/2053-errexit
Fix missed errors in weave script

Fixes #2053.
2016-03-17 20:09:37 +00:00
Bryan Boreham c8ca295cda CNI plugin smoke test 2016-03-17 18:20:29 +00:00
Bryan Boreham 4e09889cab Make container_pid a common test function 2016-03-17 18:20:29 +00:00
Bryan Boreham a66543f98e Use link ParentIndex where available 2016-03-17 18:20:18 +00:00
Bryan Boreham 0705319f25 Return failure from various functions when sub-operation fails.
We cannot rely on `set -e` to fail the whole script in contexts
where functions are called inside conditionals.
2016-03-17 15:02:40 +00:00
Bryan Boreham b153e6a0d2 Simplify, after review feedback 2016-03-17 14:29:34 +00:00
Bryan Boreham ef892fd4ed Docs for CNI plugins 2016-03-17 14:29:34 +00:00
Bryan Boreham 024eb46c7d CNI plugin implemented as script that docker runs plugin container,
installed via `weave setup`
2016-03-17 14:29:33 +00:00
Bryan Boreham ecdd7aa7ce Configure arp cache on new interface 2016-03-17 14:29:33 +00:00
Adam Harrison b09b556796 Utility function to configure ARP cache timers 2016-03-17 14:29:25 +00:00
Bryan Boreham 2d6a916b2d Find weave veths by looking at what is connected to the bridge, not by name
and don't even look at containers running in the root namespace
2016-03-17 12:41:37 +00:00
Bryan Boreham 011fb55e5f Refactor FindNetDevs so we can get the link, and re-use parts of the function 2016-03-17 12:41:37 +00:00
Bryan Boreham ac4e87418a Set a default route via bridge if config doesn't specify any 2016-03-17 12:41:14 +00:00
Bryan Boreham 42ff61f97c CNI net plugin 2016-03-17 12:41:14 +00:00
Bryan Boreham 08059412b5 Refactor so we can call parts individually 2016-03-17 12:41:14 +00:00
Bryan Boreham f9615c34dc CNI IPAM plugin 2016-03-17 12:41:14 +00:00
Bryan Boreham 703b8dfd11 Expose 'ipam' type so we can refer to it elsewhere 2016-03-17 12:08:37 +00:00
Bryan Boreham b86e6412fa Don't try to parse return from DELETE address 2016-03-17 12:06:34 +00:00
Matthias Radestock aa1c1cc9be ignore arping failures
This is a largely cosmetic change since arping really shouldn't fail.
2016-03-16 20:32:42 +00:00
Adam Harrison 4b5fb2785e Merge pull request #2051 from weaveworks/issues/2046-static-ip
Fix plugin accepting --ip address
2016-03-16 15:46:49 +00:00
Bryan Boreham 4eaeb0f30c Merge branch '1.4' 2016-03-16 14:52:59 +00:00
Bryan Boreham 9c096526b8 Merge pull request #2049 from weaveworks/issues/2016-retry-docker-event-subscription
Retry docker event subscription
2016-03-16 14:38:27 +00:00
Bryan Boreham eee77d49d1 Claim IP takes CIDR not IP 2016-03-16 14:22:39 +00:00
Bryan Boreham d2d1d2b43a Test for docker network subnets and IPs 2016-03-16 13:47:30 +00:00
Adam Harrison 4874605add Merge pull request #2050 from weaveworks/bump-ci-docker
Bump template name so it will fetch latest Docker
2016-03-16 13:46:49 +00:00
Adam Harrison 922f465ecb Reset retry interval if we spent long enough processing events 2016-03-16 13:41:18 +00:00
Bryan Boreham c80bf7e996 Bump template name so it will fetch latest Docker 2016-03-16 13:14:40 +00:00
Bryan Boreham dd505a8e17 Merge pull request #2038 from weaveworks/wp-markdown-plugin-fixes
Doc fixes required by updated WP markdown plugin
2016-03-16 12:46:50 +00:00
Adam Harrison 08e9db900a Retry docker event subscription 2016-03-16 09:23:32 +00:00
Matthias Radestock 86bfc91ac9 refactor: clearer IPAM config 2016-03-15 10:29:32 +00:00
Adam Harrison 2eeb754454 refactor: Introduce IPAM config object 2016-03-14 17:41:20 +00:00
Matthias Radestock 2a10182cf6 Merge pull request #2029 from weaveworks/router-and-proxy-always-restart
Router and proxy run with --restart=always
2016-03-14 17:19:47 +00:00
Adam Harrison 115162fbfd Merge pull request #2037 from weaveworks/2021-fallback-to-hypervisor-uuid
fall back to hypervisor uuid for mac derivation
2016-03-14 16:56:00 +00:00
Adam Harrison 82adc85562 Router and proxy run with --restart=always 2016-03-14 16:31:06 +00:00
Matthias Radestock 05a7024b88 bump go-checkpoint version 2016-03-11 11:00:44 +00:00
Adam Harrison 62e8028591 Fixup link URLs 2016-03-11 10:52:58 +00:00
Adam Harrison 2bc5fd30c0 Make image paths absolute with respect to repo 2016-03-11 10:35:47 +00:00
Bryan Boreham 35671135bd Return errors that happen inside WithNetNS 2016-03-10 15:18:16 +00:00
Bryan Boreham a57335738d Don't do unnecessary clock skew check in IPAM 2016-03-10 11:41:47 +00:00
Matthias Radestock 459bb08828 fall back to hypervisor uuid for mac derivation
since the system uuid is not available on paravirtual EC2 VMs, and
possibly other hypervisors.

Fixes #2021
2016-03-09 22:35:44 +00:00
Bryan Boreham 3ad9d8e785 Don't fail start if image is missing 2016-03-09 17:10:20 +00:00
Matthias Radestock 52552b59fb Merge pull request #2024 from weaveworks/abstract-api-log
Abstract out logging function from weave api package
2016-03-09 15:45:00 +00:00
Matthias Radestock f8e2af32cd refactor: extract common docker run options 2016-03-08 23:10:19 +00:00
Anita Buehrle 66cd178308 Merge pull request #2019 from weaveworks/1-5-edit3
cleaned up product names
2016-03-08 12:29:18 -06:00
Anita Buehrle be2dfda78e edits from awh 2016-03-08 12:14:27 -06:00
Bryan Boreham 0009b05635 Improve naming of 'release' function in IPAM API 2016-03-07 16:24:53 +00:00
Bryan Boreham f2e38ae6c5 Abstract out logging function from weave api package to reduce dependencies 2016-03-07 15:37:51 +00:00
Bryan Boreham b83f4a00ed Merge pull request #1997 from weaveworks/issues/1994-weave-consense
Implement `weave consense`
2016-03-03 15:26:02 -08:00
Anita Buehrle e2c8dba981 cleaned up product names 2016-03-03 16:12:12 -06:00
Adam Harrison 6584df274e Implement weave consense 2016-03-03 18:52:09 +00:00
Bryan Boreham 7c65b6e3bb Merge pull request #1990 from weaveworks/issues/1743-restricted-electorate
Support non-electing peers via --observer
2016-03-03 10:46:58 -08:00
Adam Harrison 268d355cae Observer smoke tests 2016-03-03 17:48:50 +00:00
Adam Harrison b84ef98de8 Support non-electing peers via --observer 2016-03-03 17:48:50 +00:00
Adam Harrison 29674b7780 Merge pull request #2012 from weaveworks/issues/1655-store-all-addresses
Store all addresses+subnets in IPAM
2016-03-03 17:06:02 +00:00
Martynas Pumputis 9cfc104fc7 Add TestSpaceRequest test for allocator
Checks whether a donating peer does not leave one ip address
behind a block it donates (#2009).
2016-03-03 08:36:14 -08:00
Bryan Boreham 824329d4c9 Fix up unit tests to look at CIDRs instead of addresses. 2016-03-02 17:21:52 -08:00
Bryan Boreham 604309fb53 Parse CIDR strings without separating into subnet and address 2016-03-02 17:21:52 -08:00
Bryan Boreham 73f1a04d5f Deal in subnets, not ranges, when requesting address allocation 2016-03-02 17:21:51 -08:00
Bryan Boreham b76e2a87cf Store address+subnet prefix for 'owned' addresses 2016-03-02 17:21:24 -08:00
Bryan Boreham b6eec08247 Return all applicable results from Lookup
and stop erroring on Lookup not found; just return a blank result
2016-03-02 17:01:12 -08:00
Bryan Boreham 03563e847e Remember addresses outside of the allocation range 2016-03-02 17:01:12 -08:00
Bryan Boreham 4c159a9af6 Merge pull request #1973 from weaveworks/issues/678-persist-owned2
Persist 'owned' addresses in IPAM
2016-03-02 16:58:23 -08:00
Bryan Boreham bc61838aaa Merge pull request #2015 from weaveworks/1-5-edits2
Reorganization of docs for WordPress
2016-03-02 16:24:14 -08:00
Bryan Boreham 8c9937b0be Fix up some wording and links 2016-03-02 15:39:06 -08:00
Anita Buehrle bdc9eae000 reorganization-edit docs for WP 2016-03-02 13:54:05 -06:00
Bryan Boreham 95cbc8940e Sync 'owned' data with existing containers at startup 2016-03-02 11:35:24 -08:00
Bryan Boreham f29716387f Persist the 'owned' address set 2016-03-02 11:35:24 -08:00
Adam Harrison 30b9d33276 Adjust tests to accomodate docker/docker#14012 2016-03-02 11:59:10 +00:00
Bryan Boreham 532a6b69d9 Merge pull request #1672 from weaveworks/vagrant-pin-docker
Pin docker version in vagrant VM
2016-03-01 14:15:05 -08:00
Bryan Boreham f2ef5e880a Merge pull request #1982 from weaveworks/issues/578-pid-equals-host
Use --pid=host
2016-03-01 12:41:52 -08:00
Bryan Boreham dd74bb1774 Simplify by using GetFromPid 2016-03-01 12:12:46 -08:00
Adam Harrison adf56d316d Remove obsolete alternative procfs support 2016-03-01 20:10:47 +00:00
Adam Harrison cb9af20a2e Replace PROCFS with --pid=host 2016-03-01 20:10:47 +00:00
Bryan Boreham cb01e3f87b Typo 2016-02-29 15:08:55 -08:00
Bryan Boreham 590c1dde1d Merge branch '1.4' 2016-02-29 15:04:12 -08:00
Bryan Boreham be3f88656b Add release v1.4.5 2016-02-29 22:28:58 +00:00
Bryan Boreham 246f394731 Merge branch '1.4' 2016-02-29 14:07:02 -08:00
David Wragg 27367ab292 Process DiscardingFlowOp correctly in FastDatapath send()
The nil FlowOp check in collectFlowOps was not addressed with the
introduction of DiscardingFlowOp.  This meant that DiscardingFlowOps
produced in the router core would get handled by fastdp as if they were
foreign FlowOps, preventing flow creation and so leading to unwarranted
ODP misses.

To fix this, collectFlowOps cannot simply eliminate FlowOps for which
Discards() is true, because it's true for odpFlowKeyFlowOp.  So the
Discards() case has to be handled in FastDatapath send().
2016-02-29 13:27:15 -08:00
Matthias Radestock f5d8fc5de2 move weavedns design from site to docs 2016-02-29 19:18:08 +00:00
Matthias Radestock 7cdf273c88 Merge branch '1.4' 2016-02-29 19:13:23 +00:00
Matthias Radestock 20620f0002 Merge branch 'latest_release_doc_updates' into 1.4 2016-02-29 19:13:00 +00:00
Matthias Radestock 8d79e33ba1 remove stale ToC entry
This was missed in 8b061fd55
2016-02-29 19:12:00 +00:00
Bryan Boreham 7453c7a5dd Merge branch '1.4' 2016-02-29 08:22:22 -08:00
Bryan Boreham ce4857f5dc Merge pull request #2001 from weaveworks/issues/1996-try-all-pending-allocations
Try all pending allocations - LGTM.  Fixes #1996
2016-02-29 08:20:49 -08:00
Adam Harrison 71af1f3120 Merge pull request #1972 from weaveworks/persist-peers
Persist set of peers to connect to
2016-02-29 15:54:54 +00:00
Adam Harrison e65a08471f Merge pull request #1967 from weaveworks/issues/1859-start-existing
Start existing container, if its image and arguments match
2016-02-29 15:33:30 +00:00
Alfonso Acosta b96330d529 Pin docker version in vagrant VM
Otherwise it will always install the latest docker version, which will be
undesirable when new major releases are done, until they are well tested.

For instance, docker after automatically updating to 1.9, it was killing my VM
when spawning a kubernetes cluster, due to a high CPU consumption, probably due
to https://github.com/docker/docker/issues/17720
2016-02-29 14:31:06 +00:00
Bryan Boreham f17d50cc50 Check the exact version of the image, not the base 2016-02-26 23:44:04 +00:00
Bryan Boreham 436f8ef7c8 Compare the environment so we can detect a change in password 2016-02-26 23:41:57 +00:00
Bryan Boreham 65f435f042 Smoke-test for restarts 2016-02-26 23:41:57 +00:00
Bryan Boreham 561c8d012c Treat a restarting container like a running one, for idempotency 2016-02-26 23:41:46 +00:00
Bryan Boreham bb4c0f5247 Start existing container, if its image and arguments match 2016-02-26 23:40:02 +00:00
Adam Harrison 31a964ba9b Merge pull request #1954 from weaveworks/version-check
Periodically check for up to date versions of weave.
2016-02-26 17:25:24 +00:00
Tom Wilkie b717399364 Update go-checkpoint 2016-02-26 16:47:32 +00:00
Tom Wilkie b79bb32782 Review feedback 2016-02-26 15:37:00 +00:00
Tom Wilkie 6ff7419981 Review feedback 2016-02-26 15:35:12 +00:00
Tom Wilkie b228bbb9fb Periocially check for up to date versions of weave. 2016-02-26 15:35:12 +00:00
Matthias Radestock 752baa4bd6 remove unnecessary WEAVE_CIDR=none
since the router is now always running with --net=host
2016-02-26 13:58:06 +00:00
Matthias Radestock 6cbde89eeb refactor: consistency in specification of common docker run options 2016-02-26 13:57:37 +00:00
Adam Harrison bceabe32a2 Try all pending allocations
We can have outstanding allocations for different ranges owned by
different peers, so we should not short circuit after the first space
request.
2016-02-25 14:56:33 +00:00
Adam Harrison c5361801c9 Fix typo in weaver CLI help 2016-02-25 12:02:28 +00:00
Matthias Radestock 3283bc89fc Merge branch '1.4' 2016-02-23 13:56:56 +00:00
Matthias Radestock 26519333c0 cosmetic: correct comment 2016-02-23 13:36:56 +00:00
Matthias Radestock 639cde0f67 refactor: inline 2016-02-23 13:34:14 +00:00
Matthias Radestock 6a9f9f66dc don't check for 'Restarting' when attaching on startup
It is overkill.
2016-02-23 13:20:22 +00:00
Adam Harrison 639e0e82c9 Merge pull request #1989 from weaveworks/1977-restarting-not-running
treat 'restarting' as 'not running'
2016-02-23 10:49:31 +00:00
Adam Harrison 6f65512471 Merge branch '1.4' 2016-02-23 10:47:08 +00:00
Adam Harrison 4b0a6e1433 Merge pull request #1983 from weaveworks/1929-auto-detect-odp-on-relaunch
don't complain on relaunch when ODP is not supported
2016-02-23 10:46:36 +00:00
Matthias Radestock d5b82cac45 Merge branch '1.4' 2016-02-23 10:17:03 +00:00
Matthias Radestock cb6db91b09 Merge branch 'latest_release_doc_updates' into 1.4 2016-02-23 10:16:08 +00:00
Matthias Radestock 6a02e2dc17 explain TCP/UDP connections, heartbeats, back-off
Fixes #1969
2016-02-23 09:54:15 +00:00
Ilya Dmitrichenko f4ad97b0c9 Merge branch '1.4' 2016-02-22 14:16:37 +00:00
Ilya Dmitrichenko b377207faf Merge branch 'latest_release_doc_updates' into 1.4 2016-02-22 14:16:02 +00:00
Ilya Dmitrichenko 24ebb7cc7c Add missing dependency for latest gsutil 2016-02-22 14:11:36 +00:00
Ilya Dmitrichenko b5518db03c Add missing argument to tar 2016-02-22 14:02:39 +00:00
Ilya Dmitrichenko 2aa4e6a83a Use "official" gsutil installation instructions 2016-02-22 13:58:42 +00:00
Ilya Dmitrichenko 7c655cc3ba Fix false-positive docs uploads 2016-02-22 13:56:49 +00:00
Matthias Radestock d7a1bdd7a8 Merge branch '1.4' 2016-02-22 13:55:45 +00:00
Matthias Radestock 75cda01167 Merge branch 'latest_release_doc_updates' into 1.4 2016-02-22 13:55:18 +00:00
Matthias Radestock 4f0f3cf98d warn against using the plugin in combination with --net=weave
and expand the basic proxy usage docs slightly.
2016-02-22 13:53:39 +00:00
Matthias Radestock d9637ce620 Merge branch '1.4' 2016-02-22 13:38:08 +00:00
Matthias Radestock e014140134 Merge branch 'latest_release_doc_updates' into 1.4 2016-02-22 13:36:33 +00:00
Matthias Radestock c8ae128e59 for Travis, this no longer is a go project
Travis insists that one picks a project language. There is no go left
in the steps executed by travis. Instead we have Python, Ruby and
shell. Let's pick the first...

Picking Python makes travis unhappy with "Can not perform a '--user'
install. User site-packages are not visible in this
virtualenv". Dropping the '--user' flag fixes that.

(cherry picked from commit 1d8d098450)
2016-02-22 13:29:33 +00:00
Matthias Radestock 12d848162d shrink Travis usage
There is no point running builds, tests, lints on Travis, since we
already do that on Circle.

The only thing we aren't doing (and can't do) on Circle is doc
publishing, so now Travis does just that.

(cherry picked from commit 1038cbd1a3)
2016-02-22 13:29:33 +00:00
Matthias Radestock b12096bd6c tweak 2016-02-22 13:23:29 +00:00
Matthias Radestock 644485d4ae Merge branch '1.4' 2016-02-22 13:13:48 +00:00
Matthias Radestock 1430982166 Merge branch 'latest_release_doc_updates' into 1.4 2016-02-22 13:13:13 +00:00
Matthias Radestock 2a83aad1d6 warn against using plugin and proxy simultaneously
and give a complete example.

Partially addresses #1988.
2016-02-22 13:11:02 +00:00
Matthias Radestock 4a7157959a don't attempt to attach 'restarting' containers
this is an optimisation... there is no point attempting to attach a
'restarting' container - it will fail.

When the container *actually* restarts we'll get a 'Start' event, and
attach at that point.

Also, there is no point checking for 'Paused' since 'Paused' ->
'Running'.
2016-02-20 11:00:04 +00:00
Matthias Radestock e52abafc48 treat restarting containers as "not running"
thus preventing stale DNS & IPAM entries.

Fixes #1977
2016-02-20 10:59:47 +00:00
Bryan Boreham b064bcce49 Log when command-line peer list overridden by persisted list
Reworked interface to router so we split setting up the initial list
from beginning to make connections - we shouldn't do that until
after router.Start().
2016-02-19 14:29:33 +00:00
Matthias Radestock 0f9d9c77a3 remove cruft 2016-02-19 00:30:22 +00:00
Matthias Radestock 33c81add8d update dependency to fix build breakage 2016-02-19 00:27:45 +00:00
Matthias Radestock ee531b8023 don't complain on relaunch when ODP is not supported
...and WEAVE_NO_FASTDP isn't set.

Fixes #1929.
2016-02-18 22:00:08 +00:00
Matthias Radestock 497a104db7 Merge branch '1.4' 2016-02-18 21:59:42 +00:00
Matthias Radestock 5e761a62b0 Merge pull request #1985 from weaveworks/issues/1984-discovery
Add two functions required by ipamapi "contract"

Fixes #1984
2016-02-18 21:55:53 +00:00
Bryan Boreham b442567406 Add two functions required by ipamapi "contract" but not actually used 2016-02-18 15:29:10 +00:00
Adam Harrison 5dd8584fb6 Fix veth cleanup on Ubuntu 15.10
Cope with the @ characters that have started appearing in veth names as
of Ubuntu 15.10.
2016-02-18 12:11:48 +00:00
Matthias Radestock 4bd18737b7 fix typo 2016-02-18 11:39:54 +00:00
Bryan Boreham ba8926a6ea Persist set of peers to connect to 2016-02-17 18:12:16 +00:00
Matthias Radestock 09cd9e091a Merge branch '1.4' 2016-02-16 14:09:06 +00:00
Matthias Radestock 17d53af2a2 improve logging of dns entry creation
- log inside the lock, so we get proper serialisation
- include the container name, so we can identify the specific entry
2016-02-16 14:04:34 +00:00
Adam Harrison 2d4d3577ba Merge pull request #1971 from weaveworks/issues/678-persist-ipam2
Persist IPAM ring
2016-02-15 10:15:53 +00:00
Bryan Boreham 546f9592f9 Hard-fail on persistence errors, otherwise the network can get confused on a restart.
Create `Allocator.fatalf()`, for consistency
2016-02-12 18:12:26 +00:00
Bryan Boreham 06f3793f05 Remove persisted IPAM ring data on peerName change 2016-02-12 18:12:26 +00:00
Bryan Boreham f396c60402 Persist the Ring 2016-02-12 18:12:26 +00:00
Bryan Boreham ad036499eb Add db infra to IPAM 2016-02-12 18:12:26 +00:00
Bryan Boreham 38c6eb28e8 Add basic infrastructure to use BoltDB for persistence 2016-02-12 18:12:26 +00:00
Matthias Radestock 11e2515f70 Merge pull request #1968 from weaveworks/refactor-veth-creation
"refactor" veth creation
2016-02-10 13:49:13 +00:00
Matthias Radestock c79e036c08 Merge pull request #1966 from weaveworks/issues/1965-fix-local-weave-ps
Make weaveutil container-addrs observe $PROCFS

Fixes #1965.
2016-02-09 22:40:36 +00:00
Matthias Radestock 7a19c2f147 add a test 2016-02-09 22:26:01 +00:00
Adam Harrison 4cee647e73 Make weaveutil container-addrs observe $PROCFS 2016-02-09 22:25:47 +00:00
Matthias Radestock 7ea3299dc6 oops
/usr/local/bin/weave: 1172: [: true false: unexpected operator

This got broken in #1941.
2016-02-09 22:05:11 +00:00
Matthias Radestock 5707581ba3 Merge pull request #1964 from weaveworks/weave-veth-cleanup
Fix attach-bridge bugs
2016-02-09 21:11:27 +00:00
Adam Harrison 264d5e4828 Make attach-bridge iptables rule insertion idempotent 2016-02-09 20:42:59 +00:00
Matthias Radestock 9311294d9c "refactor" veth creation
Invoke the new create_veth from a few places, eliminating code
duplication and inconsistencies.

Semantic differences:

- init_bridged_fastdp now skips the veth creation/config if the veth
  already exists. This eliminates routing blips. Though in reality
  something very strange must have happened to end up in this code
  with an existing veth.
- init_bridged_fastdp no longer deletes the $BRIDGE and $DATAPATH when
  veth creation/configuration fails. This is consistent with
  init_bridge, which does not delete $BRIDGE when something goes
  wrong. And it is generally desirable since the init_* functions are
  invoked on potentially existing bridges - e.g. following 'weave
  stop'.
- attach_bridge and setup_router_iface_bridge used to mark one veth
  end 'up', then invoke add_iface_* for it, and then mark the other
  end 'up'. create_veth marks both ends 'up' first. This makes no
  practical difference in these cases.

notable other differences:
- we detect veth presence by checking whether *both* ends are present,
  rather than just one. We deliberately continue to (and fail in) the
  veth creation if one end already exists. This can only happen when
  we've stumbled across a different interface, since a veth end cannot
  exist independently. So it is right to treat this as an error.
- init_bridged_fastdp invokes add_iface_bridge instead of duplicating
  what that does. Also makes for nice coherence with the
  add_iface_fastdp it is invoking too.
2016-02-09 19:22:14 +00:00
Adam Harrison 2bfc86e7b2 Cleanup attach-bridge iptables rule 2016-02-09 16:51:04 +00:00
Adam Harrison 36ee8bacb0 Remove all vethwe* interfaces in reset 2016-02-09 16:48:03 +00:00
Matthias Radestock 1bb1108b91 tiny refactor: use ${CONTAINER_IFNAME} for name construction 2016-02-09 16:40:58 +00:00
Matthias Radestock a77201bf77 Merge pull request #1955 from weaveworks/weave-attach-bridge
'attach-bridge' feature to link an existing bridge netdev with the weave bridge
2016-02-09 15:45:28 +00:00
Adam Harrison a3d842bf4a Implement attach-bridge 2016-02-09 15:20:11 +00:00
Adam Harrison 43eb70193b Merge branch '1.4' 2016-02-09 11:40:14 +00:00
Adam Harrison 1228dbddb9 Add release v1.4.4 2016-02-09 11:20:51 +00:00
Adam Harrison a401d0d6ea Merge branch '1.4' 2016-02-09 10:53:52 +00:00
Adam Harrison c00b00d623 Merge pull request #1963 from weaveworks/issues/1959-dont-remove-network
Don't remove weave network on plugin shutdown because it bricks Docker 1.10
2016-02-09 10:53:13 +00:00
Bryan Boreham 7bbc9f1b82 Don't remove the weave network on shutdown because it bricks Docker 1.10 2016-02-09 10:02:06 +00:00
Matthias Radestock 6252871e93 Merge branch '1.4' 2016-02-09 09:30:19 +00:00
Matthias Radestock 15a92f9c92 Merge pull request #1961 from weaveworks/issues/1956-any-iface
Wait for multicast route on any interface

Fixes #1956.
2016-02-09 09:29:05 +00:00
Bryan Boreham 9386c01845 Wait for multicast route on any interface, to match weave script
which only adds a route if there isn't one already
2016-02-08 14:04:25 +00:00
Adam Harrison 6d1e33b558 Merge pull request #1957 from weaveworks/issues/1949-ring-errors
Make error messages on ring merge clearer
2016-02-08 13:52:59 +00:00
Bryan Boreham ed3c50f43e Merge pull request #1951 from weaveworks/issues/1940-remove-proxy-dockerbridgeip-dep
Use netlink instead of shelling out to `weave docker-bridge-ip`
2016-02-08 11:05:10 +00:00
Bryan Boreham 9ac62e8005 Extract common getenv-testing code 2016-02-08 10:46:18 +00:00
Bryan Boreham 034da376c4 Make error messages on ring merge clearer 2016-02-08 10:13:41 +00:00
Matthias Radestock 10fbc75997 Merge pull request #1922 from weaveworks/issues/1179-its-alive
In IPAM, resurrect apparently-dead containers on ContainerStarted event
2016-02-05 16:36:28 +00:00
Matthias Radestock 98d76e1099 Merge pull request #1941 from weaveworks/issues/1873-check-running-master
Improve visibility of startup problems

Fixes #1873.
2016-02-04 16:50:50 +00:00
Matthias Radestock f2a1b3829d tweak: consistency 2016-02-04 16:19:29 +00:00
Matthias Radestock e47c4a78f0 Merge pull request #1948 from weaveworks/test-claimforpeers
Improve IPAM Ring unit testing, and streamline ring.ClaimForPeers
2016-02-04 15:31:00 +00:00
Bryan Boreham f9f6649f90 Check some ring entries via AllRangeInfo, to improve coverage 2016-02-04 15:12:13 +00:00
Bryan Boreham a5c9898884 Checking for existing entries is pointless when the Ring starts empty 2016-02-04 15:12:13 +00:00
Bryan Boreham 839eb28310 Unit test for ring.ClaimForPeers 2016-02-04 15:11:46 +00:00
Adam Harrison e2ec2b436d Use netlink instead of shelling out to weave docker-bridge-ip 2016-02-04 14:00:01 +00:00
Bryan Boreham 07b79568dd Resurrect apparently-dead containers on ContainerStarted event 2016-02-04 13:49:43 +00:00
Bryan Boreham 1d3c80ab49 Merge pull request #1944 from weaveworks/issues/1940-remove-proxy-weaveps-dep
Use netlink instead of shelling out to `weave ps`
2016-02-04 13:45:58 +00:00
Bryan Boreham 38013d2f41 Kill zombies 2016-02-04 12:52:16 +00:00
Adam Harrison 65c48707f6 Use netlink instead of shelling out to weave ps 2016-02-04 12:51:18 +00:00
Adam Harrison 415e550f86 Merge pull request #1930 from weaveworks/issues/1746-always-use-host-netns
Always use host netns
2016-02-04 12:50:08 +00:00
Adam Harrison 034d8933c0 make multiweave work with weave running in the host netns
Multiweave now creates a temporary bridge with an IP alias per router
in the host netns, and overrides the router to bind to that specific
IP for weave protocol and data traffic and http control.
2016-02-03 11:57:12 +00:00
Matthias Radestock cf24bb0e89 remove weaveapi.NewClientWithResolver cruft 2016-02-03 11:56:50 +00:00
Matthias Radestock ae725e333a make plugin pay attention to WEAVE_HTTP_ADDR 2016-02-03 11:54:05 +00:00
Matthias Radestock dde244160b make proxy pay attention to WEAVE_HTTP_ADDR 2016-02-03 11:28:38 +00:00
Matthias Radestock fdd006022d make weave control address configurable 2016-02-02 21:38:02 +00:00
Adam Harrison 1e01a31939 Support --host argument to weave launch
Allow the weave router bind to a specific host IP address instead of
INADDR_ANY.
2016-02-02 20:48:49 +00:00
Adam Harrison 4117ef0c50 Fix WEAVE_NO_FASTDP test on GCE 2016-02-02 20:48:49 +00:00
Matthias Radestock e3c19d6414 get rid of container_ip
We already know what the weave container IP is, since now it runs in
the host netns.
2016-02-02 20:48:49 +00:00
Matthias Radestock b1e6bc2929 Always use host netns
which allows us to get rid of port mappings and a whole bunch of other
code.
2016-02-02 20:48:49 +00:00
Matthias Radestock feee4f0494 refactor: make proxy use weave/api
and extend that api as required, namely with DNSDomain()
2016-02-02 20:45:30 +00:00
Matthias Radestock 34ab86124b fix typo 2016-02-02 20:31:38 +00:00
Adam Harrison f37eb4b77d Merge branch '1.4' 2016-02-02 16:52:20 +00:00
Adam Harrison 5232a9af6b Add release v1.4.3 2016-02-02 16:35:32 +00:00
Adam Harrison 90795e5446 Merge branch '1.4'
Conflicts:
	plugin/ipam/driver.go
2016-02-02 16:04:49 +00:00
Adam Harrison c393b23b31 Merge pull request #1918 from weaveworks/issues/1906-plugin-no-weave
Return an error when weave isn't running, on RequestPool
2016-02-02 15:54:39 +00:00
Matthias Radestock 6bebce0b5a tiny refactor 2016-02-02 14:03:01 +00:00
Bryan Boreham 71da517e88 Refactor to collect all code that touches alloc.owned 2016-02-02 13:57:12 +00:00
Matthias Radestock faa7bad8d8 refactor with_container_netns
make it set CONTAINER_NETNS instead of CONTAINER_PID (well, it still
sets the latter, but not for effect), which reduces coupling.
2016-02-02 13:37:17 +00:00
Matthias Radestock 710c13ced9 correct typo in comment 2016-02-02 13:02:33 +00:00
Adam Harrison 6bd8da905e Refactor: uniform use of weave_container_addresses 2016-02-02 11:30:36 +00:00
Adam Harrison 839f534350 Merge branch '1.4' 2016-02-01 15:30:51 +00:00
Adam Harrison 955fbca44a Merge pull request #1943 from weaveworks/1942-mcast-iface-up
don't set the interface 'up' before it is fully configured
2016-02-01 15:29:46 +00:00
Matthias Radestock 18c26e9fbb don't set the interface 'up' before it is fully configured
This was causing container entrypoints to execute too early,
e.g. before the interface had been given an IP address. But only when
running with --no-multicast-route, since otherwise weavewait is
waiting for the multicast route to appear.

Fixes #1942.
2016-02-01 12:04:15 +00:00
Bryan Boreham 0a4b3a04ba Wait for plugin status via unix socket 2016-02-01 10:11:46 +00:00
Bryan Boreham 78f2d82984 Extract function to listen on Unix socket 2016-02-01 10:11:46 +00:00
Matthias Radestock f8fa37c895 Merge branch '1.4' 2016-01-30 11:16:30 +00:00
Matthias Radestock b54efbde69 fix typo in comment 2016-01-30 11:15:57 +00:00
Bryan Boreham c2a869491f Check State.Restarting as well as State.Running 2016-01-29 17:41:02 +00:00
Bryan Boreham a750ef8033 Don't check if container is running when we only want its ID.
This avoids trying to decide if "restarting" is as good as "running".
In wait_for_status we now explitly check_running, and
in dns_add/remove we add an extra check_running test.
2016-01-29 17:41:02 +00:00
Matthias Radestock 30fef10afa Merge remote-tracking branch 'upstream/master' 2016-01-29 16:08:00 +00:00
Matthias Radestock 2e9c1ee046 Merge branch '1.4' 2016-01-29 16:07:20 +00:00
Adam Harrison 81c49e6005 Merge pull request #1938 from weaveworks/issues/1827-stopped-version
Check if container is running before using its image to ask for version
2016-01-29 15:57:15 +00:00
Adam Harrison 11ccada740 Merge pull request #1939 from weaveworks/issues/1937-dont-rm
Don't rm old containers, in case we want the log
2016-01-29 15:47:40 +00:00
Matthias Radestock be9d64b2cc Merge pull request #1936 from weaveworks/issues/1934-rm-socket
Remove Unix domain sockets on shutdown

Fixes #1934.
2016-01-29 15:46:24 +00:00
Matthias Radestock b2c9802aa2 Merge branch '1.4' 2016-01-29 15:25:50 +00:00
Matthias Radestock c6f356a167 Merge pull request #1935 from weaveworks/issues/1757-volumes-container
Reduce docker volumes for weavewait to just one set per release

Fixes #1757.
2016-01-29 15:24:42 +00:00
Adam Harrison 5fbceb0f78 Merge pull request #1777 from weaveworks/remove-plugin-nameserver-option
Remove 'nameserver' option from plugin
2016-01-29 15:24:04 +00:00
Bryan Boreham 3c6211f9f2 Don't rm old containers, in case we want the log 2016-01-29 15:07:14 +00:00
Bryan Boreham b9502ee1cd Check if container is running before using its image to ask for version 2016-01-29 14:43:02 +00:00
Adam Harrison 4f97b3ac85 Merge pull request #1916 from weaveworks/issues/1734-fixed-ip
Support requesting a specific IP from the plugin
2016-01-29 14:22:23 +00:00
Bryan Boreham e4828ad30a Remove 'nameserver' option 2016-01-29 14:03:04 +00:00
Matthias Radestock 20dab1f8fe Merge branch '1.4' 2016-01-29 12:46:08 +00:00
Matthias Radestock eae45ebc94 Merge pull request #1921 from weaveworks/issues/1745-plugin-ps
Make weave script scan veths with prefix 'ethwe'

Fixes #1745
2016-01-29 12:45:10 +00:00
Bryan Boreham ea50b3d5cc Create a different weavevolumes container for each Weave version.
They will be named 'weavevolumes-v1.4.3', 'weavevolumes-latest', etc.
Use a label to identify these containers so they can all be removed on `weave reset`.
2016-01-29 12:22:22 +00:00
Bryan Boreham 3297b93edb Smoke-test 'weave ps' and restarting when using plugin 2016-01-29 12:13:00 +00:00
Bryan Boreham 6d0e867ad0 Capture addresses from veths with prefix 'ethwe'
This is to address the plugin case, where the veth will have a name like 'ethwe0'.
Previously we only looked at the device named exactly 'ethwe'.
Covers `weave ps` and reclaim of addresses for IPAM and WeaveDNS.
2016-01-29 12:13:00 +00:00
Bryan Boreham 1cea9c1c87 Extract function to detect container running in host namespace 2016-01-29 12:13:00 +00:00
Bryan Boreham 3320a9e7d4 Re-organise code so we can clean up using defer and return error codes to top level 2016-01-29 11:41:24 +00:00
Bryan Boreham 9b90a938f5 Remove Unix domain sockets on shutdown 2016-01-28 18:26:34 +00:00
Bryan Boreham c0ece16881 Don't need to rm the network here because 'weave reset' does it 2016-01-28 17:55:27 +00:00
Matthias Radestock 95a4ca8e3e Merge branch '1.4' 2016-01-28 17:51:20 +00:00
Matthias Radestock c6d0149ba6 add missing dependency
The plugin image derives from the weaveexec image.
2016-01-28 17:50:26 +00:00
Bryan Boreham 598efe5d1a Reduce docker volumes for weavewait to just one set.
- Create an auxilliary container 'weavevolumes' to hold the '/w/w'
  files, and map into that instead of creating new volumes every time.
- Show "/bin/false" as its command in `docker ps` instead of
"/home/weave/sigproxy".
- Remove volumes when cleaning up smoketest containers.
2016-01-28 15:57:22 +00:00
Matthias Radestock cab4e37ef8 Merge pull request #1924 from weaveworks/update-mesh
Update mesh
2016-01-28 10:04:40 +00:00
Peter Bourgon 0dff2e66c6 vendor: update mesh
Now, broadcast operations cannot fail. So, update various broadcast-y
methods to no longer return errors.
2016-01-28 10:43:32 +01:00
Matthias Radestock 6680a8a054 Merge branch '1.4' 2016-01-27 22:04:09 +00:00
Matthias Radestock 3679065258 cope with nil route.Dst
Fixes #1932.
2016-01-27 22:02:07 +00:00
Bryan Boreham 482045aed8 Send back an http error code with any plugin errors. 2016-01-27 14:53:26 +00:00
Bryan Boreham 610a90c727 Claim address requested by caller 2016-01-27 12:11:01 +00:00
Matthias Radestock 31f736b37e fix errors spotted by usage analysis 2016-01-26 18:13:29 +00:00
Matthias Radestock d220379ad3 Merge branch '1.4' 2016-01-26 16:57:28 +00:00
Matthias Radestock 4649f1158a Merge pull request #1926 from weaveworks/issues/1905-fix-negative-fragment
Negative fragment fix

Fixes #1905.
2016-01-26 16:56:03 +00:00
Bryan Boreham 952e9de265 Remove superfluous line and fix comment typo 2016-01-25 18:05:43 +00:00
Bryan Boreham ef1b8d6237 Merge pull request #1927 from weaveworks/revert-1808-1803-plugin-mac
Revert "Refactor plugin to create veths in CreateEndpoint"
2016-01-25 18:04:56 +00:00
Bryan Boreham 2970df4505 Revert "Refactor plugin to create veths in CreateEndpoint" 2016-01-25 17:57:53 +00:00
Adam Harrison 87f793f0e0 Merge pull request #1808 from weaveworks/1803-plugin-mac
Refactor plugin to create veths in CreateEndpoint
2016-01-25 11:53:17 +00:00
Adam Harrison de17a44f35 Fix fragmentation test
The assumptions on which this test was based were violated by the
introduction of fast datapath. A new rule is required to block fast
datapath traffic, to ensure that sleeve is selected for forwarding; the
rules must also be moved from the FORWARD chain to INPUT as the router
now runs in the host netns (NB we use INPUT instead of OUTPUT as the
latter results in sleeve receiving an 'operation not permitted' udpv4
write error when it tries to send a packet that is too big, rather than
the packet just being silently dropped as required)
2016-01-25 10:58:31 +00:00
Adam Harrison 52ce4df18e Increase the lowest possible good PMTU
The current minimum PMTU we can detect is eight bytes, which, being
lower than the minimum IPv4 MTU of 68 bytes, can cause an exception in
the sleeve packet fragmentation implementation. We increase that minimum
to 552, the lowest PMTU value that Linux will cache.
2016-01-25 10:53:10 +00:00
Matthias Radestock 1a590b3ffa document --name 2016-01-23 09:01:41 +00:00
Matthias Radestock e249a7ef0c tweak plugin docs 2016-01-22 13:44:49 +00:00
Matthias Radestock 83412e4514 Merge pull request #1915 from weaveworks/issues/1806-plugin-subnet
Support subnet and iprange arguments on network create

Closes #1806.
2016-01-22 13:39:52 +00:00
Bryan Boreham 1a59734cdb Support subnet and iprange arguments on network create 2016-01-22 13:37:36 +00:00
Matthias Radestock 7f3dc6f202 Merge branch '1.4' 2016-01-22 13:35:58 +00:00
Matthias Radestock f1ed5bf838 Merge branch 'latest_release_doc_updates' into 1.4 2016-01-22 13:35:27 +00:00
Matthias Radestock 256a801d16 typo 2016-01-22 13:34:59 +00:00
Matthias Radestock c416cf8da5 tidying of plugin docs 2016-01-22 13:27:22 +00:00
Matthias Radestock efffbe6de1 Merge pull request #1913 from weaveworks/fix-smoketests-docker-1.10
Fix smoke tests for docker 1.10
2016-01-21 17:30:52 +00:00
Adam Harrison a64435a9a5 Adjust tests to accomodate docker/docker#14012 2016-01-21 17:28:54 +00:00
Bryan Boreham c2fba38c46 Merge pull request #1902 from weaveworks/vendored-dep-management-doc
Document vendored dependency management commands
2016-01-21 14:14:47 +00:00
Matthias Radestock d2ba647f68 Merge pull request #1920 from weaveworks/1893-make-testrunner
move smoke test dependencies from 'all' to 'testrunner' target

Fixes #1893.
2016-01-21 13:46:34 +00:00
Matthias Radestock a6aad6dc49 move smoke test dependencies from 'all' to 'testrunner' target
That way a plain 'make' works out-of-the-box.

Fixes #1893.
2016-01-21 13:00:32 +00:00
Bryan Boreham 7455a699c4 Use more chars from endpointID to reduce clashes 2016-01-21 12:36:58 +00:00
Matthias Radestock 0872623ca5 Merge branch '1.4' 2016-01-21 12:30:32 +00:00
Matthias Radestock 75e812a061 Merge branch 'latest_release_doc_updates' into 1.4 2016-01-21 12:30:14 +00:00
Matthias Radestock 4cc7b01940 Merge pull request #1907 from weaveworks/systemd-timeout
Suggest disabling systemd timeout if using Weave Net plugin
2016-01-21 12:29:42 +00:00
Matthias Radestock 4d05775e11 Merge branch '1.4' 2016-01-21 11:30:05 +00:00
Matthias Radestock a2ff7e5981 Merge pull request #1919 from weaveworks/issues/1900-dont-stop-stoppin
Warn, don't error, if unable to remove network in 'weave stop'

Fixes #1900.
2016-01-21 11:22:21 +00:00
Matthias Radestock d5bfc61a73 use hashicorp's wily64 images instead of ubuntu's
The latter suffer from https://github.com/mitchellh/vagrant/issues/6653
2016-01-21 11:08:14 +00:00
Bryan Boreham 7ec17ab2ef Merge branch '1.4' 2016-01-21 10:18:01 +00:00
Bryan Boreham cda98a6375 Merge pull request #1917 from weaveworks/issues/1911-fix-unexpected-eof
Fix unexpected EOF with Docker 1.10-rc1 and proxy --rewrite-inspect
2016-01-21 10:15:20 +00:00
Matthias Radestock 03ac917567 Merge branch '1.4' 2016-01-20 18:56:59 +00:00
Matthias Radestock 3b7a754b0a Merge branch 'latest_release_doc_updates' into 1.4 2016-01-20 18:56:26 +00:00
Anita Buehrle c01c6bcb91 fixed logo image in header 2016-01-20 12:48:31 -06:00
Bryan Boreham 5d598a1015 Refactor to make suffix part clearer 2016-01-20 16:50:42 +00:00
Bryan Boreham adafb79e34 Move endpoint creation into CreateEndpoint so we can return the MAC address 2016-01-20 16:45:08 +00:00
Bryan Boreham e47360f8dc Warn, don't error, if unable to remove network in 'weave stop' 2016-01-20 16:18:09 +00:00
Bryan Boreham 6035b54277 Send back an http error code in case of error, so Docker is clear something went wrong 2016-01-20 15:36:42 +00:00
Bryan Boreham a238130613 Give more explanation if we can't find weave to talk to 2016-01-20 15:36:34 +00:00
Bryan Boreham 998be42a52 Don't crash if no default subnet available 2016-01-20 15:36:25 +00:00
Matthias Radestock bafa3f4f4e Merge pull request #1912 from weaveworks/wily-vagrant
Update Vagrant to use Wily 15.10
2016-01-20 14:59:40 +00:00
Adam Harrison 14944da396 Ignore stderr in proxy_addrs 2016-01-20 14:24:59 +00:00
Adam Harrison a3974c2aeb Abort inspect exec rewrite unless Containers node is present 2016-01-20 14:24:28 +00:00
Bryan Boreham 6570b0ba1a Merge branch '1.4' 2016-01-20 14:06:00 +00:00
Bryan Boreham 13ec517f94 Merge pull request #1910 from weaveworks/1909-forEachRoute-panic
cope with errors during route traversal
2016-01-20 14:05:10 +00:00
Adam Harrison 2a2b2da097 Update Vagrant to use Wily 15.10 2016-01-20 09:17:07 +00:00
Matthias Radestock 43419815f4 bypass netlink.LinkByIndex
since we are seeing some cases where it returns "Link not found" when
the link is in fact there.
2016-01-19 16:36:16 +00:00
Matthias Radestock b5256f7b71 refactor: inline
This eliminates the unnecessary indirection via interface names,
instead identifying the interface by its index.
2016-01-19 16:36:16 +00:00
Matthias Radestock 0caa9dd652 cope with errors during route traversal
Fixes #1909.
2016-01-19 15:28:31 +00:00
Bryan Boreham dd7271aaa2 Merge pull request #1866 from weaveworks/901-peername-from-machine-id
Derive peer name from product_uuid; LGTM
2016-01-18 15:29:44 +00:00
Matthias Radestock 133c16f989 document new reboot behaviour
...and generally tidy up IPAM stop/restart docs.
2016-01-18 14:57:03 +00:00
Matthias Radestock e631fb0d69 derive the bridge MAC from the system (aka BIOS) UUID
...if possible. This provides a stable peer identity across
reboots. If we cannot determinbe the system UUID then we revert to a
random MAC, as before.

Fixes #901.
2016-01-18 14:56:55 +00:00
Bryan Boreham 5e1e8ec543 Suggest user disables systemd timeout if using plugin 2016-01-18 11:45:17 +00:00
Adam Harrison 432c1904da Merge pull request #1890 from weaveworks/1889-vendor-mesh
Change import location for mesh
2016-01-15 17:18:31 +00:00
Adam Harrison 8a691814e2 Document vendored dependency management commands 2016-01-15 16:17:07 +00:00
Peter Bourgon 553c8b734d git submodule add weaveworks/mesh 2016-01-15 16:03:42 +01:00
Peter Bourgon 3767a680e8 Makefile doesn't need to build mesh/*.go anymore 2016-01-15 15:57:01 +01:00
Peter Bourgon e27b320ede Update import location for mesh 2016-01-15 15:57:01 +01:00
Peter Bourgon 90afa7db93 git rm -rf mesh 2016-01-15 15:57:01 +01:00
Bryan Boreham efd4fc4704 Merge pull request #1901 from weaveworks/1897-weaveutil-plugin-network
move plugin network creation/removal into weaveutil
2016-01-15 11:07:38 +00:00
Matthias Radestock d770532b08 improve error handling 2016-01-15 08:53:04 +00:00
Matthias Radestock 31b303a419 move plugin network creation into weaveutil
Note that we remove the ability to set the weavemesh network name, or
disabling it altogether. This was always poorly support, since the
removal operation only ever operated on the default name. The option
was also not listed in the usage, though it was in the docs.
2016-01-15 08:52:57 +00:00
Matthias Radestock 9578798ec0 move plugin network removal into weaveutil
This does require starting containerised weaveutil with docker.sock
volume mounts.
2016-01-15 07:58:21 +00:00
Matthias Radestock 8061ea4079 don't attempt to delete the mesh network on plugin termination
It's pointless and inconsistent. Firstly, deletion will fail if there
are any attached containers. Secondly, we run the plugin with
restart=always, so it will get restarted and the network re-created.

Removal of the network does still happen on `weave stop|reset`, if
possible.
2016-01-15 06:21:11 +00:00
Tom Wilkie a83b58cd27 Merge pull request #1896 from weaveworks/tweak-circle
Improve build times on CircleCI
2016-01-14 08:57:20 -08:00
Bryan Boreham 8eeb6dd836 Only rebuild without coverage if we're going to publish 2016-01-14 15:33:46 +00:00
Bryan Boreham bd7e5d6921 Do a build before the 'go test'; perversely this runs faster 2016-01-14 15:29:58 +00:00
Bryan Boreham 7c1e80ca89 Don't do coverage on vendored directories 2016-01-14 14:16:28 +00:00
Bryan Boreham 9aae1fa3c9 Save the ~/docker directory in cache because rebuild_image stores things there 2016-01-14 13:02:32 +00:00
Adam Harrison 5bf440d558 Merge branch '1.4' 2016-01-14 12:07:21 +00:00
Adam Harrison c391092ea6 Add release v1.4.2 2016-01-14 11:40:17 +00:00
Matthias Radestock d97c385b4e make 'make lint' run gocyclo (again) 2016-01-13 17:02:52 +00:00
Matthias Radestock 1d3ca061ad tiny refactor: tweak init order for better grouping 2016-01-13 16:48:49 +00:00
Matthias Radestock d50975a185 refactor: extract password determination 2016-01-13 16:23:00 +00:00
Matthias Radestock 6261ce0865 extract our peer name creation 2016-01-13 16:23:00 +00:00
Tom Wilkie b4682bbc8c Fresh clones need git submodule update --init 2016-01-13 08:22:35 -08:00
Adam Harrison d9a32e563c Merge pull request #1861 from weaveworks/1657-1656-vendor-and-build-in-container
Build in a container by default, using go 1.5 and vendored dependencies.
2016-01-13 15:55:51 +00:00
Adam Harrison b0e98f99d0 Merge pull request #1888 from weaveworks/refactor-overlay-init
refactor overlay creation
2016-01-13 15:35:11 +00:00
Tom Wilkie 6684ae8316 Do a git submodule update every time we enter the build container. 2016-01-13 05:58:41 -08:00
Matthias Radestock 9b4a5d1cb4 tiny refactor: just move around some code
The router name derivation uses the result of createOverlay, so move
it closer to that.
2016-01-13 13:52:09 +00:00
Matthias Radestock 9f79e5be54 refactor: rename
Conceptually, an OverlaySwitch is just a single Overlay.
2016-01-13 13:52:09 +00:00
Matthias Radestock aa44b66a31 refactor: extract overlay creation 2016-01-13 13:52:09 +00:00
Matthias Radestock 3a367595d7 derive routerName from networkConfig.Bridge.Interface() 2016-01-13 13:52:00 +00:00
Matthias Radestock e5c256daa1 add Bridge.Interface() 2016-01-13 13:50:18 +00:00
Matthias Radestock f12ec3b295 refactor(ish): make fastdp hold on to interface
rather than just the MTU
2016-01-13 13:50:18 +00:00
Matthias Radestock 9f0399f27e refactor: extract DNSServer creation 2016-01-13 13:48:38 +00:00
Matthias Radestock cc72f7d3ee cosmetic 2016-01-13 13:20:17 +00:00
Tom Wilkie c098aefed9 Build in a container by default, using go 1.5 and vendored dependancies.
- Use submodules for vendoring.
- Don't go clean, now that everything is in .pkg.
- sudo -E as we need the environment variables.
- Install -race version of std so the tests can run without sudo.
- Cache the build image on circle, use the rebuild-image script from tools.
2016-01-13 04:40:18 -08:00
Matthias Radestock 6a103aef27 cosmetic 2016-01-13 11:49:15 +00:00
Matthias Radestock 80df5a7906 cosmetic 2016-01-13 11:39:32 +00:00
Adam Harrison 28561237ab Merge branch '1.4' 2016-01-13 11:10:30 +00:00
Adam Harrison b3a29bec1b Merge pull request #1886 from weaveworks/issues/1869-leave-plugin
Allow plugin to keep running on 'weave launch'
2016-01-13 11:08:54 +00:00
Bryan Boreham b055c9a4a2 Fool-proofing 2016-01-13 10:33:49 +00:00
Matthias Radestock 799160c5c2 remove "encryption -> pcap" cruft
As of e12dbb460 (#1758) we no longer force the usage of pcap when
encryption is enabled. Hence...

- we no longer need to figure out whether the router was started with
  a password when re-attaching it from the proxy. We therefore remove
  the code for that.

- there is no longer any mode in which we pass both `--datapath` and
  `--iface` options to the router. Previously this would only happen
  when encryption was enabled and the only overlay used for
  connections was sleeve. It is not clear what the behaviour is when
  these conditions do not hold, so, to be safe, we prevent the
  specification of both flags.
2016-01-13 10:27:25 +00:00
Bryan Boreham 3daceac668 Allow pre-existing plugin on 'weave launch-plugin' 2016-01-13 10:05:02 +00:00
Adam Harrison 29ebeeaff5 Merge pull request #1191 from weaveworks/1047-same-ip-on-restart
Don't delete record of IP allocation immediately after container death
2016-01-13 09:46:12 +00:00
Matthias Radestock 257d88f48e Merge branch '1.4' 2016-01-13 09:26:13 +00:00
Matthias Radestock 4611e8825a Merge branch 'latest_release_doc_updates' into 1.4 2016-01-13 09:25:34 +00:00
Matthias Radestock 00e4729533 Merge pull request #1872 from weaveworks/issues/1871-address-docs
Documentation on IP addresses, routes and networks
2016-01-13 09:24:31 +00:00
Bryan Boreham 517a2e0e0a Fix nonzero exit code for a pre-existing plugin on launch;
do this purely for the 'plugin running' case, not 'restarting' etc.
2016-01-12 17:06:38 +00:00
Bryan Boreham bb8c7c599c Revert "don't launch anything when plugin is running"
This reverts commit 3ade796e8d.
2016-01-12 16:51:49 +00:00
Bryan Boreham 0d0fc39236 More review feedback 2016-01-12 15:35:34 +00:00
Bryan Boreham e468399616 Extend the timeout for dead containers to 30 seconds,
but remove them if they are destroyed, to reduce starvation
when users are creating and destroying containers quickly.
2016-01-12 14:38:44 +00:00
Bryan Boreham b2b293a8ee Added 'ContainerDestroyed()' callback from docker client 2016-01-12 14:38:44 +00:00
Bryan Boreham 2f885a7906 Reclaim all addresses on restart 2016-01-12 14:38:44 +00:00
Bryan Boreham 7985e43e68 Add 'weave restart' command 2016-01-12 14:38:44 +00:00
Bryan Boreham f84b933d7c Leave container allocations for a time after death
so they will be reclaimed if the container is restarted.
Still cancel pending operations immediately a container dies
2016-01-12 14:38:44 +00:00
Bryan Boreham 4672e9ec1f Generalise ticker so we can use it for more than paxos,
and call tryPendingOps() from it so we eventually re-try operations
2016-01-12 14:38:44 +00:00
Adam Harrison a5ddba03f7 Merge branch '1.4' 2016-01-12 14:28:16 +00:00
Adam Harrison 302a5a4efc Merge pull request #1884 from weaveworks/issues/1882-check-after-subscribe
Fix race condition in weavewait
2016-01-12 14:28:03 +00:00
Bryan Boreham 3b29e8e6f2 Check for existing interfaces and routes after subscribing to receive new ones 2016-01-12 12:27:55 +00:00
Bryan Boreham a1dff70ba2 Review feedback 2016-01-11 11:55:11 +00:00
Matthias Radestock 9336cc4121 Merge branch '1.4' 2016-01-11 11:49:49 +00:00
Matthias Radestock 12671be260 Merge branch 'latest_release_doc_updates' into 1.4 2016-01-11 11:49:22 +00:00
Matthias Radestock d2ad5ddb01 oops 2016-01-11 11:47:22 +00:00
Tom Wilkie 73df093e48 Merge pull request #1864 from weaveworks/shrink-travis-usage
Shrink travis usage
2016-01-11 11:27:02 +00:00
Bryan Boreham 9a4adccec6 Remove inconsistent information about restart policy 2016-01-11 11:20:40 +00:00
Matthias Radestock abea21245d rename Makefile target
since travis is no longer using it
2016-01-11 10:33:33 +00:00
Bryan Boreham f90390974a Add page explaining IP addresses, networks and routes 2016-01-11 10:30:37 +00:00
Matthias Radestock 0b4f1b5af0 cosmetic: whitespace 2016-01-11 00:42:14 +00:00
Matthias Radestock 9933a4a368 refactor: tweak overlay & bridge initialisation sequence
for clarity
2016-01-11 00:13:29 +00:00
Matthias Radestock c3f2150b5b cosmetic: whitespace 2016-01-11 00:03:37 +00:00
Matthias Radestock 46566e2159 refactor: extract sleeve crypto initialisation 2016-01-10 23:52:46 +00:00
Matthias Radestock 1d8d098450 for Travis, this no longer is a go project
Travis insists that one picks a project language. There is no go left
in the steps executed by travis. Instead we have Python, Ruby and
shell. Let's pick the first...

Picking Python makes travis unhappy with "Can not perform a '--user'
install. User site-packages are not visible in this
virtualenv". Dropping the '--user' flag fixes that.
2016-01-09 14:21:23 +00:00
Matthias Radestock 1038cbd1a3 shrink Travis usage
There is no point running builds, tests, lints on Travis, since we
already do that on Circle.

The only thing we aren't doing (and can't do) on Circle is doc
publishing, so now Travis does just that.
2016-01-09 14:01:27 +00:00
Matthias Radestock 21a2cdd579 Merge branch '1.4' 2016-01-08 18:14:56 +00:00
Matthias Radestock f598ae297b Merge branch 'latest_release_doc_updates' into 1.4 2016-01-08 18:14:23 +00:00
Bryan Boreham 4b0fe502f0 Document the --no-multicast-route flag 2016-01-08 17:12:20 +00:00
Matthias Radestock d9b9ce6bcd simplify gitignore 2016-01-08 15:23:37 +00:00
Matthias Radestock 4fffa6fa43 fix typo 2016-01-08 15:11:21 +00:00
Tom Wilkie c0cd9dffc2 Merge pull request #1862 from weaveworks/1651-pause-differently
Fix race condition in ipam TestHTTPCancel
2016-01-08 14:07:06 +00:00
Bryan Boreham f91d7bb7e4 Rewrite TestHTTPCancel to avoid fiddling inside Allocator 2016-01-08 13:37:15 +00:00
Matthias Radestock 3e6f31c8e2 add missing dependencies and netgo checks 2016-01-08 13:27:37 +00:00
Matthias Radestock 19b53cdeb1 refactor: get rid of superfluous rule 2016-01-08 12:06:38 +00:00
Matthias Radestock c6cc10169f refactor: put all dependencies in one place 2016-01-08 12:05:48 +00:00
Bryan Boreham 987d89632d Merge pull request #1847 from weaveworks/1613-weaveutil
extract script utilities into single binary; LGTM
2016-01-07 18:53:25 +00:00
Bryan Boreham 8804f88c93 Merge pull request #1856 from weaveworks/no-gossip-sender-gc
get rid of GossipSender gc; LTGM
2016-01-07 17:29:54 +00:00
Bryan Boreham 3c654bc036 Merge pull request #1561 from weaveworks/proxy-retry-attach
Proxy retry attaching containers; fixes #1556
2016-01-07 17:27:19 +00:00
Paul Bellamy 8ddbb3d8af [proxy] Keep retrying container attaches until they succeed. 2016-01-07 17:09:34 +00:00
Tom Wilkie 422e9b58cd Merge pull request #1857 from weaveworks/issues/864-gce-retry
Stop masking failures in gce hosts destroy
2016-01-07 14:53:02 +00:00
Matthias Radestock 64a017c972 Merge branch '1.4' 2016-01-07 14:36:08 +00:00
Matthias Radestock e4295a2da9 don't attach rewrite_etc_hosts helper container to weave
...since that is a) inefficent and b) can block when IPAM hasn't had
consensus.

We can only end up in this situation when DOCKER_HOST is pointing at
the weave proxy and we are running `weave run|attach` with
`--local`. So it's very much an edge case.

Fixes #1858.
2016-01-07 14:32:52 +00:00
Matthias Radestock 216a0fe4fc refactor: WEAVE_CIDR=none is redundant when --net=host 2016-01-07 14:29:51 +00:00
Bryan Boreham 604f5c599a Check if there are any machines to destroy, and stop masking failures 2016-01-07 13:40:34 +00:00
Matthias Radestock 9aa4313d37 refactor 2016-01-06 17:38:40 +00:00
Matthias Radestock 969dc4e527 get rid of GossipSender gc
With the per-broadcast-source GossipSenders gone, we can get rid of
GossipSender gc...

Instead of maintaining a Connection->GossipSender map in the
GossipChannels - which we then need to gc when connections get closed
- we keep gossip_channel_name->GossipSender maps in LocalConnections.

Access to the map is guarded by a separate lock, rather than re-using
the LocalConnection lock. This reduces lock contention and risk of
deadlock.

In the GossipSenders, we replace the Stop() method with a signalling
channel, i.e. senders stop when that channel gets closed. Handily, the
LocalConnection.finished channel fits that description. So when a
LocalConnection's run loop terminates, any existing and future
associated GossipSenders will end up terminating too.
2016-01-06 17:38:40 +00:00
Bryan Boreham bbd0b15792 Merge pull request #1855 from weaveworks/gossip-broadcast-stall-3
don't stall gossip broadcasting when there are blocked connections; LGTM
2016-01-06 16:43:37 +00:00
Matthias Radestock 99b7fbbc71 optimisation: stop GossipSender on send error 2016-01-05 17:18:41 +00:00
Matthias Radestock 486eb740b5 optimisation: abort GossipSender.deliver when stopped 2016-01-05 17:18:41 +00:00
Matthias Radestock c6a73b8a75 don't stall broadcasting when there are blocked connections
Previously broadcasts were being handled by one GossipSender per
broadcast source (and channel), which sends the broadcast to all next
hops, and hence can stall when a single destination is stalled.

Here we get rid of these per broadcast source GossipSenders. Instead
broadcasts are sent to per-connection GossipSenders for all next hops.

For this we use the existing GossipSenders we have set up for ordinary
gossip. In order to deal with broadcasts they need one GossipData cell
per broadcast source, since only broadcasts from the same source can
be Merge()ed. So we add a PeerName->GossipData map of cells, in
addition to the existing cell for ordinary gossip.

The GossipSender goroutine picks one of the cells at a time, Encode()s
the contents and sends it. It prefers the ordinary gossip cell over
the broadcast cells since typically ordinary gossip is more important.

To reduce coupling, the GossipSenders don't actually know how to
construct protocol messages. They just invoke a couple of functions
for that - one for ordinary gossip and one for broadcast - which are
supplied by the GossipChannel.

There are two downsides to this change:

1. broadcasts get encoded per connection, rather than just once

2. we can potentially end up with O(n_peers^2) cells, each containing
accumulated (via GossipData.Merge()) broadcasts. For this to happen,
the peer must

- deal with gossip from most nodes. This doesn't happen in
  (near)complete connection topologies. Hypercube topologies are
  probably the worst case uniform topology. And a star topology is the
  worst case for a single (the centre) peer.

- have backlogged connections to most of its neighbours, without
  those connections being completely stalled (since that would cause
  heartbeat timeouts to terminate them).

Furthermore, for this to matter in practise, the accumulated broadcast
GossipData must be sizeable:

- For topology gossip, GossipData is just a set of PeerNames. Which
  takes very little space and is bounded, since there is a finite
  number of peers. And, if we could get rid of workaround for #1793
  (cbaa92dcb), then topology broadcasts would only ever contain
  information about the source peer, so the GossipData would contain
  just one PeerName.

- IPAM only employs broadcast during initialisation and shutdown.

- DNS broadcasts contain DNS entries for containers on the source
  peer. Each entry will typically be 100-200 bytes. The accumulated
  broadcast GossipData from a peer will contain entries for all the
  peer's DNS entries, worst case. This includes tombstones,
  i.e. entries for containers that have died. If there is churn,
  i.e. DNS entries being added and removed continuously, and the churn
  rate exceeds the rate at which we can forward those entries, then
  the accumulated broadcast GossipData can grow unbounded. Note that
  this is the case on master too; the difference here is that we can
  have up to n_peers copies of that GossipData.
2016-01-05 17:18:19 +00:00
Bryan Boreham 262f8915a8 Merge pull request #1826 from weaveworks/cleaner-gossip-sender
clean up GossipSender
2016-01-05 16:36:26 +00:00
Ilya Dmitrichenko b623e914c9 update year in copyright notices 2016-01-05 12:19:00 +00:00
Matthias Radestock 70bfcd033b Merge branch '1.4' 2016-01-04 11:14:28 +00:00
Matthias Radestock 80770d39e5 oops 2016-01-04 10:53:41 +00:00
Matthias Radestock beb15fa32c don't fail weave launch when plugin is disabled
Fixes #1851.
2016-01-04 10:35:44 +00:00
Matthias Radestock 1bec425510 Merge branch '1.4' 2016-01-04 09:46:35 +00:00
Matthias Radestock 0adf7626d0 Merge branch 'latest_release_doc_updates' into 1.4 2016-01-04 09:45:56 +00:00
Matthias Radestock 9c17fe259c add ToC to build instructions 2016-01-04 09:41:39 +00:00
Matthias Radestock ecab4b4716 correct image names 2016-01-04 09:35:17 +00:00
Matthias Radestock c3e6669d18 Merge branch '1.4' 2016-01-03 16:45:41 +00:00
Matthias Radestock 7660ad761a oops
I broke this in 370212609.

Fixes #1848.
2016-01-03 16:42:39 +00:00
Matthias Radestock d010000583 fall back to invoking weaveutil in a container
As a result, `weave --local ...` now runs both netcheck and
docker-tls-args.
2016-01-02 14:13:29 +00:00
Matthias Radestock 419f2ff71b move fastdp helpers into weaveutil
so the weave script can invoke them w/o having to run a container
2016-01-02 14:00:44 +00:00
Matthias Radestock 4ebcd355f6 move docker_tls_args into weaveutil
and also give users a clue what went wrong when docker isn't running
2016-01-02 14:00:44 +00:00
Matthias Radestock ec872d7b45 move netcheck into weaveutil 2016-01-02 14:00:44 +00:00
Matthias Radestock 9801e00ba6 add weaveutil
just a placeholder for now
2016-01-02 14:00:44 +00:00
Matthias Radestock 79452d3a9a cosmetic(ish) 2016-01-02 14:00:23 +00:00
Matthias Radestock 0ee22af32d refactor: further simplify fastdp initialisation 2016-01-02 13:17:40 +00:00
Matthias Radestock 13f37edb64 refactor: simplify fastdp initialisation 2016-01-02 13:17:28 +00:00
Matthias Radestock 75d9e95b15 appease linter 2016-01-02 12:35:10 +00:00
Matthias Radestock d59594c6b0 Revert "refactor: pass procfs location to docker_tls_args on command line"
changed my mind

This reverts commit be8260ae79.
2016-01-02 10:50:13 +00:00
Matthias Radestock 4a6b72c649 Revert "cosmetic"
changed my mind

This reverts commit 20a8488a15.
2016-01-02 10:49:22 +00:00
Matthias Radestock 20a8488a15 cosmetic
PROCFS is always set
2016-01-02 00:14:18 +00:00
Matthias Radestock be8260ae79 refactor: pass procfs location to docker_tls_args on command line
...rather than via an env var. This is cleaner.
2016-01-01 23:52:46 +00:00
Matthias Radestock 9c31de9cb9 refactor: replace some 'if's with && and || expressions 2015-12-31 15:36:18 +00:00
Matthias Radestock c1e8c9c537 Merge branch '1.4' 2015-12-31 13:26:55 +00:00
Matthias Radestock c8ff2de3b3 properly deal with unavailable docker server api version
Fixes #1845.
2015-12-31 12:51:16 +00:00
Matthias Radestock 24d1c73012 Merge branch '1.4' 2015-12-31 12:32:30 +00:00
Matthias Radestock 24a2e43547 Merge pull request #1841 from weaveworks/1840-weave-stop-plugin-complaint
don't complain in `weave stop` when plugin is not enabled

Fixes #1840.
2015-12-31 12:32:05 +00:00
Matthias Radestock 2816899543 refactor: extract helper to invoke fastdp functions from script 2015-12-31 12:19:51 +00:00
Matthias Radestock 394d2add68 Merge branch '1.4' 2015-12-31 10:59:10 +00:00
Matthias Radestock a9d212c888 don't fail on missing docker_tls_args
instead just don't auto-detect TLS args in that case.

This makes `weave --local launch` work (again).

Fixes #1844.
2015-12-31 10:43:46 +00:00
Matthias Radestock c1b1276aaf refactor: simplify 2015-12-31 10:16:37 +00:00
Matthias Radestock 370212609c Show expected error message when docker_tls_args fails.
And also make the error message more meaningful.

Fixes #1843.
2015-12-31 10:05:41 +00:00
Matthias Radestock 159bad54b0 prettier usage 2015-12-31 01:42:01 +00:00
Matthias Radestock 1cc7ca18ba Merge branch '1.4' 2015-12-31 01:11:06 +00:00
Matthias Radestock 281937cf82 document weave launch-router --trusted-subnets
and eliminate duplication

Fixes #1842.
2015-12-31 01:09:51 +00:00
Matthias Radestock d11b6e8075 don't complain in weave stop when plugin is not enabled 2015-12-30 23:40:27 +00:00
Matthias Radestock 4e22922256 refactor: rename netcheck.go -> main.go, for consistency 2015-12-30 23:17:48 +00:00
Matthias Radestock 8f01f6e85c make some rules more generic, depending on *.go instead of main.go 2015-12-30 23:14:53 +00:00
Matthias Radestock 27f477a075 refactor: introduce a small helper so we don't repeat ourselves 2015-12-30 22:40:30 +00:00
Matthias Radestock 82ac69be4e cosmetic 2015-12-30 22:23:16 +00:00
Matthias Radestock 0f357cdf7c Merge branch '1.4' 2015-12-30 20:27:18 +00:00
Matthias Radestock 7709c6d0bd Merge branch 'latest_release_doc_updates' into 1.4 2015-12-30 20:26:06 +00:00
Matthias Radestock ef3e478506 Merge pull request #1804 from weaveworks/1774-trouble
Update 'reboots' info

Fixes #1774.
2015-12-30 19:51:09 +00:00
Matthias Radestock 93eef26d0b reword 2015-12-30 19:38:13 +00:00
Matthias Radestock 14d78cf08c Update 'reboots' info 2015-12-30 19:32:18 +00:00
Matthias Radestock 872d88acb6 Merge branch '1.4' 2015-12-30 19:14:51 +00:00
Matthias Radestock e96a63f550 Merge branch 'latest_release_doc_updates' into 1.4 2015-12-30 19:14:33 +00:00
Matthias Radestock 7a5b69f850 cosmetic 2015-12-30 19:13:57 +00:00
Matthias Radestock a71d2a1682 move things around on troubleshooting page
- level 2 headings for top-level instead of level 3
- put all status reporting as L3s under one L2 heading
- add 'Reboots' to ToC
- move 'Stopping weave' into its own section and and move that
2015-12-30 19:06:04 +00:00
Matthias Radestock f0f0e6f36d reword "Contact Us" 2015-12-30 18:37:57 +00:00
Matthias Radestock 6ecdf69b88 replace partially broken link soup 2015-12-30 17:42:49 +00:00
Matthias Radestock 58de14ff65 optimisation: don't re-assign our ShortID if nothing got gc'ed 2015-12-30 14:07:23 +00:00
Matthias Radestock 4d304146f3 refactor: inlining 2015-12-30 12:29:23 +00:00
Matthias Radestock e9520215a0 refactor: introduce a helper
which has a very narrow purpose, and can use 'defer' to release the
lock, which is nice.
2015-12-30 12:09:19 +00:00
Matthias Radestock a2b192c472 we no longer need the GossipChannel lock around GossipSender.Send 2015-12-30 12:09:19 +00:00
Matthias Radestock 52575915d0 clean up GossipSender and make it more self-contained
In particular don't require Send() to be serialised by the caller.

We split up the triple(!) purpose 'cell' channel into:

1) a 'cell' member, holding pending GossipData or nil
2) a 'more' channel, for signalling that 'cell' has been filled
3) a 'stop' channel, for requesting termination
2015-12-30 12:09:19 +00:00
Matthias Radestock 0ecc0ee02e tiny refactor 2015-12-30 12:07:56 +00:00
Matthias Radestock 8101dea338 remove some noisy logging 2015-12-24 21:25:25 +00:00
Matthias Radestock 373f8a4463 oops 2015-12-24 21:23:35 +00:00
Matthias Radestock 8846274c42 optimisation: terminate connection actorLoop asap on error 2015-12-24 14:25:25 +00:00
Matthias Radestock c2356ebcde optimisation: stop sending gossip on dead connections
An error in SendProtocolMsg indicates that the connection is
permanently broken. So there is no point continuing to attempt to send
gossip on it.

The connection will eventually be removed from LocalPeer, and any
associated GossipSenders will be gc'ed, but that doesn't happen
straight away, so this change is about not doing unnecessary work in
the meantime.
2015-12-24 12:27:33 +00:00
Matthias Radestock 33812f7666 tiny refactor: rename 2015-12-23 18:44:09 +00:00
Matthias Radestock f58e3bf2a9 refactor: relocate an optimisation -> reduce duplication 2015-12-23 18:27:59 +00:00
Matthias Radestock 5473995305 remove maxFeasibleMessageLen check
since the root cause got fixed by 3cd199e85
2015-12-23 15:29:35 +00:00
Bryan Boreham 1796582032 Merge pull request #1773 from weaveworks/1761-lazy-route-calculation-1
lazy route calculation; LGTM
2015-12-23 12:27:02 +00:00
Bryan Boreham 4214a09392 Merge branch '1.4' 2015-12-23 11:09:13 +00:00
Bryan Boreham e833ab672d Merge branch '1.4' 2015-12-23 11:08:23 +00:00
Bryan Boreham 257b1a5353 Add the plugin to the list of images to tag and push 2015-12-23 11:00:58 +00:00
Matthias Radestock 39e29fd40b refactor(ish): cleaner / more idiomatic GossipSender flush 2015-12-23 10:57:36 +00:00
Bryan Boreham ec0c5f0375 Merge pull request #1800 from weaveworks/1568-release-process
Add more steps to the release process; fixes #1568 and #1506
2015-12-23 10:52:02 +00:00
Bryan Boreham b45ac75735 Merge pull request #1825 from weaveworks/1824-idempotent-env-restore
make `eval $(weave env)` idempotent; LGTM.  Fixes #1824
2015-12-23 10:48:35 +00:00
Bryan Boreham ac53d7d47b Merge pull request #1801 from weaveworks/1723_publish_plugin
Add the plugin to the list of images to tag and push. Fixes #1723
2015-12-23 10:46:15 +00:00
Matthias Radestock c7c669fd11 make eval $(weave env) idempotent
so that `weave $(env --restore)` does the right thing regardless of
how many times `eval $(weave env)` was invoked previously.

Fixes #1824.
2015-12-23 09:08:56 +00:00
Bryan Boreham fdc7e15192 Merge branch '1.4' 2015-12-22 17:36:06 +00:00
Bryan Boreham ba266ef8d3 Add release v1.4.1 2015-12-22 17:25:47 +00:00
Bryan Boreham f434fad3be Merge pull request #1822 from weaveworks/1820-unix-only
Only pass $DOCKER_HOST if it is a Unix socket - fixes #1820
2015-12-22 17:16:40 +00:00
Bryan Boreham bab758ebf9 Revert "Launch the proxy via unix socket in last test"
- since we won't now be copying $DOCKER_HOST

This reverts commit d8cfbc4e08.
2015-12-22 17:01:04 +00:00
Bryan Boreham 800f4663b6 Only pass through $DOCKER_HOST in exec_remote() if it is a Unix socket;
a TCP socket may be secured by TLS, in which case we can't use it.
2015-12-22 17:01:04 +00:00
Matthias Radestock 78ba69ef9f Merge branch '1.4' 2015-12-22 15:25:48 +00:00
Matthias Radestock b1b62afa90 Merge pull request #1812 from weaveworks/1810-warn-with-dns
Issue a warning on --with-dns option to proxy, because it was removed

Fixes #1810
2015-12-22 15:12:27 +00:00
Bryan Boreham 6b90ef7078 Clarify message 2015-12-22 14:56:40 +00:00
Matthias Radestock 593e3d3593 Merge remote-tracking branch 'upstream/1.4' 2015-12-22 14:02:15 +00:00
Matthias Radestock 2ed4b45c24 Merge pull request #1817 from weaveworks/1815-docker-version
Check we have Docker 1.9 or newer before trying to remove a network

Fixes #1815.
2015-12-22 14:01:55 +00:00
Matthias Radestock 716f50c4e4 Merge remote-tracking branch 'upstream/1.4' 2015-12-22 13:50:10 +00:00
Matthias Radestock 47ba9748b4 Merge pull request #1814 from weaveworks/1778-check-running
Handle weave containers in 'restarting' state

Fixes #1778.
2015-12-22 13:49:19 +00:00
Bryan Boreham 077ad4208f Merge pull request #1813 from weaveworks/1797-plugin-version
Show plugin version; Fixes #1797
2015-12-22 13:12:38 +00:00
Bryan Boreham c19edec364 Add 'weave stop-xxx' instructions for 'already running' case 2015-12-22 13:04:06 +00:00
Bryan Boreham 0c2aa494ae Reduce duplication 2015-12-22 13:03:04 +00:00
Bryan Boreham 73e0a6bb0a Inform user about weave containers in state 'restarting' 2015-12-22 13:01:00 +00:00
Bryan Boreham abf1db0045 Merge pull request #1819 from weaveworks/1818-dont-launch-when-plugin-running
don't launch anything when plugin is running; fixes #1818 . LGTM.
2015-12-22 12:55:57 +00:00
Matthias Radestock 2f94d727ea Merge remote-tracking branch 'upstream/1.4' 2015-12-22 12:49:00 +00:00
Matthias Radestock b40b78ece0 refactor docker_sock_volume_mount() 2015-12-22 12:47:36 +00:00
Matthias Radestock 3ade796e8d don't launch anything when plugin is running
...just as we don't launch anything if either the router or proxy are
running.

Fixes #1818.
2015-12-22 12:30:53 +00:00
Bryan Boreham 7c2e808924 Check we have Docker 1.9 or newer before trying to remove a network 2015-12-22 12:10:48 +00:00
Bryan Boreham 7d2227c5a4 Add plugin version to 'weave version' 2015-12-22 10:50:02 +00:00
Bryan Boreham 8a517d5c7c Issue a warning on --with-dns option to proxy, because it was removed 2015-12-22 10:00:06 +00:00
Matthias Radestock cb6176fd8a tweak ProtocolSender API
make SendProtocolMsg return an error; this isn't used at any call
sites (yet) but is TRTTD.
2015-12-21 18:24:22 +00:00
Matthias Radestock b93ce1cea5 refactor: no need for GossipSender.sent 2015-12-21 18:09:50 +00:00
Matthias Radestock 3be28523c9 cosmetic 2015-12-21 17:56:38 +00:00
Matthias Radestock 592335092c refactor: tweak GossipChannel API 2015-12-21 17:42:20 +00:00
Matthias Radestock 6c4e9fccd3 cosmetic 2015-12-21 17:28:22 +00:00
Matthias Radestock 6903b8d458 refactoring for consistency 2015-12-21 17:18:12 +00:00
Matthias Radestock 274265f001 typo 2015-12-21 17:03:03 +00:00
Bryan Boreham ceac3c3d83 Merge branch '1.4' 2015-12-18 09:54:22 +00:00
Bryan Boreham 48658f011f Merge pull request #1805 from weaveworks/script-indentation
Fix indentation of weave script
2015-12-18 09:53:12 +00:00
Bryan Boreham 4ebb13fa94 Fix indentation of netcheck if-statement 2015-12-17 16:23:42 +00:00
Bryan Boreham 5580b7a522 Add more steps to the process 2015-12-17 13:55:26 +00:00
Adam Harrison bda8cff7c1 Merge branch '1.4' 2015-12-17 13:09:20 +00:00
Adam Harrison ff9a6b91a4 Merge branch 'latest_release_doc_updates' into 1.4 2015-12-17 13:07:48 +00:00
Adam Harrison 86fc37a968 Merge pull request #1799 from weaveworks/plugin-docs
Extend plugin docs
2015-12-17 12:24:12 +00:00
Bryan Boreham 37ae169323 Merge remote-tracking branch 'origin/master' into latest_release_doc_updates 2015-12-17 11:48:23 +00:00
Bryan Boreham 1ce0df4e94 Explain multiple networks 2015-12-17 11:42:41 +00:00
Bryan Boreham db5ba61915 Improve formatting 2015-12-17 11:41:44 +00:00
Bryan Boreham 31006002f3 Add the plugin to the list of images to tag and push 2015-12-17 11:08:00 +00:00
Bryan Boreham db120fb9be Add release v1.4.0 2015-12-17 10:30:06 +00:00
Adam Harrison ea6e171a7f Merge pull request #1794 from weaveworks/warn-stop-plugin
Warn user if weave network is in use on stop or reset of plugin
2015-12-17 10:27:58 +00:00
Bryan Boreham 246cb76e50 Add note to docs about not removing the plugin 2015-12-17 10:26:08 +00:00
Bryan Boreham ecf4a82b99 Warn user if weave network is in use on stop or reset 2015-12-17 10:05:36 +00:00
Bryan Boreham 357f67255e Move logging of Docker API info to callers 2015-12-17 08:25:51 +00:00
Adam Harrison 7015ab8717 Merge pull request #1780 from weaveworks/1748-no-with-dns
Remove WITH_DNS variable from weave script
2015-12-16 15:59:24 +00:00
Bryan Boreham 67195bc9f3 Remove WITH_DNS variable and deprecate --with-dns option to 'weave run' 2015-12-16 14:55:35 +00:00
Adam Harrison ce18509aa7 Merge pull request #1781 from weaveworks/1754-no-with-dns
Remove --with-dns option from proxy
2015-12-16 14:02:30 +00:00
Bryan Boreham cbaa92dcb2 Revert "don't broadcast-gossip other peer when adding a connection"
while we consider how to fix it properly.

This reverts commit cbb2ad018d.
2015-12-16 13:46:37 +00:00
Bryan Boreham f09d87c112 Merge pull request #1796 from weaveworks/gossip-test-connection-mistake
fix gossip test connection peer initialisation and connection deletion mistakes
2015-12-16 13:36:50 +00:00
Adam Harrison 7a8bba4d95 Merge pull request #1776 from weaveworks/1752-plugin-multicast
Plugin optional multicast route
2015-12-16 13:28:03 +00:00
Bryan Boreham e6e414a017 Merge pull request #1795 from weaveworks/issues/1772-fix-fastdp-address-already-in-use
Introduce limited retry on vxlan vport creation. LGTM; fixes #1772.
2015-12-16 13:22:50 +00:00
Matthias Radestock 81df06b3f4 fix DeleteTestGossipConnection
This is a one-sided operation, so we shouldn't be touching the
remote's Peers.

Also fix the associated test... When both 1 and 2 have lost their
connection to 3, they no longer have a route to 3 and hence gc it.

And because they no longer have a route, gossip from them won't get
through to 3.
2015-12-16 13:18:05 +00:00
Matthias Radestock 5401037743 refactor: inline mockGossipConnection.Connect
Also change Start() order in AddTestGossipConnection to be more
pleasing to the eye; the order isn't actually important.
2015-12-16 12:45:12 +00:00
Matthias Radestock 9d9768ee6f fix incorrect peer initialisation on test gossip connections
We were creating peers with NewPeerFrom, which copies the Version (but
not connections). That's not what happens for a real connection, where
remote peers are always created with an initial version of 0.

The mistake results in brokenness: when we subsequently receive a
topology update for that peer with the same version then we ignore it,
even though the update contains connection information which is new to
us.

Related, it is conceptually wrong to call FetchWithDefault on the
remote router. That is not what happens for a real connection - the
FetchWithDefault occurs in the symmetric counterpart.
2015-12-16 12:33:07 +00:00
Bryan Boreham 3043217b2c Extend --no-multicast-route test to plugin 2015-12-16 12:17:25 +00:00
Bryan Boreham afcb84d42c Set up static route for multicast, with option to turn off 2015-12-16 12:17:25 +00:00
Adam Harrison d5aad8f8d2 Introduce limited retry on vxlan vport creation
The kernel processes vport deletion asynchronously, meaning that we can
sometimes fail to recreate vxlan vports on startup with an EADDRINUSE
error. We compensate by retrying a small number of times with a short
sleep on encountering this error, failing as before on a different error
or exhaustion of retries.
2015-12-16 11:51:28 +00:00
Bryan Boreham c46febd7df Fix Makefile so weavewait* are statically linked
- the `-tags netgo` was being ignored by an interaction with the newer tags
2015-12-16 11:45:10 +00:00
Bryan Boreham f880da4827 Merge pull request #1722 from weaveworks/fdp-high-level-overview
Add fast datapath high level overview
2015-12-16 10:49:31 +00:00
Bryan Boreham 85c9cf43f7 Merge pull request #1689 from weaveworks/1586-alternate-docker-sock
Support weave script running against non-standard DOCKER_HOST.
2015-12-16 10:35:46 +00:00
Adam Harrison ce90d2389b Merge pull request #1790 from weaveworks/1783-veth-name
Prefix interface names with 'veth' so NetworkManager ignores them
2015-12-16 10:34:32 +00:00
Bryan Boreham d8cfbc4e08 Launch the proxy via unix socket in last test
- proxy copies permissions from $DOCKER_HOST socket if available, so in
   this case it was not accessible because we were booting via a TCP
   socket
2015-12-16 10:14:44 +00:00
Paul Bellamy 88fad251aa add test for proxy against docker on non-standard unix socket
Means we need to rebuild the gce images

(also small improvement re tmpdir)
2015-12-16 10:14:15 +00:00
Bryan Boreham 1a1d8b7c74 Prefix interface names with 'veth' so NetworkManager ignores them 2015-12-16 10:01:57 +00:00
Paul Bellamy a4ef96690e support alternate DOCKER_HOST settings when launching the plugin 2015-12-15 18:12:31 +00:00
Paul Bellamy f28ad350bd make weave and the proxy work with tcp-only dockers via DOCKER_HOST 2015-12-15 18:02:59 +00:00
Paul Bellamy 0afc3db383 First pass at passing DOCKER_HOST=unix://* through to the weave and proxy 2015-12-15 18:02:27 +00:00
Paul Bellamy ca1cce3232 Makefile should use DOCKER_HOST env var 2015-12-15 18:02:27 +00:00
Adam Harrison f9228eeb46 Merge pull request #1738 from weaveworks/1727-local-plugin
"mesh mode" plugin
2015-12-15 17:53:26 +00:00
Adam Harrison 0c077b8bb1 Merge pull request #1782 from weaveworks/1709-json-func
Add a 'json' function for 'weave report -f'
2015-12-15 17:09:02 +00:00
Bryan Boreham 0e9991f7d4 Make plugin create 'weave' network by default 2015-12-15 16:52:37 +00:00
Bryan Boreham 41482aff01 Update plugin README and documentation 2015-12-15 16:52:37 +00:00
Bryan Boreham 791fc9d6b1 Return fake 'gateway address' to avoid requiring consensus during initialization 2015-12-15 16:52:37 +00:00
Bryan Boreham 776ccac00a Pin docker API version to 1.21 2015-12-15 16:52:30 +00:00
Bryan Boreham 1539009362 Simple smoke-test for 'local' plugin network 2015-12-15 16:47:33 +00:00
Bryan Boreham 9542b77a34 Extend smoke-test framework for weaveplugin 2015-12-15 16:47:33 +00:00
Bryan Boreham b709cdeab5 Create local and global network from the same driver and create local-scope weave network by default on weave launch 2015-12-15 16:47:18 +00:00
Bryan Boreham e2f936fde3 Rework version check
- extract function so we can use the check elsewhere
- use shell variable expansion rather than exec-ing 'cut'
2015-12-15 16:40:43 +00:00
Bryan Boreham a4ca389f2e Make the plugin scope (local or global) an option 2015-12-15 16:31:07 +00:00
Bryan Boreham c973808b20 Merge pull request #1758 from weaveworks/issues/82-optional-encryption
Make encryption optional; fixes #82, #1788. LGTM.
2015-12-15 15:23:58 +00:00
Adam Harrison e12dbb4605 Disable pcap optimisation of encrypted sleeve
Prior to optional encryption support, enabling encryption disabled the
fast datapath overlay (because it doesn't support encryption) but left
the OVS datapath netdev in place for bridging (so that users could
switch encryption on and off without resetting the bridge). In this
situation the ODP miss handler is guaranteed to be invoked for every
packet, so as an optimisation the weave script configured the router to
use pcap to capture packets from the bridge as that is slightly more
efficient. The introduction of optional encryption means the guarantee
no longer holds, and so the optimisation must be removed.
2015-12-15 14:51:21 +00:00
Bryan Boreham c341399498 Document 'json' function 2015-12-15 13:52:28 +00:00
Bryan Boreham d1ba4ab7f4 Merge pull request #1755 from weaveworks/issues/1741-weave-no-multicast-route
Add options to disable multicast route - LGTM; fixes #1741
2015-12-15 10:17:09 +00:00
Adam Harrison 85d4b1f137 Smoke test trusted subnets 2015-12-14 12:13:16 +00:00
Adam Harrison b9792f8f96 Document trusted subnets
Update features and troubleshooting markdown.
2015-12-14 12:13:16 +00:00
Adam Harrison e0cb9cf24d Restore leading whitespace to weave status 2015-12-14 12:13:16 +00:00
Adam Harrison 4e41d4d451 Add trusted subnets to weave status
`weave status` now displays the list of specified trusted subnets, and
`weave staus connections` shows the encryption state of individual
connections.
2015-12-14 12:13:16 +00:00
Adam Harrison 059cc65b55 Fallback to encrypted sleeve on a per-connection basis
If overlay encryption is required between peers, the fast datapath
forwarder returns an error rather than aborting the process, allowing
the overlay switch to fall back gracefully to an encrypted sleeve
overlay connection.
2015-12-14 12:13:11 +00:00
Adam Harrison d434b50dfc Include trust level in features exchange
Add a 'Trusted' feature to the protocol exchange which indicates whether
the remote considers us to be reachable via a secure network; overlay
encryption will be disabled in the event that both peers agree. For
backwards compatibility purposes a default value of untrusted is assumed
if the feature is missing.
2015-12-14 12:12:25 +00:00
Adam Harrison 96f69583e7 Smoke test --no-multicast-route 2015-12-14 11:53:06 +00:00
Adam Harrison ce25f58639 weave launch-proxy accepts --no-multicast-route 2015-12-14 11:53:06 +00:00
Adam Harrison 367b73e6e3 Introduce nomcast weavewait 2015-12-14 11:53:06 +00:00
Adam Harrison 98a7d3fc99 weave run and weave attach accept --no-multicast-route 2015-12-14 11:53:06 +00:00
Bryan Boreham 6fd0f121a0 Add a 'json' function for 'weave report -f' 2015-12-12 14:44:54 +00:00
Bryan Boreham 68d6c262d1 Remove --with-dns option from proxy 2015-12-12 14:12:39 +00:00
Bryan Boreham 1d9ef76080 Remove mention of --with-dns option; see #1748 and #1754 2015-12-12 13:58:14 +00:00
Bryan Boreham b51b1adfcd Merge pull request #1767 from weaveworks/1765-test-gossip-surrogate-failure
better emulation of connections in gossip tests. Fixes #1765.
2015-12-11 17:20:23 +00:00
Matthias Radestock b1cb0c298d refactor 2015-12-10 14:37:30 +00:00
Matthias Radestock d7835eabfb lazy route calculation
Instead of calculating all routes in one go, we calculate them when
needed.

Except for unicast routes, and broadcast routes from ourself. We still
calculate those eagerly because they are needed to route locally
captured/fdp-missed packets, and performing route calculcations in
that critical path increases the chances of dropping packets due to
not keeping up.

Well, technically only the established & symmetric routes are needed
for the data plane, but we might as well calculate the equivalent
routes for the control plane - it keeps the code simple and uniform.

Calculating all routes is O(n_peers^2), so this change represents a
huge saving in situations where not all of them are needed, which is
quite common, especially when the topology is evolving rapidly.

One downside of this new approach is that we can no longer suppress
OnChange callbacks when the data plane routes remain unchanged. This
means we will be purging the FDP flows more frequently than before,
e.g. when only the control plane topology changed, e.g. new
connections appeared that haven't been marked as 'established'
yet. It's a small price to pay, fixable if we really care, and in any
case making FDP flow invalidation more fine-grained would be a better
approach.

Fixes #1761.
2015-12-10 14:20:59 +00:00
Matthias Radestock ab902b45aa refactor: introduce a helper to reduce duplication 2015-12-10 10:56:18 +00:00
Matthias Radestock ed14561afd refactor: rename 2015-12-10 10:54:20 +00:00
Matthias Radestock 86d2db5cc2 better emulation of connections in gossip tests
real Connections do not process gossip until after AddConnection.
mockChannelConnection wasn't behaving in that way, which resulted in
some sporadic test failures since it would cause some gossip to get
processed too early, which in turn would trigger gc of some of the
just-received peers, which we would then find missing in the test
assertions.

To fix this we introduce a latch on mockChannelConnection which closes
when the remote end is ready to receive gossip. Effectively this
emulates the entering of LocalConnection.receiveTCP after the call to
AddConnection completes.

Unfortunately an open latch will cause sendPendingGossip to block. We
get around that by abandoning checks in "half-connected" connection
states.

Fixes #1765.
2015-12-10 10:54:10 +00:00
Bryan Boreham 700851cdd5 Add a note about connecting up peers 2015-12-10 10:40:48 +00:00
Adam Harrison c3e1f5a6c6 .gitignore tls binary 2015-12-10 10:08:04 +00:00
Bryan Boreham 9bf18b1761 Merge pull request #1769 from weaveworks/ditch-run-with-timeout
Wins the prize for "best add-to-delete ratio in a PR this year"
2015-12-09 13:56:54 +00:00
Matthias Radestock 1374e4c4de ditch RunWithTimeout test helper
It breaks stack traces on failure.

We can just rely on running `go test -timeout ...` instead, which we
already do in tools/test.
2015-12-09 13:20:57 +00:00
Matthias Radestock 0ef57a102f cosmetic: remove unnecessary comment 2015-12-09 12:37:53 +00:00
Adam Harrison 1c7954a43d Merge pull request #1728 from weaveworks/1676-ipam-plugin
Docker IPAM plugin
2015-12-09 11:07:46 +00:00
Matthias Radestock be1dc8ef96 Merge branch '1.3' 2015-12-09 10:34:52 +00:00
Matthias Radestock 18fc6ccc03 remove redundant code in test 2015-12-09 10:32:14 +00:00
Matthias Radestock 7ec46983aa Merge branch '1.3' 2015-12-08 23:08:35 +00:00
Matthias Radestock eddcf93942 oops 2015-12-08 23:08:19 +00:00
Matthias Radestock 42807f7b8a Merge branch '1.3' 2015-12-08 23:07:06 +00:00
Matthias Radestock 0b521272ae prevent peer duplication in tests
and correct the test assertions accordingly - they make more sense
now.

Fixes #1766.
2015-12-08 23:06:02 +00:00
Bryan Boreham ecd93bbfe4 Resolve weave IP every time we need it, in case it changed 2015-12-08 16:59:34 +00:00
Bryan Boreham a6f07fbaac Move baseUrl usage up to httpVerb 2015-12-08 16:59:34 +00:00
Bryan Boreham f87876c1c3 Fetch the default subnet from weave to use as the ipam driver 'pool' 2015-12-08 16:59:34 +00:00
Bryan Boreham ec3de1a072 Introduce ipam plugin 2015-12-08 16:59:32 +00:00
Bryan Boreham c1d2c159f0 Expand listener skeleton to support IPAM driver 2015-12-08 16:58:55 +00:00
Bryan Boreham 9f86e2ba43 Moved net plugin to its own directory 2015-12-08 16:58:53 +00:00
Adam Harrison d0be36dc9b Merge branch '1.3'
Conflicts:
	Makefile
2015-12-08 16:53:47 +00:00
Adam Harrison af604a1477 Merge pull request #1760 from weaveworks/make-test-tls
Move test/tls program into Makefile so it builds inside the build container
2015-12-08 16:41:59 +00:00
Bryan Boreham c981cff450 Move build of test/tls program into Makefile so it builds in the build container 2015-12-08 16:14:53 +00:00
Bryan Boreham ab1033c26c Merge pull request #1736 from weaveworks/remove-unknown-peer-error
remove UnknownPeerError for quicker convergence and efficiency. LGTM.
2015-12-04 11:00:05 +00:00
Adam Harrison 01706df7c8 Merge pull request #1753 from weaveworks/1751-remove-unused-vars
remove CLIENT_TLS_ENABLED and DOCKER_CLIENT_TLS_VERIFY, as they're unused
2015-12-04 10:19:09 +00:00
Adam Harrison 827a7c1cf1 Merge branch '1.3' 2015-12-04 10:09:15 +00:00
Adam Harrison d14d9933b4 Merge pull request #1750 from weaveworks/add-some-quotes
quote $@
2015-12-04 10:08:34 +00:00
Adam Harrison af946893f0 Merge pull request #1749 from weaveworks/remove-eqeq-non-posixism
'==' is not POSIX
2015-12-04 10:08:26 +00:00
Paul Bellamy 245ae5e987 remove CLIENT_TLS_ENABLED and DOCKER_CLIENT_TLS_VERIFY, as they're unused 2015-12-02 17:17:04 +00:00
Matthias Radestock 29f3d711c6 Merge branch '1.3' 2015-12-02 15:34:07 +00:00
Matthias Radestock 3909936cc8 cosmetic(ish) use PROXY_PORT 2015-12-02 15:33:38 +00:00
Matthias Radestock 0602c91c54 quote $@ 2015-12-02 15:28:41 +00:00
Matthias Radestock a7bdb02a2b Merge remote-tracking branch 'upstream/master' 2015-12-02 14:33:28 +00:00
Matthias Radestock 2cfaf5a119 Merge branch '1.3' 2015-12-02 14:23:28 +00:00
Matthias Radestock 20a48f05b3 fix (harmless) typo 2015-12-02 14:22:23 +00:00
Matthias Radestock 4e70fb7f9d '==' is not POSIX 2015-12-02 14:20:29 +00:00
Adam Harrison 1f438dbf71 Merge pull request #1740 from weaveworks/1694-symlink-into-var-run-2
Symlink sockets to /var/run/weave/weave.sock from inside the proxy
2015-12-02 14:12:02 +00:00
Adam Harrison 619d0e2bdd Merge pull request #1730 from weaveworks/1725-plugin-dns
Fix DNS integration in Weave docker plugin
2015-12-02 09:49:21 +00:00
Bryan Boreham ec420c66d4 Review feedback 2015-12-01 16:47:47 +00:00
Paul Bellamy ac1cf633c7 clarify some variable shadowing 2015-12-01 16:16:39 +00:00
Paul Bellamy 6f25d2170d [proxy] have symlinking respond to WEAVE_DEBUG not DEBUG 2015-12-01 15:51:16 +00:00
Paul Bellamy 295a2ced32 [proxy] treat addrs prefix with / as unix addrs 2015-12-01 15:45:32 +00:00
Matthias Radestock cbb2ad018d don't broadcast-gossip other peer when adding a connection
This is more efficient since broadcasting about other peers is
strictly redundant. Any change to the peers will be broadcast by
those peers anyway. And SendAllGossipDown takes care of informing new
peers about others on first connect, and periodic gossip take care of
missed broadcasts.

The only reason we did broadcast about the remote peer is to reduce
the liklihood of UnknownPeerError and the associated throwing away of
gossip. This was always a bit of kludge, and is no longer necessary
since UnknownPeerError is gone.

Now peers only ever broadcast information about themselves. Which,
unlike information about other peers, is always authorative and most
up-to-date. Which is nice.
2015-12-01 13:10:06 +00:00
Matthias Radestock 7e15eabe65 remove UnknownPeerError
when encountering an unknown peer in received gossip, rather than
ignoring the entire gossip we create a placeholder Peer. This has
version 0 and uid 0, which means it will be replaced by any complete
peer information subsequently received via gossip.
2015-11-30 16:17:16 +00:00
Bryan Boreham eb9b5b535f Merge branch '1.3' 2015-11-30 16:16:09 +00:00
Bryan Boreham a13351a9eb Merge pull request #1712 from weaveworks/issues/1577-interpose-bridge-netdev
Optional intermediary bridge netdev. Fixes #1577.
2015-11-30 15:54:14 +00:00
Bryan Boreham 74fdf6beec Merge pull request #1732 from weaveworks/1731-merge-peer-has-short-id
update Peer.HasShortID as part of topology merge
Fixes #1731
2015-11-30 15:53:23 +00:00
Paul Bellamy cd7c88e5a5 [proxy] Symlink sockets to /var/run/weave/weave.sock from inside the proxy
We copy docker.sock owner to symlinks. Permissions are not copied,
because the permissions will inherit from the target.

use versioned exec image to create symlinks
2015-11-30 15:45:30 +00:00
Bryan Boreham a22b88ed89 Track endpoints so we can register the right address with DNS 2015-11-30 14:27:33 +00:00
Bryan Boreham 5eb99fe5ef Get container IP for various networks 2015-11-30 14:27:33 +00:00
Bryan Boreham 85e465cfa4 Eliminate 'dockerer' 2015-11-30 14:27:33 +00:00
Bryan Boreham e101dde62e Extract 'api' package 2015-11-30 14:27:33 +00:00
Adam Harrison 1980ffea30 Merge pull request #1702 from weaveworks/issues/1639-ipam-diagnostics
Show some IPAM stats with `weave status ipam`
2015-11-30 14:20:13 +00:00
Adam Harrison 0935e0a13d Merge branch '1.3' 2015-11-30 14:09:44 +00:00
Adam Harrison b2b68119fc Merge pull request #1719 from weaveworks/issues/1653-make-dir
Ensure /var/run/weave directory exists before telling Docker to use it
2015-11-30 13:57:37 +00:00
Adam Harrison 4420057d4f Merge pull request #1716 from weaveworks/issues/1714-complete-addr-1.3
Ensure `weave connect` attempts connection immediately
2015-11-30 13:52:13 +00:00
Bryan Boreham bd2b8df7c5 Refactor to use Weave's docker client and watcher 2015-11-30 13:25:20 +00:00
Matthias Radestock 068bbe0837 Merge branch '1.3' 2015-11-30 13:19:21 +00:00
Bryan Boreham 7e0e1fbaad Adjust formatting after review feedback; hostnames up to 14 chars will now align 2015-11-30 12:07:59 +00:00
Bryan Boreham 9723476392 Merge pull request #1708 from weaveworks/gce-connect-fix
Connect to gce boxes as vagrant so we can access docker unix socket
2015-11-30 11:45:30 +00:00
Matthias Radestock 9dee2f2230 update Peer.HasShortID as part of topology merge
This was missing.

There are two parts to this change:

1. updating the Peers.byName mapping when HasShortID changed (in
addition to the existing update on ShortID change). We need to be
careful about the sequencing here - both ShortID and HasShortID must
be set between the calls to deleteByShortID and addByShortID, since
the former is meant to delete the existing entry (hence use the old
values) and the latter add the new entry (hence use the new values).

2. update a peer when the received info has the same version and UID
but the current record has HasShortID=false, and the received info has
HasShortID=true. This caters for the case where we receive an update
about a weave 1.2+ peer first via a pre-1.2 peer (which does not
transmit ShortIDs, and always sets HasShortID=false) and subsequently
via a 1.2+ peer. The former update will force us to communicate with
that peer over the 'sleeve' overlay. We want to accept the latter
update, even though the version is the same, in order to update the
ShortID and HasShortID, so we can switch to fastdp.

Fixes #1731.
2015-11-29 16:32:50 +00:00
Matthias Radestock 175f38414e cosmetic 2015-11-28 20:15:57 +00:00
Bryan Boreham 8bbf8231d2 Show which range is being allocated in weave report 2015-11-26 17:24:41 +00:00
Bryan Boreham 2fbbb802bd Don't assert invariants when printing status
- if it's broken you might appreciate being able to print it out
2015-11-26 17:24:41 +00:00
Bryan Boreham cb65a80dce Reworded IPAM service description in weave status
following review in #1702
2015-11-26 17:24:41 +00:00
Bryan Boreham 3a9bcbcf6b Remove specialised knowledge of IPAM from weave status formatter
and unnecessary info from `weave report` output
2015-11-26 17:24:40 +00:00
Bryan Boreham e38018ab1e Add warning to main ipam status if all IPs owned by unreachable peers 2015-11-26 17:23:49 +00:00
Bryan Boreham 044c6474b2 Remove counting of ring tokens, since it isn't useful to end-user.
Previously the count of tokens was claimed to be a count of addresses in use,
which is incorrect.
Also rename `appendAddresses` to `appendOwned` since it doesn't involve addresses.
2015-11-26 17:23:49 +00:00
Bryan Boreham 5f42a4d95e Hold stats by peer identity not nickname
so we can print the peer name for each ownership.
Also avoid crashing if we don't own anything
2015-11-26 17:23:49 +00:00
Bryan Boreham 6d3fd6da07 Simplify ipam status format
Don't use the word "universe" in user-visible output; it is an internal term.
Removed everything but owned ranges from 'weave status ipam' results, for consistency with similar functions
2015-11-26 17:23:49 +00:00
Alvaro Saurin 34e7996f2f Show some IPAM status at /status/ipam 2015-11-26 17:23:47 +00:00
Bryan Boreham f2d7a28258 Add docker plugin README 2015-11-26 17:18:59 +00:00
Adam Harrison ba6f8da1e4 Merge pull request #1670 from weaveworks/issues/1634-block-6783-6784
Forbid traffic to the Weave port from containers
2015-11-26 16:52:34 +00:00
Adam Harrison 0a5e79891d Merge pull request #1724 from weaveworks/1674-move-plugin
Move Weave docker plugin into this repo
2015-11-26 15:34:15 +00:00
Bryan Boreham 901bf63cb8 Fix printf error caught by lint 2015-11-26 15:19:57 +00:00
Bryan Boreham 350b8efb0b Move Weave docker plugin into this repo 2015-11-26 14:40:28 +00:00
Adam Harrison 2f69b4d190 Mention WEAVE_MTU 2015-11-26 10:39:41 +00:00
Adam Harrison 57a15a4e96 Add fast datapath high level overview 2015-11-26 10:36:52 +00:00
Adam Harrison 13042002d7 Merge pull request #1663 from weaveworks/issues/1592-fdp-miss-counter
Add FDP miss counter to reports
2015-11-25 17:21:03 +00:00
Adam Harrison 8ac745b4e5 Lock read of miss counter 2015-11-25 17:05:19 +00:00
Adam Harrison 8a4f038ec4 Merge pull request #1662 from weaveworks/issues/1571-upstream-dns-report
DNS upstream servers report
2015-11-25 16:47:14 +00:00
Adam Harrison 890522f6f4 Add hidden weave bridge-type command 2015-11-25 16:31:32 +00:00
Adam Harrison c8aa032051 Eliminate function name stutter 2015-11-25 16:31:32 +00:00
Adam Harrison 9830c146d0 The bridge netdev is always named weave 2015-11-25 16:31:32 +00:00
Adam Harrison 00c9164fdb Pass WEAVE_NO_BRIDGED_FASTDP to remote for testing 2015-11-25 16:31:32 +00:00
Adam Harrison a31e7118b4 Optional intermediary bridge netdev 2015-11-25 16:31:32 +00:00
Matthias Radestock 2058ce3f3a refactor: change Routes.RandomNeighbours return for consistency
PeerNameSet -> []PeerName, which is what the other functions
return. This is also easier to deal with at the call site.
2015-11-25 14:46:41 +00:00
Matthias Radestock 61e3bf4a20 cosmetic(ish) 2015-11-25 14:32:34 +00:00
Bryan Boreham ea5bae711b Ensure /var/run/weave directory exists before telling Docker to use it 2015-11-25 13:56:09 +00:00
Bryan Boreham 44a2c5fdff Merge pull request #1718 from weaveworks/constant-spacetime-connection-shutdown
LGTM. prevent unbounded number of goroutines for connection shutdown
2015-11-25 11:22:08 +00:00
Matthias Radestock 3b43960779 prevent unbounded number of goroutines for connection shutdown
We need Connection.Shutdown to be non-blocked, and the way we achieved
this is by spawning a goroutine. However, there can be a potentially
unbounded number of Connection.Shutdown invocations. For example, if
the TCP connection has gone bad then any Connection.SendProtocolMsg
invocation will end up invoking Connection.Shutdown. There can be many
such invocations until the Connection has been removed from the
various data structures (e.g. LocalPeer.connections and
GossipSender.senders). Hence we can end up with with an unbounded
number of spawned goroutines.

To fix this, we introduce a one-element error channel on the
connection. Connection.Shutdown does a non-blocking send on that, and
the Connection.actorLoop reads from it and terminates.

This will throw away all but the first error encountered, but that is
fine and not much different from what was happening before (where we'd
throw away all but one of the errors encountered).
2015-11-25 11:06:20 +00:00
Bryan Boreham 89f27ec99a Set default port number on address before checking in InitiateConnections, to fix #1714 2015-11-24 14:55:21 +00:00
Adam Harrison 82cf4358ce Add release v1.3.1 2015-11-23 12:06:10 +00:00
Paul Bellamy 0f9b117744 Connect to gce boxes as vagrant so we can access docker unix socket 2015-11-20 16:54:41 +00:00
Adam Harrison c420c21219 Merge pull request #1707 from weaveworks/revert-1696-1694-symlink-into-var-run
Revert "Automatically symlink /var/run/*.sock sockets to /var/run/weave/*.sock"
2015-11-20 16:27:04 +00:00
Paul Bellamy 3bae4b0d93 Revert "Automatically symlink /var/run/*.sock sockets to /var/run/weave/*.sock" 2015-11-20 16:23:40 +00:00
Adam Harrison 1432bd7a81 Merge pull request #1696 from weaveworks/1694-symlink-into-var-run
Automatically symlink /var/run/*.sock sockets to /var/run/weave/*.sock
2015-11-20 16:23:12 +00:00
Adam Harrison bdcf930e25 Merge branch '1.3' 2015-11-20 11:08:49 +00:00
Adam Harrison 2e42d74c59 Merge pull request #1706 from weaveworks/1683-update-docker-1.3
Raise minimum Docker version to 1.6
2015-11-20 11:06:00 +00:00
Bryan Boreham bbf26fc3e8 Raise minimum Docker version to 1.6 to address #1683 2015-11-20 10:44:45 +00:00
Bryan Boreham 6dcc42cdeb Merge branch '1.3' 2015-11-20 10:33:38 +00:00
Bryan Boreham 385b0aa07f Fix typo in -tls info string 2015-11-20 10:33:20 +00:00
Bryan Boreham f2b1ee3398 Merge branch 'latest_release_doc_updates' into 1.3 2015-11-20 10:30:28 +00:00
Bryan Boreham 2a2c60201f Merge pull request #1699 from weaveworks/issues/1693-fix-proxy-docs-tls-args
Fix erroneously hyphenated Docker TLS arguments; Fixes #1693.
LGTM
2015-11-20 10:27:34 +00:00
Matthias Radestock 53749156a7 Merge branch '1.3' 2015-11-19 20:58:14 +00:00
Matthias Radestock ee12b34334 eliminate a gossip inefficiency and dormant bug
Fixes #1704
2015-11-19 20:57:27 +00:00
Matthias Radestock b5a4aefe8b never broadcast empty nameserver gossip 2015-11-19 18:28:37 +00:00
Bryan Boreham c2d5cab1b8 Merge remote-tracking branch 'origin/1.3' 2015-11-19 15:30:20 +00:00
Bryan Boreham f25af8f7d6 Merge pull request #1698 from weaveworks/1697-copy-on-write-gossip-data
make GossipData immutable; Fixes #1697. Fixes #1450. Fixes #1452.
2015-11-19 14:58:32 +00:00
Paul Bellamy 33648b083c SSH into test vms on gce as 'vagrant' user 2015-11-19 14:10:52 +00:00
Alvaro Saurin eb79711e0a Added flow misses count 2015-11-19 15:05:16 +01:00
Alvaro Saurin 03ce6052cc Updated docs 2015-11-19 14:54:37 +01:00
Alvaro Saurin 7992bf4177 DNS upstream servers report 2015-11-19 14:54:23 +01:00
Alvaro Saurin ddb390d5ec Forbid traffic to the Weave port from other containers
Make sure we have the Docker bridge IP before adding/removing iptables rules
2015-11-19 14:46:28 +01:00
Matthias Radestock 1500b1dc00 refactor: extract nameserver GossipData.copy
and remove a self-evident comment
2015-11-18 11:30:40 +00:00
Adam Harrison 9263d3e82c Fix erroneously hyphenated Docker TLS arguments 2015-11-18 10:24:46 +00:00
Adam Harrison 02b7fd53ed Merge tag 'v1.3.0' into latest_release_doc_updates
Resetting doc update branch for 1.3.0 release.
2015-11-18 10:14:10 +00:00
Matthias Radestock 3cd199e852 make GossipData immutable
The same piece of GossipData can be shared and subject to different
Merge operations. We either need to copy the data when we share it, or
create copies on modification, i.e. copy-on-write.

We choose the latter, since it is more efficient and there is just one
mutating operation.

Fixes #1697.
2015-11-17 20:13:46 +00:00
Paul Bellamy 77bc22baf5 [proxy] Auto-symlink /var/run/*.sock in from /var/run/weave/*.sock
Avoids the obscure warning for users
2015-11-17 17:25:21 +00:00
Paul Bellamy f57988761c Revert "Revert "Merge pull request #1580 from weaveworks/1579-launch-proxy-mount-h""
This reverts commit 7987d09438.
2015-11-17 17:15:28 +00:00
Adam Harrison 7987d09438 Revert "Merge pull request #1580 from weaveworks/1579-launch-proxy-mount-h"
This reverts commit 262352f8bb, reversing
changes made to 312691376a due to a bug
whereby `weave env` returns a unix domain socket with an incorrect path.

This change will be superceeded by #1694.
2015-11-17 16:28:31 +00:00
Adam Harrison 262352f8bb Merge pull request #1580 from weaveworks/1579-launch-proxy-mount-h
[proxy] dynamically mount -H dirs into the proxy when launching
2015-11-17 14:52:17 +00:00
Paul Bellamy e8c56a8e8e Review Feedback 2015-11-17 14:49:50 +00:00
Matthias Radestock 312691376a Merge remote-tracking branch 'upstream/master' 2015-11-17 13:57:08 +00:00
Matthias Radestock a9611c782b cosmetic: move comment 2015-11-17 13:56:18 +00:00
Adam Harrison bcc70b36fd Merge pull request #1679 from weaveworks/1539-no-detect-tls-flag
[proxy] add --no-detect-tls flag, and proxy always tries to detect TLS.
2015-11-17 13:55:43 +00:00
Matthias Radestock 9ee3b1bfbd add some timestamps to multiweave 2015-11-17 10:28:28 +00:00
Paul Bellamy e80a83b30b adding work around to the proxy /var/run warning 2015-11-17 09:40:34 +00:00
Paul Bellamy d80e72dfcd [proxy] dynamically mount -H dirs into the proxy when launching
This lets you use -H unix://*.sock outside /var/run/weave. Using a
socket directly in /var/run (i.e. /var/run/foo.sock), will reintroduce
the bug with namespaces not being GCed, so that is a warning.
2015-11-17 09:40:34 +00:00
Matthias Radestock d01c26e618 cosmetic: remove outdated comment
The deadlock described for SendProtocolMsg (if it was going via the
actor) cannot occur since all sending of broadcasts and gossip by
LocalPeer is mediated by GossipSenders, the interaction with which is
non-blocking.
2015-11-17 09:27:49 +00:00
Matthias Radestock cab2e11ca9 refactor: simplify per-connection GossipSender gc and creation
by putting it in one place and inlining some helper functions
2015-11-16 23:21:33 +00:00
Matthias Radestock b48994b1b3 cosmetic: move some functions 2015-11-16 23:01:20 +00:00
Matthias Radestock fb48acddb2 cosmetic: update comment 2015-11-16 19:27:31 +00:00
Paul Bellamy 7d627f7af4 Merge pull request #1673 from weaveworks/1440-cleanup
Move some netlink code to upstream library
2015-11-16 14:24:10 +00:00
Paul Bellamy f458491d88 [proxy] add --no-detect-tls flag, and proxy always tries to detect TLS. 2015-11-13 15:27:27 +00:00
Bryan Boreham de802f9d76 Work round docker-py assuming busybox is present (https://github.com/docker/docker-py/issues/852) 2015-11-13 11:44:08 +00:00
Bryan Boreham 804e6ba586 Cope with changes in docker-py structure.
Tests are now in a different directory,
and get sharded by module rather than individually.
2015-11-13 11:08:57 +00:00
Bryan Boreham e230eeb486 Use upstream netlink code 2015-11-12 13:08:56 +00:00
403 changed files with 22654 additions and 15946 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
--ignore-dir=vendor
--ignore-dir=.pkg
+15 -9
View File
@@ -25,6 +25,7 @@ _testmain.go
*.prof
profile.cov
coverage.html
.pkg
# Emacs backup files
*~
@@ -40,25 +41,30 @@ prog/weaveproxy/weaveproxy
prog/sigproxy/sigproxy
prog/weavewait/weavewait
prog/weavewait/weavewait_noop
prog/netcheck/netcheck
prog/docker_tls_args/docker_tls_args
prog/weavewait/weavewait_nomcast
prog/weaveutil/weaveutil
prog/*/Dockerfile.weaveworks
prog/kube-peers/kube-peers
prog/weave-kube/kube-peers
prog/weave-npc/weave-npc
prog/plugin/plugin
testing/cover/cover
testing/runner/runner
releases
.weaver.uptodate
.weavedns.uptodate
.weaveexec.uptodate
weave.tar.gz
.*.uptodate
weave*.tar.gz
prog/weaveexec/weave
prog/weaveexec/weavehosts
prog/weaveexec/weaveproxy
prog/weaveexec/weavewait
prog/weaveexec/weavewait_noop
prog/weaveexec/weavewait_nomcast
prog/weaveexec/sigproxy
prog/weaveexec/netcheck
prog/weaveexec/docker_tls_args
prog/weaveexec/docker*.tgz
prog/weaveexec/weaveutil
prog/weaveexec/docker*
Vagrantfile.local
test/tls/tls
test/tls/*.pem
test/coverage
test/coverage.*
*qemu-*-static
+123
View File
@@ -1,3 +1,126 @@
[submodule "tools"]
path = tools
url = https://github.com/weaveworks/build-tools
[submodule "vendor/github.com/vishvananda/netlink"]
path = vendor/github.com/vishvananda/netlink
url = https://github.com/weaveworks/netlink.git
[submodule "vendor/github.com/gorilla/mux"]
path = vendor/github.com/gorilla/mux
url = https://github.com/gorilla/mux.git
[submodule "vendor/github.com/gorilla/context"]
path = vendor/github.com/gorilla/context
url = https://github.com/gorilla/context.git
[submodule "vendor/github.com/google/gopacket"]
path = vendor/github.com/google/gopacket
url = https://github.com/google/gopacket.git
[submodule "vendor/github.com/weaveworks/go-odp"]
path = vendor/github.com/weaveworks/go-odp
url = https://github.com/weaveworks/go-odp.git
[submodule "vendor/github.com/opencontainers/runc"]
path = vendor/github.com/opencontainers/runc
url = https://github.com/opencontainers/runc.git
[submodule "vendor/github.com/fsouza/go-dockerclient"]
path = vendor/github.com/fsouza/go-dockerclient
url = https://github.com/fsouza/go-dockerclient.git
[submodule "vendor/github.com/docker/libnetwork"]
path = vendor/github.com/docker/libnetwork
url = https://github.com/docker/libnetwork.git
[submodule "vendor/github.com/docker/docker"]
path = vendor/github.com/docker/docker
url = https://github.com/docker/docker.git
[submodule "vendor/github.com/Sirupsen/logrus"]
path = vendor/github.com/Sirupsen/logrus
url = https://github.com/Sirupsen/logrus.git
[submodule "vendor/github.com/andybalholm/go-bit"]
path = vendor/github.com/andybalholm/go-bit
url = https://github.com/andybalholm/go-bit.git
[submodule "vendor/github.com/miekg/dns"]
path = vendor/github.com/miekg/dns
url = https://github.com/miekg/dns.git
[submodule "vendor/github.com/stretchr/testify"]
path = vendor/github.com/stretchr/testify
url = https://github.com/stretchr/testify.git
[submodule "vendor/golang.org/x/crypto"]
path = vendor/golang.org/x/crypto
url = https://github.com/golang/crypto.git
[submodule "vendor/github.com/docker/machine"]
path = vendor/github.com/docker/machine
url = https://github.com/docker/machine.git
[submodule "vendor/github.com/weaveworks/mesh"]
path = vendor/github.com/weaveworks/mesh
url = https://github.com/weaveworks/mesh
[submodule "vendor/github.com/vishvananda/netns"]
path = vendor/github.com/vishvananda/netns
url = https://github.com/vishvananda/netns.git
[submodule "vendor/github.com/boltdb/bolt"]
path = vendor/github.com/boltdb/bolt
url = https://github.com/boltdb/bolt
[submodule "vendor/github.com/weaveworks/go-checkpoint"]
path = vendor/github.com/weaveworks/go-checkpoint
url = https://github.com/weaveworks/go-checkpoint
[submodule "vendor/github.com/hashicorp/go-cleanhttp"]
path = vendor/github.com/hashicorp/go-cleanhttp
url = http://github.com/hashicorp/go-cleanhttp
[submodule "vendor/github.com/appc/cni"]
path = vendor/github.com/appc/cni
url = https://github.com/appc/cni
[submodule "vendor/github.com/coreos/go-iptables"]
path = vendor/github.com/coreos/go-iptables
url = https://github.com/coreos/go-iptables
[submodule "vendor/github.com/pkg/profile"]
path = vendor/github.com/pkg/profile
url = https://github.com/pkg/profile
[submodule "vendor/github.com/j-keck/arping"]
path = vendor/github.com/j-keck/arping
url = https://github.com/j-keck/arping
[submodule "vendor/github.com/aws/aws-sdk-go"]
path = vendor/github.com/aws/aws-sdk-go
url = https://github.com/aws/aws-sdk-go
[submodule "vendor/golang.org/x/sys"]
path = vendor/golang.org/x/sys
url = https://go.googlesource.com/sys
[submodule "vendor/github.com/beorn7/perks"]
path = vendor/github.com/beorn7/perks
url = https://github.com/beorn7/perks
[submodule "vendor/github.com/prometheus/procfs"]
path = vendor/github.com/prometheus/procfs
url = https://github.com/prometheus/procfs
[submodule "vendor/github.com/prometheus/client_golang"]
path = vendor/github.com/prometheus/client_golang
url = https://github.com/prometheus/client_golang
[submodule "vendor/github.com/prometheus/client_model"]
path = vendor/github.com/prometheus/client_model
url = https://github.com/prometheus/client_model
[submodule "vendor/github.com/prometheus/common"]
path = vendor/github.com/prometheus/common
url = https://github.com/prometheus/common
[submodule "vendor/github.com/golang/protobuf"]
path = vendor/github.com/golang/protobuf
url = https://github.com/golang/protobuf
[submodule "vendor/github.com/matttproud/golang_protobuf_extensions"]
path = vendor/github.com/matttproud/golang_protobuf_extensions
url = https://github.com/matttproud/golang_protobuf_extensions
[submodule "vendor/k8s.io/client-go"]
path = vendor/k8s.io/client-go
url = https://github.com/kubernetes/client-go
[submodule "vendor/github.com/pkg/errors"]
path = vendor/github.com/pkg/errors
url = https://github.com/pkg/errors
[submodule "vendor/github.com/spf13/cobra"]
path = vendor/github.com/spf13/cobra
url = https://github.com/spf13/cobra
[submodule "vendor/github.com/spf13/plag"]
path = vendor/github.com/spf13/plag
url = https://github.com/spf13/pflag
[submodule "vendor/github.com/spf13/pflag"]
path = vendor/github.com/spf13/pflag
url = https://github.com/spf13/pflag
[submodule "vendor/github.com/mgutz/ansi"]
path = vendor/github.com/mgutz/ansi
url = https://github.com/mgutz/ansi
[submodule "vendor/github.com/estesp/manifest-tool"]
path = vendor/github.com/estesp/manifest-tool
url = https://github.com/estesp/manifest-tool
[submodule "vendor/github.com/weaveworks/common"]
path = vendor/github.com/weaveworks/common
url = https://github.com/weaveworks/common
+8
View File
@@ -0,0 +1,8 @@
# IMPORTANT: Please only use GLOBs to ignore files and directories.
# Do not lint any bash script in Weave Net, in order to
# avoid breaking the build on make lint:
*.sh
bin/*
prog/weaveexec/symlink
weave
-28
View File
@@ -1,28 +0,0 @@
language: go
sudo: false
go:
- 1.4
env:
- PATH="${PATH}:${HOME}/.local/bin"
addons:
apt:
packages:
- libpcap-dev
install:
- go clean -i net
- go install -tags netgo std
- go get github.com/golang/lint/golint
- pip install --user --upgrade gsutil
- bin/setup-ci-secrets $encrypted_5ba036e89377_key $encrypted_5ba036e89377_iv
- make travis
- go get ./...
script:
- make tests
after_success:
- go get github.com/mattn/goveralls
- test "${TRAVIS_PULL_REQUEST}" = "false" && site/build-and-publish.sh
+340
View File
@@ -1,3 +1,343 @@
## Release 1.9.0
Highlights:
* Encryption is now available for Fast Datapath connections, which
greatly improves the performance. #1644,#2687
* We now build images for Intel/AMD 64-bit, ARM and ARM 64-bit. #2713
* Weave Net Docker images are now labelled with description, vendor, etc. #2712
* `weave status connections` now shows the MTU #2389,#2663
* CNI plugin is now a stand-alone binary that does not depend on Docker #2594,#2662
* Embedded docker client updated to version 1.10.3 #2395
**NOTE:** The move to multi-architecture required that we update the
embedded Docker client, and this has the effect that this release of
Weave Net will not work with Docker installations older than
1.10.
[Full list of changes](https://github.com/weaveworks/weave/issues?q=milestone%3A1.9.0).
## Release 1.8.2
Bug fixes and minor improvements
* Fixed a bug where looping flows were installed which caused high CPU
usage #2650, #2674
* Fixed a bug where Kubernetes master could not contact pods #2673, #2683
* Fixed a bug where weave-kube was crashing in a loop due to invalid
Weave bridge state #2657
* Fixed a bug where iptables NAT rules were not appended due to
"temporary unavailable" iptables error #2679
* Added a detection of enabling the hairpin mode on the Weave bridge port
which caused installation of looping flows #2674
* Added a detection of overlaps between Weave and the host IP address
ranges when launching weave-kube #2669, #2672
* Added logging of connections blocked by weave-npc #2546, #2573
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.8.2).
## Release 1.8.1
Bug fixes and minor improvements
* Fixed weave-npc crash from Succeeded/Failed pods #2632,#2658
* Fixed occasional failure to create Weave bridge on node reboot
#2617,#2637
* Fixed a bug where weave-kube would fail to install when run with
unrelease snapshot builds #2642
* Improved conformance to CNI spec by not releasing IP addresses when
a container dies #2643
* Improved troubleshooting of install failure by creating CNI config
after Weave Net is up #2570
* "up to date" shown even when the version check was blocked by
firewall #2537,#2565,#2645
* "Unable to claim" message on re-launching Weave after using CNI
#2548,#2577
* Eliminated spurious IP reclaim operations when IPAM was disabled
#2567,#2644
* Include `jq` tool in our build VM configuration #2656
## Release 1.8.0
Highlights:
* Exposed network policy controller Prometheus metrics
weaveworks/weave-npc#23, #2595, #2549
* Exposed router Prometheus metrics #2535, #2547, #2523, #2579, #2578,
#2568, #2560, #2561
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.8.0).
## Release 1.7.2
Bug fixes and minor improvements
* Fixed an error where the Docker plugin could fail to attach a
container with a `bridge "weave" not present` error #2540/#2541
* Fixed `cannot connect to itself` panic on weave launch #2527/#2543
* Fixed inferred initial peer count when target peers includes self
#2481/#2543
* Fixed compilation on Raspberry Pi #2506/#2538
## Release 1.7.1
Bug fixes and minor improvements
* Added utility to recover container addresses without asking Docker #2531
* Improved CI #2274
## Release 1.7.0
Highlights:
* weave-kube - Deploy Weave Net to Kubernetes with a single command
* weave-npc - Kubernetes network policy controller implementation
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.7.0).
## Release 1.6.2
Bug fixes and minor improvements
* Fixed hang after stopping and restarting on Docker 1.12 #2469/#2502
* Avoid an error on Google container images by checking for tx offload support #2504
* Fixed an issue where the supplied peer list could be ignored when restarting after failure #2503/#2509
* Check for empty peer name on launch #2495/#2501
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.6.2).
## Release 1.6.1
Bug fixes and minor improvements
* `weave ps` was occasionally failing to list allocated addresses of containers #2388/#2418/#2445
* `weave launch[-router]` on 4.2 kernel would appear to succeed even if the fast datapath VXLAN UDP port was in use by a different process #2375/#2474
* Launching the proxy would fail when the Docker daemon could not be detected #2457/#2424
* The CNI plugin did not work with Apache Mesos #2394/#2442
* Router stopped working after a restart in the AWSVPC mode #2381/#2409
* Router crashed when the Docker API endpoint parameter was explicitly set to empty #2421/#2467
* The CNI plugin did not work on recent versions of Docker for Mac #2434/#2442
* The CNI plugin assigns an IP to the bridge if necessary, which avoids failures if `weave expose` has not run yet #2471
* Distinguish peer name collisions from attempts to connect to self in logs #2460
* Improve host clock skew detection message #2174
* Improve the error message returned when executing `weave launch-plugin` without the router running #2293/#2416
* The `create-bridge` subcommand was not enabled in the fast datapath mode #2464/2466
* Allow users to omit `weave setup[-cni]` by initializing the CNI plugin on the `launch[-router]` subcommand #2435/#2442
* Reduce verbosity of fast datapath miss event logs #1852/#2417
* Include the `ipam` option in the help output of the `status` subcommand #2425/#2426
* Remove a harmless duplication of the `--no-dns` parameter #2430
* Internal refactoring
* Improvements to testing and building
* Improvements to the documentation
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.6.1).
## Release 1.6.0
## Highlights
* A new [AWS VPC](https://weave.works/docs/net/latest/using-weave/awsvpc/) mode
that leverages Amazon Virtual Private Cloud for near-native network
performance, as an alternative to the Sleeve and Fast Datapath
overlays
* Docker 1.12 introduced some internal changes that made it
incompatible with previous version of Weave Net - this version
restores compatibility
* An [operational guide](https://weave.works/docs/net/latest/operational-guide)
detailing best practices for deploying and operating Weave Net
* Changes to the target peer list are remembered across restarts,
making it much easier to deploy resilient networks
* The version checkpoint now transmits network mode (e.g. 'awsvpc')
and kernel/docker versions to us to inform and guide our development
efforts. See the [installation documentation](https://weave.works/docs/net/latest/installing-weave/)
for instructions on disabling the checkpoint feature.
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.6.0).
## Release 1.5.2
Bug fixes and minor improvements
* Weave Proxy did not flush the initial http header in the Docker event stream, which could cause Docker Swarm to show all nodes pending. #2306/#2311
* When using the CNI plugin, if a container was removed and quickly replaced by another using the same IP address, other containers might be unable to contact it. Send an address resolution protocol message to update them. #2313
* Avoid Docker hanging for 1 minute in `weave launch` if the plugin had not shut down cleanly #2286/#2292
* Print an error message when Weave bridge mode is changed without `weave reset` #2304
* Eliminate spurious warning message from IP allocator on plugin shutdown #2300/#2319
* Display error message when address requested in a subnet that is too small (/31 or /32) #2282/#2321
* Add short wait after `weave reset` to allow updates to reach peers #2280
* Weave was occasionally unable to claim existing IP address immediately after launch #2275/#2281
* Refactor some integration tests to run faster and more reliably #2291
## Release 1.5.1
Bug fixes and minor improvements
* Persisted data that was rendered invalid by changing peer name or
allocation range is detected and removed automatically, preventing
crashes and hangs #2246/#2209/#2249
* `weave rmpeer` persists the range takeover in case the peer on which
it was executed dies subsequently #2238
* Launching a container with an explicit `WEAVE_CIDR` in the
allocation range now waits instead of erroring if the allocator
hasn't finished initialising #2232/#2265
* Weave DNS now responds to AAAA queries with an empty answer section,
instead of NXDOMAIN which could be cached and block subsequent
resolution of A records #2244/#2252
* Many improvements to the documentation.
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.5.1).
## Release 1.5.0
## Highlights
- A new [Container Network Interface](https://github.com/appc/cni#cni---the-container-network-interface) plugin.
- This release is much more robust against unscheduled restarts,
because it persists key data to disk.
- New configuration options that are useful when you create or
auto-scale larger networks.
- Weave now periodically checks for updates (can be disabled)
Plus many bug fixes and minor enhancements. More details below and in
the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.5.0).
## Release 1.4.6
Fixes some issues encountered by our users.
* Restarting a peer could leave stale entries in WeaveDNS
#1867/#2023/#2081
* Weave proxy occasionally failing to attach any new containers
#2016/#2049
Other fixes:
* Resolved a crash when a restarting peer re-connected to a peer that
had not received the latest IPAM data #2083/#2092
* Make IP address space available immediately after a dead peer is
removed #2068
## Release 1.4.5
Higher performance for multicast and broadcast traffic when using
Weave's Fast Datapath
* The flow rule to deliver broadcast and multicast packets in-kernel
was not created correctly, hence every such packet caused a
context-switch to the software router #2003/#2008
Other fixes:
* Remove DNS entries for containers that are being restarted by Docker
but are not live yet #1977/#1989
* Don't let one failing allocation attempt prevent others from
succeeding; they could be in different subnets which are more
available #1996/#2001
* Don't complain on second router launch on kernels that lack support
for Fast Datapath #1929/#1983
* Fix build broken by change in libnetwork IPAM API #1984/#1985
## Release 1.4.4
Fixing a rather serious issue that slipped through our preparations
for Docker 1.10:
* Restarting Docker or rebooting your machine while the Weave Net
plugin is running causes Docker 1.10.0 to fail to start #1959/#1963
Also one other small fix:
* Avoid a hang when trying to use plugin and proxy at the same time
#1956/#1961
## Release 1.4.3
Preparing for Docker 1.10, plus some bug-fixes.
* Avoid hang in Docker v1.10 on `docker volume ls` after `weave stop`,
`weave stop-plugin` or `weave reset` #1934/#1936
* Fix "unexpected EOF" from Docker 1.10 on `docker exec` with Weave
proxy `--rewrite-inspect` enabled #1911/#1917
* Avoid losing DNS entries and potentially double-allocating IP
Addresses allocated via plugin, on router restart; also extend
`weave ps` to show IP addresses allocated via plugin #1745/#1921
* Stop creating lots of copies of `weavewait` program in Docker
volumes #1757/#1935
* Prevent container starting prematurely when proxy in
`--no-multicast-route` mode #1942/#1943
* Log error message from plugin rather than crashing when weave not
running #1906/#1918
* Warn, don't error, if unable to remove plugin network in 'weave
stop', to avoid breaking the usual upgrade or config change process
#1900/#1919
* Don't crash if network conditions suggest only very small packets
will get through #1905/#1926
* Cope with unexpected errors during route traversal when starting
container via proxy #1909/#1910/#1932
## Release 1.4.2
Bug-fixes and minor improvements.
* A race condition in weavewait that would occasionally hang
containers at startup #1882/#1884
* Having the plugin auto-restart prevents successful `weave launch` on
reboot #1869
* Work round weave router failure on CoreOS 4.3 caused by kernel bug
#1854
* `weave launch` would exit with error code on docker <1.9 #1851
* Running `eval $(weave env)` multiple times would break `eval $(weave
env --restore)` #1824/#1825
* Don't complain in `weave stop` about "Plugin is not running" when
plugin is not enabled #1840/#1841
* `weave --local launch` would fail if utility program
`docker_tls_args` could not be found #1844
* Improved error reporting when TLS arg detection fails #1843
* Improve error reporting when docker isn't running #1845
* Add `--trusted-subnets` usage to `weave` script #1842
* weave run can hang under rare combinations of options #1858
## Release 1.4.1
This is a bug-fix release to cover a few issues that came up since the
release of 1.4.0.
* Weave would fail to launch when `$DOCKER_HOST` was set to a TCP socket secured with TLS #1820/#1822
* Weave would fail to stop when run against Docker pre-1.9 #1815/#1817
* Issue a warning instead of failing on `--with-dns` option to proxy, which was removed #1810/#1812
* Make `weave version` show the plugin version #1797/#1813
* Make `weave launch` show when the a container is restarting #1778/#1814
* Make `weave launch` fail if the plugin is running, for consistency with router and proxy. #1818/#1819
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.4.1).
## Release 1.4.0
**Highlights**
* The Docker Network plugin can now operate without a cluster store, so it is now run by default.
* You can now use the fast datapath over trusted links and Weave encryption over untrusted links, in the same network.
Plus many bug fixes and minor enhancements. More details below and in
the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.4.0).
## Release 1.3.1
**Highlights**
* The minimum Docker version has been increased to 1.6 due to the
[upcoming deprecation of Dockerhub access](https://blog.docker.com/2015/10/docker-hub-deprecation-1-5/)
for old clients. From December 7th onwards previous versions of the
`weave` script will fail to pull down images from the hub; if you
are unable to upgrade to 1.3.1 immediately you can work around this
by running `weave --local setup` in conjunction with a compatible
Docker client installation
* Docker networking plugin now works with older kernels and allows you
to configure the MTU
More details in the
[change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.3.1).
## Release 1.3.0
**Highlights**
+32
View File
@@ -0,0 +1,32 @@
Thanks for your interest in contributing to this project and for
taking the time to read this guide.
# Code of conduct
**Be respectful:** disagreements between people are to be expected and are usually the sign of healthy debate and engagement. Disagreements can lead to frustration and even anger for some members. Turning to personal insults, intimidation or threatening behaviour does not improve the situation. Participants should thus take care to ensure all communications / interactions stay professional at all times.
**Be considerate:** remember that the community has members with a diverse background, many of whom have English as a second language. What might appear impolite, may simply be a result of a lack of knowledge of the English language. Bear in mind that actions will have an impact on other community members and the project as a whole, so take potential consequences into account before pursuing a course of action.
**Be forgiving:** humans are fallible and as such prone to make mistakes and inexplicably change their positions at times. Don't assume that other members are acting with malicious intent. Be prepared to forgive people who make mistakes and assist each other in learning from them. Playing a blame game doesn't help anyone.
# Issues
* Before reporting an issue make sure you search first if anybody has already reported a similar issue and whether or not it has been fixed.
* Make sure your issue report sufficiently details the problem:
* If you set up weave in some way other than that described by our [main instructions](https://github.com/zettio/weave#installation), please mention that.
* Include step-by-step instructions to reproduce the issue.
* State the OS platform you are using, i.e. `uname -a`
* `iptables` rules and firewalls can have a great impact on any Linux network; please note whether you have set up any rules and/or are running a firewall on your machine(s).
* If you want to tackle any open issue, make sure you let people know you are working on it.
## Pull Requests
* Please be generous describing your changes.
* Although it is highly suggested to include tests, they are not a hard requirement in order to get your contributions accepted.
* Keep pull requests small so core developers can review them quickly.
* Keep each pull request focused on a specific topic. If you have two things to change, create two pull requests. This helps reviewers to understand the meat of your contribution.
## Workflow
See [WorkingOnWeave](https://github.com/weaveworks/weave/wiki/WorkingOnWeave)
# Acknowledgements
Much of this taken from https://github.com/cloudescape/gowsdl/blob/master/CONTRIBUTING.md
+1 -1
View File
@@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS
Copyright 2014-2015 Weaveworks Ltd.
Copyright 2014-2016 Weaveworks Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+285 -72
View File
@@ -1,40 +1,137 @@
PUBLISH=publish_weave publish_weaveexec
.DEFAULT: all
.PHONY: all update tests lint publish $(PUBLISH) clean clean-bin prerequisites build travis run-smoketests
.PHONY: all exes testrunner update tests lint publish-one-arch $(PUBLISH) clean clean-bin prerequisites build run-smoketests
# If you can use docker without being root, you can do "make SUDO="
SUDO=sudo
SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E")
BUILD_IN_CONTAINER=true
RM=--rm
RUN_FLAGS=-ti
COVERAGE=
DOCKERHUB_USER=weaveworks
WEAVE_VERSION=git-$(shell git rev-parse --short=12 HEAD)
# This specifies the architecture we're building for
ARCH?=amd64
# We're using QEMU to be able to build Docker images for other architectures
# from amd64 machines.
QEMU_VERSION=v2.7.0
# A list of all supported architectures here. Should be named as Go is naming platforms
# All supported architectures must have an "ifeq" block below that customizes the parameters
ALL_ARCHITECTURES=amd64 arm arm64
ML_PLATFORMS=linux/amd64,linux/arm,linux/arm64
ifeq ($(ARCH),amd64)
# The architecture to use when downloading the docker binary
WEAVEEXEC_DOCKER_ARCH?=x86_64
# The name of the alpine baseimage to use as the base for weave images
ALPINE_BASEIMAGE?=alpine:3.4
# The extension for the made images
# Specifying none means for example weaveworks/weave:latest
ARCH_EXT?=
# The name of the gcc we're using for compiling C code
CC=gcc
# Optional parameters that can be passed when linking C code into the Go binary
CGO_LDFLAGS=
endif
ifeq ($(ARCH),arm)
# The architecture to use when downloading the docker binary
WEAVEEXEC_DOCKER_ARCH?=armel
# Using the (semi-)official alpine image
ALPINE_BASEIMAGE?=armhf/alpine:3.4
# arm images have the -arm suffix, for instance weaveworks/weave-arm:latest
ARCH_EXT?=-arm
# The name of the gcc binary
CC=arm-linux-gnueabihf-gcc
# The architecture name to use when downloading a prebuilt QEMU binary
QEMUARCH=arm
# In the weaveworks/build image; libpcap libraries for arm are placed here
# Tell the gcc linker to search for libpcap here
CGO_LDFLAGS="-L/usr/local/lib/$(CC)"
endif
ifeq ($(ARCH),arm64)
# Use the arm 32-bit docker client variant
WEAVEEXEC_DOCKER_ARCH?=armel
# Using the (semi-)official alpine image
ALPINE_BASEIMAGE?=aarch64/alpine:3.5
# arm64 images have the -arm64 suffix, for instance weaveworks/weave-arm64:latest
ARCH_EXT?=-arm64
# The name of the gcc binary
CC=aarch64-linux-gnu-gcc
# The architecture name to use when downloading a prebuilt QEMU binary
QEMUARCH=aarch64
# In the weaveworks/build image; libpcap libraries for arm64 are placed here
# Tell the gcc linker to search for libpcap here
CGO_LDFLAGS="-L/usr/local/lib/$(CC)"
endif
# The name of the user that this Makefile should produce image artifacts for. Can/should be overridden
DOCKERHUB_USER?=weaveworks
# The default version that's chosen when pushing the images. Can/should be overridden
WEAVE_VERSION?=git-$(shell git rev-parse --short=12 HEAD)
# Paths to all relevant binaries that should be compiled
WEAVER_EXE=prog/weaver/weaver
WEAVEPROXY_EXE=prog/weaveproxy/weaveproxy
SIGPROXY_EXE=prog/sigproxy/sigproxy
KUBEPEERS_EXE=prog/kube-peers/kube-peers
WEAVENPC_EXE=prog/weave-npc/weave-npc
WEAVEWAIT_EXE=prog/weavewait/weavewait
WEAVEWAIT_NOOP_EXE=prog/weavewait/weavewait_noop
NETCHECK_EXE=prog/netcheck/netcheck
DOCKERTLSARGS_EXE=prog/docker_tls_args/docker_tls_args
WEAVEWAIT_NOMCAST_EXE=prog/weavewait/weavewait_nomcast
WEAVEUTIL_EXE=prog/weaveutil/weaveutil
PLUGIN_EXE=prog/plugin/plugin
RUNNER_EXE=tools/runner/runner
MANIFEST_TOOL_DIR=vendor/github.com/estesp/manifest-tool
MANIFEST_TOOL_EXE=$(MANIFEST_TOOL_DIR)/manifest-tool
TEST_TLS_EXE=test/tls/tls
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE)
# All binaries together in a list
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE) $(PLUGIN_EXE) $(RUNNER_EXE) $(TEST_TLS_EXE) $(MANIFEST_TOOL_EXE)
WEAVER_UPTODATE=.weaver.uptodate
WEAVEEXEC_UPTODATE=.weaveexec.uptodate
# These stamp files are used to mark the current state of the build; whether an image has been built or not
BUILD_UPTODATE=.build.uptodate
WEAVER_UPTODATE=.weaver$(ARCH_EXT).uptodate
WEAVEEXEC_UPTODATE=.weaveexec$(ARCH_EXT).uptodate
PLUGIN_UPTODATE=.plugin$(ARCH_EXT).uptodate
WEAVEKUBE_UPTODATE=.weavekube$(ARCH_EXT).uptodate
WEAVENPC_UPTODATE=.weavenpc$(ARCH_EXT).uptodate
WEAVEDB_UPTODATE=.weavedb.uptodate
IMAGES_UPTODATE=$(WEAVER_UPTODATE) $(WEAVEEXEC_UPTODATE)
IMAGES_UPTODATE=$(WEAVER_UPTODATE) $(WEAVEEXEC_UPTODATE) $(PLUGIN_UPTODATE) $(WEAVEKUBE_UPTODATE) $(WEAVENPC_UPTODATE)
WEAVER_IMAGE=$(DOCKERHUB_USER)/weave
WEAVEEXEC_IMAGE=$(DOCKERHUB_USER)/weaveexec
# The names of the images. Note that the images for other architectures than amd64 have a suffix in the image name.
WEAVER_IMAGE=$(DOCKERHUB_USER)/weave$(ARCH_EXT)
WEAVEEXEC_IMAGE=$(DOCKERHUB_USER)/weaveexec$(ARCH_EXT)
PLUGIN_IMAGE=$(DOCKERHUB_USER)/plugin$(ARCH_EXT)
WEAVEKUBE_IMAGE=$(DOCKERHUB_USER)/weave-kube$(ARCH_EXT)
WEAVENPC_IMAGE=$(DOCKERHUB_USER)/weave-npc$(ARCH_EXT)
BUILD_IMAGE=weaveworks/weavebuild
WEAVEDB_IMAGE=$(DOCKERHUB_USER)/weavedb
IMAGES=$(WEAVER_IMAGE) $(WEAVEEXEC_IMAGE)
IMAGES=$(WEAVER_IMAGE) $(WEAVEEXEC_IMAGE) $(PLUGIN_IMAGE) $(WEAVEKUBE_IMAGE) $(WEAVENPC_IMAGE) $(WEAVEDB_IMAGE)
WEAVE_EXPORT=weave.tar.gz
PUBLISH=publish_weave publish_weaveexec publish_plugin publish_weave-kube publish_weave-npc
PUSH_ML=push_ml_weave push_ml_weaveexec push_ml_plugin push_ml_weave-kube push_ml_weave-npc
WEAVEEXEC_DOCKER_VERSION=1.3.1
DOCKER_DISTRIB=prog/weaveexec/docker-$(WEAVEEXEC_DOCKER_VERSION).tgz
DOCKER_DISTRIB_URL=https://get.docker.com/builds/Linux/x86_64/docker-$(WEAVEEXEC_DOCKER_VERSION).tgz
WEAVE_EXPORT=weave$(ARCH_EXT).tar.gz
DOCKER_VERSION=1.10.3
DOCKER_DISTRIB=prog/weaveexec/docker-$(DOCKER_VERSION).tgz
DOCKER_DISTRIB_URL=https://get.docker.com/builds/Linux/$(WEAVEEXEC_DOCKER_ARCH)/docker-$(DOCKER_VERSION).tgz
NETGO_CHECK=@strings $@ | grep cgo_stub\\\.go >/dev/null || { \
rm $@; \
echo "\nYour go standard library was built without the 'netgo' build tag."; \
@@ -43,106 +140,222 @@ NETGO_CHECK=@strings $@ | grep cgo_stub\\\.go >/dev/null || { \
echo " sudo go install -tags netgo std"; \
false; \
}
BUILD_FLAGS=-ldflags "-extldflags \"-static\" -X main.version $(WEAVE_VERSION)" -tags netgo
# The flags we are passing to go build. -extldflags -static for making a static binary,
# -linkmode external for linking external C libraries into the binary, -X main.version for telling the
# Go binary which version it is, -tags netgo for enforcing the native Go DNS resolver
BUILD_FLAGS=-i -ldflags "-linkmode external -extldflags -static -X main.version=$(WEAVE_VERSION)" -tags netgo
PACKAGE_BASE=$(shell go list -e ./)
all: $(WEAVE_EXPORT) $(RUNNER_EXE)
all: $(WEAVE_EXPORT)
testrunner: $(RUNNER_EXE) $(TEST_TLS_EXE)
travis: $(EXES)
$(WEAVER_EXE) $(WEAVEPROXY_EXE) $(WEAVEUTIL_EXE): common/*.go common/*/*.go net/*.go net/*/*.go
$(WEAVER_EXE): router/*.go ipam/*.go ipam/*/*.go db/*.go nameserver/*.go prog/weaver/*.go
$(WEAVEPROXY_EXE): proxy/*.go prog/weaveproxy/*.go
$(WEAVEUTIL_EXE): prog/weaveutil/*.go net/*.go plugin/net/*.go plugin/ipam/*.go db/*.go
$(SIGPROXY_EXE): prog/sigproxy/*.go
$(KUBEPEERS_EXE): prog/kube-peers/*.go
$(WEAVENPC_EXE): prog/weave-npc/*.go npc/*.go npc/*/*.go
$(PLUGIN_EXE): prog/plugin/*.go plugin/*/*.go api/*.go common/*.go common/docker/*.go net/*.go
$(TEST_TLS_EXE): test/tls/*.go
$(RUNNER_EXE): tools/runner/*.go
$(MANIFEST_TOOL_EXE): $(MANIFEST_TOOL_DIR)/*.go
$(WEAVEWAIT_NOOP_EXE): prog/weavewait/*.go
$(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
$(WEAVEWAIT_NOMCAST_EXE): prog/weavewait/*.go net/*.go
tests: tools/.git
lint: tools/.git
update:
go get -u -f -v -tags netgo $(addprefix ./,$(dir $(EXES)))
ifeq ($(BUILD_IN_CONTAINER),true)
$(WEAVER_EXE) $(WEAVEPROXY_EXE): common/*.go common/*/*.go net/*.go
# This make target compiles all binaries inside of the weaveworks/build container
# It bind-mounts the source into the container and passes all important variables
exes $(EXES) tests lint: $(BUILD_UPTODATE)
git submodule update --init
@mkdir -p $(shell pwd)/.pkg
$(SUDO) docker run $(RM) $(RUN_FLAGS) \
-v $(shell pwd):/go/src/github.com/weaveworks/weave \
-v $(shell pwd)/.pkg:/go/pkg \
-e GOARCH=$(ARCH) -e CGO_ENABLED=1 -e GOOS=linux -e CIRCLECI -e CIRCLE_BUILD_NUM -e CIRCLE_NODE_TOTAL -e CIRCLE_NODE_INDEX -e COVERDIR -e SLOW -e DEBUG \
$(BUILD_IMAGE) COVERAGE=$(COVERAGE) WEAVE_VERSION=$(WEAVE_VERSION) CC=$(CC) QEMUARCH=$(QEMUARCH) CGO_LDFLAGS=$(CGO_LDFLAGS) $@
else
exes: $(EXES)
$(WEAVER_EXE) $(WEAVEPROXY_EXE) $(PLUGIN_EXE):
ifeq ($(COVERAGE),true)
$(eval COVERAGE_MODULES := $(shell (go list ./$(@D); go list -f '{{join .Deps "\n"}}' ./$(@D) | grep "^$(PACKAGE_BASE)/") | paste -s -d,))
go get -t -tags netgo ./$(@D)
$(eval COVERAGE_MODULES := $(shell (go list ./$(@D); go list -f '{{join .Deps "\n"}}' ./$(@D) | grep "^$(PACKAGE_BASE)/") | grep -v "^$(PACKAGE_BASE)/vendor/" | paste -s -d,))
go test -c -o ./$@ $(BUILD_FLAGS) -v -covermode=atomic -coverpkg $(COVERAGE_MODULES) ./$(@D)/
else
go get -tags netgo ./$(@D)
go build $(BUILD_FLAGS) -o $@ ./$(@D)
endif
$(NETGO_CHECK)
$(NETCHECK_EXE): common/*.go common/*/*.go net/*.go
go get -tags netgo ./$(@D)
$(WEAVEUTIL_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE):
go build $(BUILD_FLAGS) -o $@ ./$(@D)
$(NETGO_CHECK)
$(WEAVER_EXE): router/*.go mesh/*.go ipam/*.go ipam/*/*.go nameserver/*.go prog/weaver/*.go
$(WEAVEPROXY_EXE): proxy/*.go prog/weaveproxy/main.go
$(NETCHECK_EXE): prog/netcheck/netcheck.go
$(WEAVEWAIT_EXE):
go build $(BUILD_FLAGS) -tags "netgo iface mcast" -o $@ ./$(@D)
$(NETGO_CHECK)
# Sigproxy and weavewait need separate rules as they fail the netgo check in
$(WEAVEWAIT_NOMCAST_EXE):
go build $(BUILD_FLAGS) -tags "netgo iface" -o $@ ./$(@D)
$(NETGO_CHECK)
# These programs need a separate rule as they fail the netgo check in
# the main build stanza due to not importing net package
$(SIGPROXY_EXE): prog/sigproxy/main.go
$(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
$(DOCKERTLSARGS_EXE): prog/docker_tls_args/*.go
$(WEAVEWAIT_EXE) $(SIGPROXY_EXE) $(DOCKERTLSARGS_EXE):
go get -tags netgo ./$(@D)
$(SIGPROXY_EXE) $(TEST_TLS_EXE) $(WEAVEWAIT_NOOP_EXE) $(RUNNER_EXE) $(MANIFEST_TOOL_EXE):
go build $(BUILD_FLAGS) -o $@ ./$(@D)
$(WEAVEWAIT_NOOP_EXE): prog/weavewait/*.go
go get -tags netgo ./$(@D)
go build $(BUILD_FLAGS) -tags noop -o $@ ./$(@D)
tests:
./tools/test -no-go-get -netgo -timeout 8m
$(WEAVER_UPTODATE): prog/weaver/Dockerfile $(WEAVER_EXE)
$(SUDO) docker build -t $(WEAVER_IMAGE) prog/weaver
lint:
./tools/lint -nocomment -notestpackage .
endif
# This rule makes sure the build image is up-to-date.
# It also makes sure the multiarch hooks are reqistered in the kernel so the QEMU emulation works
$(BUILD_UPTODATE): build/*
$(SUDO) docker build -t $(BUILD_IMAGE) build/
$(SUDO) docker run --rm --privileged multiarch/qemu-user-static:register --reset
touch $@
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE)
# Creates the Dockerfile.your-user-here file from the template
# Also replaces all placeholders with real values
# If the architecture is amd64, it deletes all CROSS_BUILD lines
# but otherwise, it only removes the "CROSS_BUILD_" placeholder and downloads QEMU
%/Dockerfile.$(DOCKERHUB_USER): %/Dockerfile.template
echo "DOCKERHUB_USER|$(DOCKERHUB_USER)|g;s|ARCH_EXT|$(ARCH_EXT)|g;s|ALPINE_BASEIMAGE|$(ALPINE_BASEIMAGE)|g;s|QEMUARCH|$(QEMUARCH)"
sed -e "s|DOCKERHUB_USER|$(DOCKERHUB_USER)|g;s|ARCH_EXT|$(ARCH_EXT)|g;s|ALPINE_BASEIMAGE|$(ALPINE_BASEIMAGE)|g;s|QEMUARCH|$(QEMUARCH)|g" $^ > $@
ifeq ($(ARCH),amd64)
# When building "normally" for amd64, remove the whole line, it has no part in the amd64 image
sed -i "/CROSS_BUILD_/d" $@
else
# When cross-building, only the placeholder "CROSS_BUILD_" should be removed
# Register /usr/bin/qemu-ARCH-static as the handler for ARM binaries in the kernel
curl -sSL https://github.com/multiarch/qemu-user-static/releases/download/$(QEMU_VERSION)/x86_64_qemu-$(QEMUARCH)-static.tar.gz | tar -xz -C $(shell dirname $@)
cd $(shell dirname $@) && sha256sum -c $(shell pwd)/build/shasums/qemu-$(QEMUARCH)-static.sha256sum
sed -i "s/CROSS_BUILD_//g" $@
endif
# The targets below builds the weave images
$(WEAVER_UPTODATE): prog/weaver/Dockerfile.$(DOCKERHUB_USER) $(WEAVER_EXE) $(WEAVEEXEC_UPTODATE)
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -f prog/weaver/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVER_IMAGE) prog/weaver
touch $@
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexec/symlink $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE)
cp weave prog/weaveexec/weave
cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy
cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy
cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
cp $(NETCHECK_EXE) prog/weaveexec/netcheck
cp $(DOCKERTLSARGS_EXE) prog/weaveexec/docker_tls_args
cp $(DOCKER_DISTRIB) prog/weaveexec/docker.tgz
$(SUDO) docker build -t $(WEAVEEXEC_IMAGE) prog/weaveexec
cp $(WEAVEWAIT_NOMCAST_EXE) prog/weaveexec/weavewait_nomcast
cp $(WEAVEUTIL_EXE) prog/weaveexec/weaveutil
tar -xf $(DOCKER_DISTRIB) usr/local/bin/docker -O > prog/weaveexec/docker
chmod +x prog/weaveexec/docker
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -f prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVEEXEC_IMAGE) prog/weaveexec
touch $@
$(WEAVE_EXPORT): $(IMAGES_UPTODATE)
$(SUDO) docker save $(addsuffix :latest,$(IMAGES)) | gzip > $@
$(PLUGIN_UPTODATE): prog/plugin/Dockerfile.$(DOCKERHUB_USER) $(PLUGIN_EXE) $(WEAVER_UPTODATE)
$(SUDO) docker build -f prog/plugin/Dockerfile.$(DOCKERHUB_USER) -t $(PLUGIN_IMAGE) prog/plugin
touch $@
$(WEAVEKUBE_UPTODATE): prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) prog/weave-kube/launch.sh $(KUBEPEERS_EXE) $(WEAVER_UPTODATE)
cp $(KUBEPEERS_EXE) prog/weave-kube/
$(SUDO) docker build -f prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVEKUBE_IMAGE) prog/weave-kube
touch $@
$(WEAVENPC_UPTODATE): prog/weave-npc/Dockerfile.$(DOCKERHUB_USER) $(WEAVENPC_EXE) prog/weave-npc/ulogd.conf
$(SUDO) docker build -f prog/weave-npc/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVENPC_IMAGE) prog/weave-npc
touch $@
$(WEAVEDB_UPTODATE): prog/weavedb/Dockerfile
$(SUDO) docker build -t $(WEAVEDB_IMAGE) prog/weavedb
touch $@
$(WEAVE_EXPORT): $(IMAGES_UPTODATE) $(WEAVEDB_UPTODATE)
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker save $(addsuffix :latest,$(IMAGES)) | gzip > $@
$(DOCKER_DISTRIB):
curl -o $(DOCKER_DISTRIB) $(DOCKER_DISTRIB_URL)
cd $(shell dirname $@) && sha256sum -c $(shell pwd)/build/shasums/docker-tgz-$(WEAVEEXEC_DOCKER_ARCH).sha256sum
tests: tools/.git
tools/test
lint: tools/.git
tools/lint -nocomment -notestpackage .
tools/.git:
tools/.git $(MANIFEST_TOOL_DIR)/.git:
git submodule update --init
$(RUNNER_EXE): tools/.git
make -C tools/runner
# CODE FOR PUBLISHING THE IMAGES
$(PUBLISH): publish_%: $(IMAGES_UPTODATE)
$(SUDO) docker tag -f $(DOCKERHUB_USER)/$* $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
$(SUDO) docker push $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
ifneq ($(UPDATE_LATEST),false)
$(SUDO) docker push $(DOCKERHUB_USER)/$*:latest
# This target first runs "make publish" for each architecture
# Then it pushes the manifest lists
publish: $(addprefix sub-publish-,$(ALL_ARCHITECTURES)) $(WEAVEDB_UPTODATE)
$(MAKE) DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) $(PUSH_ML)
ifeq ($(PUBLISH_WEAVEDB),true)
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/weavedb:latest
endif
publish: $(PUBLISH)
sub-publish-%:
$(MAKE) ARCH=$* DOCKER_HOST=$(DOCKER_HOST) clean-bin
$(MAKE) ARCH=$* DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) $(IMAGES_UPTODATE)
$(MAKE) ARCH=$* DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) publish-one-arch
publish-one-arch: $(PUBLISH)
# This rule handles the pushing of the built images
$(PUBLISH): publish_%: $(IMAGES_UPTODATE)
# Tag :latest with the real version
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker tag $(DOCKERHUB_USER)/$*$(ARCH_EXT) $(DOCKERHUB_USER)/$*$(ARCH_EXT):$(WEAVE_VERSION)
# Push the image with the arch suffix for arm and arm64, and without suffix for amd64
$(MAKE) DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) push_$*$(ARCH_EXT)
ifeq ($(ARCH),amd64)
# If the architecture is amd64, add the -amd64 suffix.
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker tag $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION) $(DOCKERHUB_USER)/$*-amd64:$(WEAVE_VERSION)
# If the version is latest, tag the -amd64 with latest as well
ifneq ($(UPDATE_LATEST),false)
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker tag $(DOCKERHUB_USER)/$*-amd64:$(WEAVE_VERSION) $(DOCKERHUB_USER)/$*-amd64:latest
endif
# Push the image with the -amd64-suffix so BINARY-ARCH-named images exist for all arches, so manifest lists may be made and ARCH is replaceable in scripts
$(MAKE) DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) push_$*-amd64
endif
# This target pushes an image, and if UPDATE_LATEST is anything but false, also updates the latest tag
# It takes one parameter, the image name
push_%:
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
ifneq ($(UPDATE_LATEST),false)
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/$*:latest
endif
# This target pushes a manifest list; it takes one parameter, the image name.
# The variable UPDATE_LATEST controls whether it updates the versioned tag and/or the latest tag
$(PUSH_ML): push_ml_%: $(MANIFEST_TOOL_EXE)
ifneq ($(UPDATE_LATEST),latest-only)
$(MANIFEST_TOOL_EXE) push from-args --platforms $(ML_PLATFORMS) --template $(DOCKERHUB_USER)/$*-ARCH:$(WEAVE_VERSION) --target $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
endif
ifneq ($(UPDATE_LATEST),false)
# Push the manifest list to :latest as well
$(MANIFEST_TOOL_EXE) push from-args --platforms $(ML_PLATFORMS) --template $(DOCKERHUB_USER)/$*-ARCH:latest --target $(DOCKERHUB_USER)/$*:latest
endif
clean-bin:
-$(SUDO) docker rmi $(IMAGES)
go clean -r $(addprefix ./,$(dir $(EXES)))
rm -f $(EXES) $(IMAGES_UPTODATE) $(WEAVE_EXPORT)
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(IMAGES)
find prog -type f -name "Dockerfile.*" -not -name "Dockerfile.template" -print | xargs rm -f
find prog -type f -name "*qemu-*" -print | xargs rm -f
rm -rf $(EXES) $(IMAGES_UPTODATE) $(WEAVEDB_UPTODATE) weave*.tar.gz $(DOCKER_DISTRIB) prog/weaveexec/docker .pkg
clean: clean-bin
rm -rf test/tls/*.pem test/coverage.* test/coverage
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(BUILD_IMAGE)
rm -rf test/tls/*.pem test/coverage.* test/coverage $(BUILD_UPTODATE) $(MANIFEST_TOOL_EXE)
build:
$(SUDO) go clean -i net
$(SUDO) go install -tags netgo std
$(MAKE)
run-smoketests: all
run-smoketests: all testrunner
cd test && ./setup.sh && ./run_all.sh
+1 -1
View File
@@ -1,3 +1,3 @@
Weave
Copyright 2014-2015 Weaveworks Ltd.
Copyright 2014-2016 Weaveworks Ltd.
This product includes software developed at Weaveworks Ltd.
+16 -163
View File
@@ -1,174 +1,27 @@
# Weave - weaving containers into applications
# Weave Net - Weaving Containers into Applications
[![Build Status](https://travis-ci.org/weaveworks/weave.svg?branch=master)](https://travis-ci.org/weaveworks/weave) [![Integration Tests](https://circleci.com/gh/weaveworks/weave/tree/master.svg?style=shield&circle-token=4933c7dabb3d0383e62117565cb9d16df7b1a811)](https://circleci.com/gh/weaveworks/weave) [![Coverage Status](https://coveralls.io/repos/weaveworks/weave/badge.svg)](https://coveralls.io/r/weaveworks/weave)
[![Integration Tests](https://circleci.com/gh/weaveworks/weave/tree/master.svg?style=shield)](https://circleci.com/gh/weaveworks/weave)
[![Coverage Status](https://coveralls.io/repos/weaveworks/weave/badge.svg)](https://coveralls.io/r/weaveworks/weave)
[![Go Report Card](https://goreportcard.com/badge/github.com/weaveworks/weave)](https://goreportcard.com/report/github.com/weaveworks/weave)
[![Slack Status](https://slack.weave.works/badge.svg)](https://slack.weave.works)
[![Docker Pulls](https://img.shields.io/docker/pulls/weaveworks/weave.svg?maxAge=604800)](https://hub.docker.com/r/weaveworks/weave/)
# About Weaveworks
[Weaveworks](http://weave.works) is the company that develops Weave -
the most productive way for developers to connect, observe and control
Docker containers. To learn about our products, including getting
started tutorials, visit our [website](http://weave.works) and
[documentation](http://docs.weave.works) or continue to read about
some of the more technical aspects of Weave in this readme.
[Weaveworks](https://www.weave.works) is the company that delivers the most productive way for developers to connect, observe and control
Docker containers.
# Weave
This repository contains [Weave Net](https://www.weave.works/products/weave-net/), the first product developed by Weaveworks, and with over 8 million downloads to date, it enables you to get started with Docker clusters and portable apps in a fraction of the time compared with other solutions.
Weave creates a virtual network that connects Docker containers
deployed across multiple hosts and enables their automatic discovery.
Weaveworks' product [Weave Cloud](https://www.weave.works/solution/cloud/) takes the heavy lifting out of building, integrating and operating open source components, so you don’t have to manage databases, storage and availability.
![Weave Virtual Network](/docs/virtual-network.png?raw=true "Weave Virtual Network")
Weave Cloud is built using these Open Source projects: [Weave Scope](https://www.weave.works/products/weave-scope/), a powerful container monitoring tool that automatically maps Docker containers and their interactions, [Weave Cortex](https://github.com/weaveworks/cortex), a horizontally-scalable version of Prometheus, and [Weave Flux](https://www.weave.works/products/weave-flux/), a continuous deployment tool that works with Kubernetes.
Applications use the network just as if the containers were all
plugged into the same network switch, with no need to configure port
mappings, links, etc. Services provided by application containers on
the weave network can be made accessible to the outside world,
regardless of where those containers are running. Similarly, existing
internal systems can be exposed to application containers irrespective
of their location.
# Weave Net
![Weave Deployment](/docs/deployment.png?raw=true "Weave Deployment")
Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery. With Weave Net, portable microservices-based applications consisting of multiple containers can run anywhere: on one host, multiple hosts or even across cloud providers and data centers. Applications use the network just as if the containers were all plugged into the same network switch, without having to configure port mappings, ambassadors or links.
Weave can traverse firewalls and operate in partially connected
networks. Traffic can be encrypted, allowing hosts to be connected
across an untrusted network.
Services provided by application containers on the Weave network can be exposed to the outside world, regardless of where they are running. Similarly, existing internal systems can be opened to accept connections from application containers irrespective of their location.
With weave you can easily construct applications consisting of
multiple containers, running anywhere.
Weave works alongside Docker's existing (single host) networking
capabilities, so these can continue to be used by containers.
## Installation
Ensure you are running Linux (kernel 3.8 or later) and have Docker
(version 1.3.1 or later) installed. Then install weave with
sudo curl -L git.io/weave -o /usr/local/bin/weave
sudo chmod a+x /usr/local/bin/weave
For usage on OSX (with Docker Machine) you first need to make sure
that a VM is running and configured, as shown in [the Docker Machine
documentation](https://docs.docker.com/installation/mac/#from-your-shell).
Then you can launch weave directly from the OSX host.
CoreOS users see [here](https://github.com/fintanr/weave-gs/blob/master/coreos-simple/user-data) for an example of installing weave using cloud-config.
Amazon ECS users see
[here](https://github.com/weaveworks/guides/blob/master/aws-ecs/LATESTAMIs.md)
for the latest Weave AMIs and
[here](http://weave.works/guides/service-discovery-with-weave-aws-ecs.html) to get started with Weave on ECS.
Weave respects the environment variable `DOCKER_HOST`, so you can run
it locally to control a weave network on a remote host.
## Quick Start Screencast
<a href="https://youtu.be/kihQCCT1ykE" alt="Click to watch the screencast" target="_blank">
<img src="/docs/hello-screencast.png" />
</a>
## Example
Say you have docker running on two hosts, accessible to each other as
`$HOST1` and `$HOST2`, and want to deploy an application consisting of
two containers, one on each host.
On $HOST1 we run:
host1$ weave launch
host1$ eval $(weave env)
host1$ docker run --name a1 -ti ubuntu
> NB: If the first command results in an error like
> `http:///var/run/docker.sock/v1.19/containers/create: dial unix
> /var/run/docker.sock: permission denied. Are you trying to connect
> to a TLS-enabled daemon without TLS?` then you likely need to be
> 'root' in order to connect to the Docker daemon. If so, run the
> above and all subsequent commands in a *single* root shell (e.g. one
> created with `sudo -s`). Do *not* prefix individual commands with
> `sudo`, since some commands modify environment entries and hence
> they all need to be executed from the same shell.
The first line runs weave. The second line configures our environment
so that containers launched via the docker command line are
automatically attached to the weave network. Finally, we run our
application container.
That's it! If our application consists of more than one container on
this host we simply launch them with `docker run` as appropriate.
Next we repeat similar steps on `$HOST2`...
host2$ weave launch $HOST1
host2$ eval $(weave env)
host2$ docker run --name a2 -ti ubuntu
The only difference, apart from the name of the application container,
is that we tell our weave that it should peer with the weave on
`$HOST1` (specified as the IP address or hostname, and optional
`:port`, by which `$HOST2` can reach it). NB: if there is a firewall
between `$HOST1` and `$HOST2`, you must permit traffic to the weave
control port (TCP 6783) and data ports (UDP 6783/6784).
Note that we could instead have told the weave on `$HOST1` to connect to
`$HOST2`, or told both about each other. Order does not matter here;
weave automatically (re)connects to peers when they become
available. Also, we can tell weave to connect to multiple peers by
supplying multiple addresses, separated by spaces. And we can
[add peers dynamically](http://docs.weave.works/weave/latest_release/features.html#dynamic-topologies).
Weave must be started once per host. The relevant container images are
pulled down on demand, but if you wish you can preload them by running
`weave setup` - this is particularly useful for automated deployments,
and ensures that there are no delays during later operations.
Now that we've got everything set up, let's see whether our containers
can talk to each other...
In the container started on `$HOST1`...
root@a1:/# ping -c 1 -q a2
PING a2.weave.local (10.40.0.2) 56(84) bytes of data.
--- a2.weave.local ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.341/0.341/0.341/0.000 ms
Similarly, in the container started on `$HOST2`...
root@a2:/# ping -c 1 -q a1
PING a1.weave.local (10.32.0.2) 56(84) bytes of data.
--- a1.weave.local ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.366/0.366/0.366/0.000 ms
So there we have it, two containers on separate hosts happily talking
to each other.
## Find out more
* [Documentation homepage](http://docs.weave.works/weave/latest_release/)
* [Getting Started Guides](http://weave.works/guides/)
* [Features](http://docs.weave.works/weave/latest_release/features.html)
* [Troubleshooting](http://docs.weave.works/weave/latest_release/troubleshooting.html)
* [Building](http://docs.weave.works/weave/latest_release/building.html)
* [How it works](http://docs.weave.works/weave/latest_release/how-it-works.html)
## Contact Us
Found a bug, want to suggest a feature, or have a question? You can
[File an issue](https://github.com/weaveworks/weave/issues). And
there is a [Weave Users Google
Group](https://groups.google.com/a/weave.works/forum/#!forum/weave-users),
which you can post to by email at weave-users@weave.works. Or you can
contact Weaveworks directly at help@weave.works. When reporting a
bug, please include which version of weave you are running, as shown
by `weave version`.
Follow on Twitter:
[@weaveworks](https://twitter.com/weaveworks).
Read the Weave blog:
[Weaveblog](http://weaveblog.com/).
IRC:
[#weavenetwork](https://botbot.me/freenode/weavenetwork/)
* [Install Weave Net](https://www.weave.works/docs/net/latest/installing-weave/)
* [Find out more about Weave Net](https://www.weave.works/products/weave-net/)
Vendored
+7 -3
View File
@@ -5,7 +5,7 @@ require './vagrant-common.rb'
vm_ip = "172.16.0.3" # arbitrary private IP
pkgs = %w(
docker-engine
docker-engine=1.10.2-0~wily
aufs-tools
build-essential
ethtool
@@ -14,15 +14,16 @@ pkgs = %w(
git
mercurial
bc
jq
)
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/ubuntu-15.04-amd64"
config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/vivid/current/vivid-server-cloudimg-amd64-vagrant-disk1.box"
config.vm.box = "ubuntu/wily64"
config.vm.network "private_network", ip: vm_ip
config.vm.provider :virtualbox do |vb|
vb.memory = 2048
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "off"]
vb.customize ["modifyvm", :id, "--natdnsproxy1", "off"]
end
@@ -30,6 +31,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/home/vagrant/src/github.com/weaveworks/weave"
# Set SSH keys up to be able to run smoke tests straightaway:
config.vm.provision "file", source: "~/.vagrant.d/insecure_private_key", destination: "/home/vagrant/src/github.com/weaveworks/weave/test/insecure_private_key"
install_build_deps config.vm, pkgs
install_go_toochain config.vm
tweak_user_env config.vm
+22
View File
@@ -0,0 +1,22 @@
package api
import (
"fmt"
"net/url"
)
func (client *Client) DNSDomain() (string, error) {
return client.httpVerb("GET", "/domain", nil)
}
func (client *Client) RegisterWithDNS(ID string, fqdn string, ip string) error {
data := url.Values{}
data.Add("fqdn", fqdn)
_, err := client.httpVerb("PUT", fmt.Sprintf("/name/%s/%s", ID, ip), data)
return err
}
func (client *Client) DeregisterWithDNS(ID string, ip string) error {
_, err := client.httpVerb("DELETE", fmt.Sprintf("/name/%s/%s", ID, ip), nil)
return err
}
+72
View File
@@ -0,0 +1,72 @@
package api
import (
"fmt"
"net"
)
// Special token used in place of a container identifier when:
// - the caller does not know the container ID, or
// - the caller is unsure whether IPAM was previously told the container ID.
//
// While addresses are typically stored under their container IDs, when this
// token is used, the address will be stored under its own string, something
// which should be kept in mind if the entry needs to be removed at any point.
const NoContainerID string = "_"
func (client *Client) ipamOp(ID string, op string) (*net.IPNet, error) {
ip, err := client.httpVerb(op, fmt.Sprintf("/ip/%s", ID), nil)
if err != nil {
return nil, err
}
return parseIP(ip)
}
// returns an IP for the ID given, allocating a fresh one if necessary
func (client *Client) AllocateIP(ID string) (*net.IPNet, error) {
return client.ipamOp(ID, "POST")
}
func (client *Client) AllocateIPInSubnet(ID string, subnet *net.IPNet) (*net.IPNet, error) {
ip, err := client.httpVerb("POST", fmt.Sprintf("/ip/%s/%s", ID, subnet), nil)
if err != nil {
return nil, err
}
return parseIP(ip)
}
// returns an IP for the ID given, or nil if one has not been
// allocated
func (client *Client) LookupIP(ID string) (*net.IPNet, error) {
return client.ipamOp(ID, "GET")
}
// Claim a specific IP on behalf of the ID
func (client *Client) ClaimIP(ID string, cidr *net.IPNet) error {
_, err := client.httpVerb("PUT", fmt.Sprintf("/ip/%s/%s", ID, cidr), nil)
return err
}
// release all IPs owned by an ID
func (client *Client) ReleaseIPsFor(ID string) error {
_, err := client.httpVerb("DELETE", fmt.Sprintf("/ip/%s", ID), nil)
return err
}
func (client *Client) DefaultSubnet() (*net.IPNet, error) {
cidr, err := client.httpVerb("GET", fmt.Sprintf("/ipinfo/defaultsubnet"), nil)
if err != nil {
return nil, err
}
_, ipnet, err := net.ParseCIDR(cidr)
return ipnet, err
}
func parseIP(body string) (*net.IPNet, error) {
ip, ipnet, err := net.ParseCIDR(string(body))
if err != nil {
return nil, err
}
ipnet.IP = ip
return ipnet, nil
}
+82
View File
@@ -0,0 +1,82 @@
package api
import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
const (
WeaveHTTPHost = "127.0.0.1"
WeaveHTTPPort = 6784
)
type Client struct {
baseURL string
log Logger
}
func (client *Client) httpVerb(verb string, url string, values url.Values) (string, error) {
url = client.baseURL + url
client.log.Debugf("weave %s to %s with %v", verb, url, values)
var body io.Reader
if values != nil {
body = strings.NewReader(values.Encode())
}
req, err := http.NewRequest(verb, url, body)
if err != nil {
return "", err
}
if values != nil {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
rbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNoContent {
return string(rbody), nil
}
return "", errors.New(resp.Status + ": " + string(rbody))
}
func NewClient(addr string, log Logger) *Client {
host := WeaveHTTPHost
port := fmt.Sprintf("%d", WeaveHTTPPort)
switch parts := strings.Split(addr, ":"); len(parts) {
case 0:
case 1:
if parts[0] != "" {
host = parts[0]
}
case 2:
if parts[0] != "" {
host = parts[0]
}
if parts[1] != "" {
port = parts[1]
}
default:
return &Client{baseURL: fmt.Sprintf("http://%s", addr), log: log}
}
return &Client{baseURL: fmt.Sprintf("http://%s:%s", host, port), log: log}
}
func (client *Client) Connect(remote string) error {
_, err := client.httpVerb("POST", "/connect", url.Values{"peer": {remote}})
return err
}
type Logger interface {
Infof(string, ...interface{})
Debugf(string, ...interface{})
}
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
set -e
echo "TEST_AND_PUBLISH=1" > "$STATE"
# Avoid doing a full build if we can. Note if the PR doesn't exist
# when the build is kicked off, we can't run this check so we do a
# full build. Subsequent pushes to the same branch will have the desired behaviour
if [ -n "$CI_PULL_REQUEST" -a "$CI_PULL_REQUEST" = "$CI_PULL_REQUESTS" ] ; then
if PR=$(echo "$CI_PULL_REQUEST" | grep -oP '(?<=^https://github.com/weaveworks/weave/pull/)[0-9]+$') ; then
echo "GH_PR=$PR" >> "$STATE"
if FILES=$(curl -s https://api.github.com/repos/weaveworks/weave/pulls/$PR/files | jq -r '.[]|.filename') ; then
echo "PR touches [$FILES]"
if ! echo "$FILES" | grep -v ^site/ ; then
echo "PR contains site changes only - skipping tests"
echo "TEST_AND_PUBLISH=" >> "$STATE"
else
echo "PR contains non-site changes - running tests"
fi
else
echo "Unable to get files for PR $PR" >&2
fi
else
echo "Unable to extract PR number from $CI_PULL_REQUEST" >&2
fi
fi
source "$STATE"
mkdir -p $(dirname $SRCDIR) && cp -r $(pwd)/ $SRCDIR
if [ -n "$TEST_AND_PUBLISH" ] ; then
[ -z "$SECRET_PASSWORD" ] || bin/setup-circleci-secrets "$SECRET_PASSWORD"
cd $SRCDIR; git submodule update --init
if [ "$CIRCLE_NODE_INDEX" = "0" -a -n "$SECRET_PASSWORD" ] ; then
cd $SRCDIR/test; ./gce.sh make_template
fi
cd $SRCDIR/build
../tools/rebuild-image weaveworks/weavebuild . Dockerfile build.sh
touch $SRCDIR/.build.uptodate
sudo chown -R ubuntu /usr/local/go
cd $SRCDIR
make testrunner
make COVERAGE=true RM= exes all
fi
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
set -e
set -o pipefail
source "$STATE"
site_changes() {
curl -s https://api.github.com/repos/weaveworks/weave/pulls/$1/files |
jq -r '.[]|.status + " " + .filename' |
grep -oP '^(added|modified|removed) site/.*(?=\.md$)'
}
format_comment() {
if [ ! -d .git ] || ! BRANCH=$(git symbolic-ref --short HEAD) || [ -z "$BRANCH" ] ; then
echo "Could not determine branch" >&2
return 1
fi
echo "#### Documentation changes:"
while read ACTION PAGE; do
echo "$ACTION [${PAGE#site/}]($WP_DEV_URL/docs/net/${BRANCH#issues/}/${PAGE#site/}/)"
done | sort
}
post_comment() {
jq -s -R '. | tostring | { body: . }' |
curl -s -d @- \
-H "Authorization: Bearer $WP_GH_COMMENT_TOKEN" \
-H 'Content-Type: application/json' \
https://api.github.com/repos/weaveworks/weave/issues/$GH_PR/comments > /dev/null
}
cd $SRCDIR
bin/install-wordepress v1.0.0
bin/publish-site "$WP_DEV_URL" "$WP_DEV_USER" "$WP_DEV_PASSWORD"
if [ -n "$WP_GH_COMMENT_TOKEN" -a -n "$GH_PR" ] ; then
echo ">>> Adding doc changelog to GitHub PR $GH_PR"
if CHANGES=$(site_changes $GH_PR) && [ -n "$CHANGES" ] ; then
echo "$CHANGES" | format_comment | post_comment
fi
fi
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ] ; then
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
cd $SRCDIR
make clean-bin
# CircleCI doesn't let us install the qemu module to do ARM docker builds
make publish ALL_ARCHITECTURES=amd64 UPDATE_LATEST=latest-only
fi
cd $SRCDIR
bin/install-wordepress v1.0.0
bin/publish-site "$WP_DEV_URL" "$WP_DEV_USER" "$WP_DEV_PASSWORD"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
set -e
cd $SRCDIR
bin/install-wordepress v1.0.0
bin/publish-site "$WP_LIVE_URL" "$WP_LIVE_USER" "$WP_LIVE_PASSWORD"
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ] ; then
if [ "$CIRCLE_NODE_INDEX" = "0" ] ; then
go get github.com/mattn/goveralls
goveralls -repotoken $COVERALLS_REPO_TOKEN -coverprofile=$SRCDIR/test/profile.cov -service=circleci
cd $SRCDIR/test; cp coverage.* $CIRCLE_ARTIFACTS
fi
fi
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ] ; then
cd $SRCDIR/test
[ -z "$SECRET_PASSWORD" ] || (./gce.sh setup && eval $(./gce.sh hosts) && ./setup.sh)
fi
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ] ; then
[ -n "$SECRET_PASSWORD" ] || { echo "Cannot run smoke tests: no secret key"; exit 1; }
cd $SRCDIR/test
eval $(./gce.sh hosts)
export COVERAGE=true
export WEAVE_NET_SANITY_CHECKS_FILES="$CIRCLE_ARTIFACTS/weave_net_sanity_check_*.log"
./run_all.sh
fi
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ] ; then
cd $SRCDIR/test
[ -z "$SECRET_PASSWORD" ] || ./gce.sh destroy
test "$CIRCLE_NODE_INDEX" != "0" || (cd $SRCDIR/test; ./gen_coverage_reports.sh)
fi
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ] ; then
cd $SRCDIR
make DEBUG=1 lint
COVERDIR=test/coverage make RM= tests
fi
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
if [ $# -ne 1 ] ; then
echo USAGE: install-wordepress [COMMIT-ISH] >&2
exit 1
fi
go get github.com/weaveworks/wordepress
cd /home/ubuntu/src/github.com/weaveworks/wordepress
git checkout $1
cd cmd/wordepress
go get
+28 -14
View File
@@ -14,7 +14,8 @@ set -e
START=${FIRST_WEAVE:-1}
COUNT=${NUM_WEAVES:-28}
FINISH=$((START+COUNT-1))
PORT=6783
SUBNET=192.168.7
weavedir=$(dirname $0)/..
@@ -26,29 +27,42 @@ random_mac() {
od -txC -An -N6 /dev/urandom | ( read a b c d e f && printf "%02x:$b:$c:$d:$e:$f" $((0x$a & ~1 | 2)) )
}
weave() {
i=$1
shift
WEAVE_CONTAINER_NAME=weave$i WEAVE_HTTP_ADDR=$SUBNET.$i:6784 $weavedir/weave "$@"
}
case "$1" in
launch)
shift 1
echo $(date -R) launching
ip link show multiweave >/dev/null 2>&1 || sudo ip link add name multiweave type bridge
for i in $(seq $START $FINISH); do
WEAVE_CONTAINER_NAME=weave$i WEAVE_PORT=$((5000+i)) $weavedir/weave launch-router --iface '' --name $(random_mac) --nickname weave$i --port $PORT --no-dns "$@"
IP=$SUBNET.$i
sudo ip addr add $IP/24 dev multiweave
weave $i launch-router --datapath '' --iface '' --no-dns --host $IP \
--name $(random_mac) --nickname weave$i "$@"
done
if [ $START -ne 1 ] ; then
status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' weave$((START-1)))
PREV="${status#true }"
fi
echo $(date -R) connecting
[ $START -gt 1 ] || START=2
for i in $(seq $START $FINISH); do
if [ -n "$PREV" ] ; then
echo connecting weave$i to $PREV
WEAVE_CONTAINER_NAME=weave$i $weavedir/weave connect $PREV
fi
status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' weave$i)
PREV="${status#true }"
TO=$SUBNET.$((i-1))
echo connecting weave$i to $TO
weave $i connect $TO
done
echo $(date -R) done
;;
stop)
for i in $(seq $START $FINISH); do
for i in $(seq $FINISH -1 $START); do
IP=$SUBNET.$i
echo Stopping weave$i
WEAVE_CONTAINER_NAME=weave$i $weavedir/weave stop-router
weave $i stop-router
sudo ip addr del $IP/24 dev multiweave || true
done
[ -z "$(ip -4 -o addr show multiweave)" ] && sudo ip link del multiweave
;;
*)
weave "$@"
;;
esac
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
set -e
set -o pipefail
PRODUCT=net
fatal() {
echo "$@" >&2
exit 1
}
if [ ! -d .git ] ; then
fatal "Current directory is not a git clone"
fi
if ! BRANCH=$(git symbolic-ref --short HEAD) || [ -z "$BRANCH" ] ; then
fatal "Could not determine branch"
fi
case "$BRANCH" in
issues/*)
VERSION="${BRANCH#issues/}"
TAGS="$VERSION"
;;
*)
if echo "$BRANCH" | grep -qE '^[0-9]+\.[0-9]+' ; then
DESCRIBE=$(git describe --match 'v*')
if ! VERSION=$(echo "$DESCRIBE" | grep -oP '(?<=^v)[0-9]+\.[0-9]+\.[0-9]+') ; then
fatal "Could not infer latest $BRANCH version from $DESCRIBE"
fi
TAGS="latest"
else
VERSION="$BRANCH"
TAGS="$VERSION"
fi
;;
esac
for TAG in $TAGS ; do
echo ">>> Publishing $PRODUCT $VERSION to $1/docs/$PRODUCT/$TAG"
wordepress \
--url "$1" --user "$2" --password "$3" \
--product "$PRODUCT" --version "$VERSION" --tag "$TAG" \
publish site
done
+60 -4
View File
@@ -157,6 +157,28 @@ draft() {
--name "weave" \
--file "./weave"
github-release release $RELEASE_ARGS \
--user $GITHUB_USER \
--repo weave-kube \
--tag $LATEST_TAG \
--name "$RELEASE_NAME $VERSION" \
--description "$RELEASE_DESCRIPTION"
sed -i -e s/:latest/:$VERSION/ -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset.yaml
github-release upload \
--user $GITHUB_USER \
--repo weave-kube \
--tag $LATEST_TAG \
--name "weave-daemonset.yaml" \
--file "./prog/weave-kube/weave-daemonset.yaml"
github-release upload \
--user $GITHUB_USER \
--repo weave \
--tag $LATEST_TAG \
--name "weave-daemonset.yaml" \
--file "./prog/weave-kube/weave-daemonset.yaml"
echo "** Draft $TYPE $RELEASE_NAME $VERSION created at"
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG"
}
@@ -165,14 +187,14 @@ publish() {
setup
cd $PWD/$RELEASE_DIR
UPDATE_LATEST=false
IS_MAINLINE=false
if [ "$RELEASE_TYPE" = 'MAINLINE' ] ; then
UPDATE_LATEST=true
IS_MAINLINE=true
fi
if [ "$RELEASE_TYPE" = 'PRERELEASE' ] ; then
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
make UPDATE_LATEST=$UPDATE_LATEST SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER publish
make UPDATE_LATEST=$IS_MAINLINE SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER publish
echo "** Docker images tagged and pushed"
echo "== Publishing pre-release on GitHub"
@@ -204,7 +226,7 @@ publish() {
echo '** Sanity checks OK for publishing tag' $LATEST_TAG as $DOCKERHUB_USER/weave:$VERSION
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
make UPDATE_LATEST=$UPDATE_LATEST SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER publish
make PUBLISH_WEAVEDB=$IS_MAINLINE UPDATE_LATEST=$IS_MAINLINE SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER publish
echo "** Docker images tagged and pushed"
echo "== Publishing release on GitHub"
@@ -236,6 +258,40 @@ publish() {
--name "weave" \
--file "./weave"
github-release publish \
--user $GITHUB_USER \
--repo weave-kube \
--tag $LATEST_TAG
if github-release info --user $GITHUB_USER --repo weave-kube \
--tag latest_release >/dev/null 2>&1; then
github-release delete \
--user $GITHUB_USER \
--repo weave-kube \
--tag latest_release
fi
github-release release \
--user $GITHUB_USER \
--repo weave-kube \
--tag latest_release \
--name "$RELEASE_NAME latest ($VERSION)" \
--description "[Release Notes](https://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG)"
github-release upload \
--user $GITHUB_USER \
--repo weave-kube \
--tag latest_release \
--name "weave-daemonset.yaml" \
--file "./prog/weave-kube/weave-daemonset.yaml"
github-release upload \
--user $GITHUB_USER \
--repo weave \
--tag latest_release \
--name "weave-daemonset.yaml" \
--file "./prog/weave-kube/weave-daemonset.yaml"
echo "** Release $RELEASE_NAME $VERSION published at"
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG"
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/latest_release"
-57
View File
@@ -1,57 +0,0 @@
#!/bin/sh
## This is the shape of unencrypted `do-setup-ci-secrets`
##
## cat > /tmp/boto_gsutil_cert.pem << EOF
## -----BEGIN PRIVATE KEY-----
## <...>
## -----END PRIVATE KEY-----
## EOF
##
## cat > ~/.boto << EOF
## [Credentials]
## gs_service_client_id = <...>
## gs_service_key_file = /tmp/boto_gsutil_cert.pem
##
## [Boto]
## https_validate_certificates = True
##
## [GSUtil]
## content_language = en
## default_api_version = 2
## default_project_id = <...>
## EOF
openssl base64 -d << EOF \
| openssl aes-256-cbc -d -K $1 -iv $2 \
-out bin/do-setup-ci-secrets
mOYNzNsAdwva0LbB2YFMY9VgL0SITFu1bPrbOujyLtOrBNjmOYbzR5d/sG+ARMFr
7NZ5OKcvMbItllz0n7TtNkzkCOMztMC870Wcx3nGJzbBephdcYwos4tBlp5bihTU
AXgxLUiDT1broYAFKnbE1aZC/XyNxuLTN+nXJWIWeijaXTgvhkEEm3tab+z7ioCb
tlg71W1BrUuocctAJAuVwH/uTZAaXaJGJj1s2S7F2DrFnG6sFlrp8rnCucPLWKnC
4IwJFC5saR5gxK6wECffwmwbpeXVOoQ58OgzxoZTEyAr9nhVbaBt5UZz3tfHlx8W
Rn5jHehACw5kg5eMtGPqMEksJ63LX4h3mfSTLJXJHEmOrzCRpFrigVrsbA408U2u
8jJTHJmKrGfwBh5ZFzBg6NuV4VplOp+ZquJLgegv2WH/iu/ciopXqB2YDCdx5ZBi
nHV2Puth7kjS4EMCKUGfeqpesjL9Djb8cygzv/J3ZBmLjNH9dqlSXWy2DcFZA1Iy
pFTTHkVU3w5sNz3nYOuT2UPQvULBW0FUndDKX6olyVa0mlxPwGBP9N3yGg918/rw
7rNV/r54lA334F5QMhDrVxar6sl9wfLA+Z+8qemBbNFlLog1uQGhuwWK2nFu1tRM
9uyvQIq0oq5NHKpogWc7NEuk7CPe1JyfRIcbMVj8+ilmKjUPB2HPC43IDmKt9/56
rY3IXAcxZ/ClGfGpeNHXqop9T/WhfaowponOZFcdGSUddG0OswqkTE4KIv71mgTF
jXooMkTQBOG+gBnCe+8bCRdRCG3anxHX74za4dGD58cOJtl6DYWnjWuR91NWnxdT
1Zr3iUe41txg9hCNY9LHo2QHGLPxe6pmNnSClQ1mcFhuY6NF8RmCX3HAGKJQkxJb
vpLGbXTXjAIFgIYgLNgKP2RLvCif/LmSWgkvE3ZU9GXtCUbm6xgJodwOqXiI9uuO
4H4+/vpGHnSFENiclkgMFrLG4yiMu8ArgmnCBzg9E2AoOX5zCrh/2ZRTU8Dk4mt7
jUd5SKQLsjB9QtB+y3tRO7zY9RDvR6iBOPRsjx6t8EJMCfPb06KchfMJw+VGxvMM
48jtmepREFnhd/8XDRGnw5bznjRuwohGik8BToltjIviMkkpifKWaLwlaOiDXaHh
VBFNXnUKvOBwRMU+PZqv4+DP2qff1gSXnGKqA5GIURYrK9P7TqHHNTnmjBdfJLzc
0x+W1DTiYhLT2vrLrkEpZ99o6qrg+lwvjat6IsJF8xoQEo4pLD/ZRPJ0WzoDyctT
oWZ5rMsN1TzTvJrBrTAWIJyhIzZcuNwChMrU6qogMr0fd6TSxWhWn0sOJ5y8AaTR
ej4JHx0qroS/9JPmgFYU61pX3c0ypdef/sSHWG23mcFzLTgwe2d4ty9VakypZy3T
sXCl6EHVVXlUFWhY4zQCjdZpYJv/rtoKL1BL4fPE2NV5WTjCL2GNvaO5SfHR7pA0
yQJR/iU+cS2n8UXsWNjyV+/qEn6+QXuyVHGLbxyH8EeqlliAbyHsc2rzVI8Xctzo
W5DuIqxwHAkNNurhmx27ktIIQ6HhaCp028SWwvLttkbBBgF4v1mmd4u/2bKbKjUd
dOaetaIUx1hU9OAeaePvVkeTDcc3mlFtPARCS9Fqj16hgJQ43onZyC0H1K2WAxmU
GsmzjCHlTNquzFTuuQihYGZKfsWIh9z6HEOkvNJ3VEQ=
EOF
exec sh bin/do-setup-ci-secrets
+72 -17
View File
@@ -1,24 +1,79 @@
FROM ubuntu
FROM golang:1.7.4
RUN apt-get -y update && apt-get -y install --no-install-recommends ca-certificates apt-transport-https
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
RUN echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list
RUN apt-get -y update && apt-get -y install --no-install-recommends build-essential git lxc-docker-1.3.1 mercurial libpcap-dev curl make pkg-config gcc bison flex python-requests
# Support Raspberry Pi 2 and newer
ENV GOARM 7
# When doing a build in a container, "apt-get update" happens twice,
# which can be a very significant overhead for incremental builds.
# And it's unnecessary, because if any of the prerequisites do change,
# the right thing to do is to rebuild the container image. Rather
# than suppressing the "apt-get update" commands explicitly, we clear
# out sources.list so that 'apt-get update' doesn't do anything.
RUN echo >/etc/apt/sources.list
# The names of the architectures that we're fetching cross-compilers for from the Ubuntu packages
ENV DEB_CROSSPLATFORMS \
armhf \
arm64
ENV GO_VERSION 1.4.2
RUN curl -sSL https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz | tar -C /usr/local -xz
ENV PATH /usr/local/go/bin:$PATH
# The go platforms we are supporting to cross-compile
ENV GO_CROSSPLATFORMS \
linux/arm \
linux/arm64
# So that sudo does not trample on PATH
RUN sed -ie '/secure_path/d' /etc/sudoers
# The names of the gcc cross-compilers we have installed
ENV GCC_CROSSCOMPILERS \
arm-linux-gnueabihf \
aarch64-linux-gnu
# Temporarily add the Ubuntu repositories, because we're going to install gcc cross-compilers from there
# Install the build-essential and crossbuild-essential-ARCH packages
RUN echo "deb http://archive.ubuntu.com/ubuntu xenial main universe" > /etc/apt/sources.list.d/cgocrosscompiling.list \
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5 3B4FE6ACC0B21F32 \
&& apt-get update \
&& apt-get install -y build-essential \
&& for platform in ${DEB_CROSSPLATFORMS}; do apt-get install -y crossbuild-essential-${platform}; done \
&& rm /etc/apt/sources.list.d/cgocrosscompiling.list \
&& apt-get update \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Install some required packages
# libpcap is required because we're linking against its C libraries from the prog/weaver binary
# flex and bison are required packages for compiling libpcap manually later
RUN apt-get update \
&& apt-get install -y \
libpcap-dev \
python-requests \
time \
file \
flex \
bison
# Install common Go tools
RUN go get \
github.com/golang/lint/golint \
github.com/fzipp/gocyclo \
github.com/client9/misspell/cmd/misspell
# First clean, because we're gonna rebuild the std both with -race enabled and disabled
# Running go install std twice is intentional and required, as content is written in two different directories
# (/usr/local/go/pkg/linux_amd64 vs /usr/local/go/pkg/linux_amd64_race)
# The other architectures do not have support for -race
RUN go clean -i net \
&& go install -tags netgo std \
&& go install -race -tags netgo std
# Prebuild std for the other architectures
RUN for platform in ${GO_CROSSPLATFORMS}; do \
GOOS=${platform%/*} GOARCH=${platform##*/} \
go install -tags netgo std; done
# The libpcap version from Debian packages is 1.6.2, matching that version here although newer versions of libpcap have been released
# We have to cross-compile the libpcap library for the new architectures, that's what we're doing here
ENV LIBPCAP_CROSS_VERSION=1.6.2
RUN curl -sSL http://www.tcpdump.org/release/libpcap-${LIBPCAP_CROSS_VERSION}.tar.gz | tar -xz \
&& cd libpcap-${LIBPCAP_CROSS_VERSION} \
&& for crosscompiler in ${GCC_CROSSCOMPILERS}; do \
CC=${crosscompiler}-gcc ac_cv_linux_vers=2 ./configure --host=${crosscompiler} --with-pcap=linux \
&& make \
&& export LIB_DIR="/usr/local/lib/${crosscompiler}-gcc" VER="$(cat ./VERSION)" MAJOR_VER="$(sed 's/\([0-9][0-9]*\)\..*/\1/' ./VERSION)" \
&& mkdir -p ${LIB_DIR} \
&& cp -f libpcap.a libpcap.so.${VER} ${LIB_DIR} \
&& ln -sf libpcap.so.${VER} /usr/local/lib/libpcap.so.${MAJOR_VER} \
&& ln -sf libpcap.so.${MAJOR_VER} /usr/local/lib/libpcap.so \
&& make clean; done
COPY build.sh /
ENTRYPOINT ["sh", "/build.sh"]
+22 -36
View File
@@ -1,45 +1,31 @@
#!/bin/sh
set -e
GOPATH=/home/go
export GOPATH
set -eu
WEAVE_SRC=$GOPATH/src/github.com/weaveworks/weave
if [ $# -eq 0 -o "$1" = "tests" ] ; then
# No arguments. Expect that the weave repo will be bind-mounted
# into $GOPATH
if ! [ -e $WEAVE_SRC ] ; then
cat 2>&1 <<EOF
No container arguments supplied, and nothing at ${WEAVE_SRC}. Please
either bind-mount the golang workspace containing weave with the
if ! [ -e $WEAVE_SRC ] ; then
cat 2>&1 <<EOF
Nothing at ${WEAVE_SRC}. Please bind-mount the weave repo with the
docker run -v option, e.g.:
$ docker run -v <host gopath>:${GOPATH} \\
-v /var/run/docker.sock:/var/run/docker.sock weaveworks/weave-build
Or supply git clone arguments to retrieve it, e.g.:
$ docker run -v /var/run/docker.sock:/var/run/docker.sock \\
weaveworks/weave-build https://github.com/weaveworks/weave.git
$ cd weave
$ docker run -v $(pwd):/go/src/github.com/weaveworks/weave \\
weaveworks/weave-build
EOF
exit 1
fi
# If we run make directly, any files created on the bind mount
# will have awkward ownership. So we switch to a user with the
# same user and group IDs as source directory. We have to set a
# few things up so that sudo works without complaining later on.
uid=$(stat --format="%u" $WEAVE_SRC)
gid=$(stat --format="%g" $WEAVE_SRC)
echo "weave:x:$uid:$gid::$WEAVE_SRC:/bin/sh" >>/etc/passwd
echo "weave:*:::::::" >>/etc/shadow
echo "weave ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
su weave -c "PATH=$PATH make -C $WEAVE_SRC build"
else
# There are arguments to pass to git-clone
mkdir -p ${WEAVE_SRC%/*}
git clone "$@" $WEAVE_SRC
make -C $WEAVE_SRC build
fi
# If we run make directly, any files created on the bind mount
# will have awkward ownership. So we switch to a user with the
# same user and group IDs as source directory. We have to set a
# few things up so that sudo works without complaining later on.
uid=$(stat --format="%u" $WEAVE_SRC)
gid=$(stat --format="%g" $WEAVE_SRC)
echo "weave:x:$uid:$gid::$WEAVE_SRC:/bin/sh" >>/etc/passwd
echo "weave:*:::::::" >>/etc/shadow
echo "weave ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
# Allow full write access to the Go folders for the user Weave
chown -R $uid:$gid /usr/local/go
su weave -c "PATH=$PATH make -C $WEAVE_SRC BUILD_IN_CONTAINER=false $*"
+1
View File
@@ -0,0 +1 @@
8f313a9df867c207ae9ceac6e0935d1d2a0360aafce780dd5d1e0687ee98e0c3 docker-1.10.3.tgz
@@ -0,0 +1 @@
7541b5490cee1183d911f909c0e91d3d9d57b2b775e40f14a1a7a6de216ca4a8 docker-1.10.3.tgz
@@ -0,0 +1 @@
c02d861383d035ba020b361ef93bf14beb3964a42a6ae645b505b6148493e7ec qemu-aarch64-static
+1
View File
@@ -0,0 +1 @@
0ff63682b8868620d771aa812d3053dc3c579dc8633ce62d3d7ae7eee83beb06 qemu-arm-static
+24 -39
View File
@@ -2,72 +2,57 @@ general:
branches:
ignore:
- gh\-pages
- /pull\/.*/
machine:
pre:
- curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0
services:
- docker
environment:
GOPATH: /home/ubuntu:$GOPATH
SRCDIR: /home/ubuntu/src/github.com/weaveworks/weave
PATH: $PATH:$HOME/.local/bin:$HOME/google-cloud-sdk/bin/
PATH: $PATH:$HOME/.local/bin
CLOUDSDK_CORE_DISABLE_PROMPTS: 1
WEAVE_TEST: $HOME/docker/weave-test.tar
STATE: /home/ubuntu/state.env
dependencies:
cache_directories:
- "~/docker"
override:
- if [[ -e "$WEAVE_TEST" ]]; then
docker load -i $WEAVE_TEST;
else
docker build -t weaveworks/weave-build build;
docker build -t weaveworks/weave-test test/image;
mkdir -p $(dirname "$WEAVE_TEST");
docker save weaveworks/weave-test >$WEAVE_TEST;
fi
post:
- sudo apt-get update && sudo apt-get install bc jq && pip install requests
- curl https://sdk.cloud.google.com | bash
- bin/setup-circleci-secrets "$SECRET_PASSWORD"
- mkdir -p $(dirname $SRCDIR) && cp -r $(pwd)/ $SRCDIR
- cd $SRCDIR/test; ./gce.sh make_template:
parallel: false
- bin/circle-dependencies-post
test:
pre:
- "$SRCDIR/bin/circle-test-pre":
parallel: true
override:
- cd $SRCDIR; make lint:
- "$SRCDIR/bin/circle-test-unit":
parallel: true
- docker run -v /home/ubuntu:/home/go -e COVERDIR=test/coverage -e SLOW=true -e CIRCLECI -e CIRCLE_BUILD_NUM -e CIRCLE_NODE_TOTAL -e CIRCLE_NODE_INDEX weaveworks/weave-test:
parallel: true
- docker run -v /var/run/docker.sock:/run/docker.sock -v /home/ubuntu:/home/go -e COVERAGE=true weaveworks/weave-build:
parallel: true
- cd $SRCDIR/test; ./gce.sh setup && eval $(./gce.sh hosts) && ./setup.sh:
parallel: true
- cd $SRCDIR/test; eval $(./gce.sh hosts); export COVERAGE=true; ./run_all.sh:
- "$SRCDIR/bin/circle-test-smoke":
parallel: true
timeout: 300
- cd $SRCDIR; make clean-bin:
parallel: true
- docker run -v /var/run/docker.sock:/run/docker.sock -v /home/ubuntu:/home/go weaveworks/weave-build:
parallel: true
post:
- cd $SRCDIR/test; ./gce.sh destroy:
- "$SRCDIR/bin/circle-test-teardown":
parallel: true
teardown:
pre:
- test "$CIRCLE_NODE_INDEX" != "0" || (cd $SRCDIR/test; ./gen_coverage_reports.sh):
parallel: true
- test "$CIRCLE_NODE_INDEX" != "0" || (go get github.com/mattn/goveralls && goveralls -repotoken $COVERALLS_REPO_TOKEN -coverprofile=$SRCDIR/test/profile.cov -service=circleci || true):
parallel: true
- test "$CIRCLE_NODE_INDEX" != "0" || (cd $SRCDIR/test; cp coverage.* $CIRCLE_ARTIFACTS):
- "$SRCDIR/bin/circle-teardown-pre":
parallel: true
deployment:
hub:
release:
branch: /[0-9]+\.[0-9]+/
owner: weaveworks
commands:
- "$SRCDIR/bin/circle-deploy-release"
master:
branch: master
owner: weaveworks
commands:
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- cd $SRCDIR; make publish
- "$SRCDIR/bin/circle-deploy-master"
issues:
branch: /.*/
owner: weaveworks
commands:
- "$SRCDIR/bin/circle-deploy-issues"
+162 -24
View File
@@ -1,82 +1,220 @@
package docker
import (
"github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
"errors"
"fmt"
"strings"
"time"
docker "github.com/fsouza/go-dockerclient"
"github.com/weaveworks/weave/common"
)
const (
InitialInterval = 1 * time.Second
MaxInterval = 20 * time.Second
)
// An observer for container events
type ContainerObserver interface {
ContainerStarted(ident string)
ContainerDied(ident string)
ContainerDestroyed(ident string)
}
type Client struct {
*docker.Client
}
type syncPair struct {
stop chan struct{}
done chan struct{}
}
type pendingStarts map[string]*syncPair
// NewClient creates a new Docker client and checks we can talk to Docker
func NewClient(apiPath string) (*Client, error) {
if apiPath != "" && !strings.Contains(apiPath, "://") {
apiPath = "tcp://" + apiPath
}
dc, err := docker.NewClient(apiPath)
if err != nil {
return nil, err
}
client := &Client{dc}
return client, client.checkWorking(apiPath)
return client, client.checkWorking()
}
func NewVersionedClient(apiPath string, apiVersionString string) (*Client, error) {
if !strings.Contains(apiPath, "://") {
apiPath = "tcp://" + apiPath
}
dc, err := docker.NewVersionedClient(apiPath, apiVersionString)
if err != nil {
return nil, err
}
client := &Client{dc}
return client, client.checkWorking(apiPath)
return client, client.checkWorking()
}
func (c *Client) checkWorking(apiPath string) error {
func NewVersionedClientFromEnv(apiVersionString string) (*Client, error) {
dc, err := docker.NewVersionedClientFromEnv(apiVersionString)
if err != nil {
return nil, err
}
client := &Client{dc}
return client, client.checkWorking()
}
func (c *Client) checkWorking() error {
_, err := c.Version()
return err
}
func (c *Client) Info() string {
env, err := c.Version()
if err != nil {
return err
return fmt.Sprintf("Docker API error: %s", err)
}
Log.Infof("[docker] Using Docker API on %s: %v", apiPath, env)
return nil
return fmt.Sprintf("Docker API on %s: %v", c.Endpoint(), env)
}
func (c *Client) DockerVersion() string {
if env, err := c.Version(); err == nil {
if v, found := env.Map()["Version"]; found {
return v
}
}
return "unknown"
}
// AddObserver adds an observer for docker events
func (c *Client) AddObserver(ob ContainerObserver) error {
events := make(chan *docker.APIEvents)
if err := c.AddEventListener(events); err != nil {
Log.Errorf("[docker] Unable to add listener to Docker API: %s", err)
return err
}
go func() {
for event := range events {
switch event.Status {
case "start":
id := event.ID
ob.ContainerStarted(id)
case "die":
id := event.ID
ob.ContainerDied(id)
pending := make(pendingStarts)
retryInterval := InitialInterval
for {
events := make(chan *docker.APIEvents)
if err := c.AddEventListener(events); err != nil {
c.errorf("Unable to add listener to Docker API: %s - retrying in %ds", err, retryInterval/time.Second)
} else {
start := time.Now()
for event := range events {
switch event.Status {
case "start":
pending.finish(event.ID)
pending.start(event.ID, c, ob)
case "die":
pending.finish(event.ID)
ob.ContainerDied(event.ID)
case "destroy":
pending.finish(event.ID)
ob.ContainerDestroyed(event.ID)
}
}
if time.Since(start) > retryInterval {
retryInterval = InitialInterval
}
c.errorf("Event listener channel closed - retrying subscription in %ds", retryInterval/time.Second)
}
time.Sleep(retryInterval)
retryInterval = retryInterval * 3 / 2
if retryInterval > MaxInterval {
retryInterval = MaxInterval
}
}
}()
return nil
}
// Docker sends a 'start' event before it has attempted to start the
// container. Delay notifying the observer until the container has a
// pid, or we are told to stop when a 'die' event arrives.
//
// Note we always deliver the event, even if the container seems to
// have gone away.
func (pending pendingStarts) start(id string, c *Client, ob ContainerObserver) {
sync := syncPair{make(chan struct{}), make(chan struct{})}
pending[id] = &sync
go func() {
defer close(sync.done)
defer ob.ContainerStarted(id)
for {
if container, err := c.InspectContainer(id); err != nil || container.State.Pid != 0 {
return
}
select {
case <-sync.stop:
return
case <-time.After(200 * time.Millisecond):
}
}
}()
}
func (pending pendingStarts) finish(id string) {
if sync, found := pending[id]; found {
close(sync.stop)
<-sync.done
delete(pending, id)
}
}
func (c *Client) AllContainerIDs() ([]string, error) {
all, err := c.ListContainers(docker.ListContainersOptions{All: true})
if err != nil {
return nil, err
}
var ids []string
for _, c := range all {
ids = append(ids, c.ID)
}
return ids, nil
}
// IsContainerNotRunning returns true if we have checked with Docker that the ID is not running
func (c *Client) IsContainerNotRunning(idStr string) bool {
container, err := c.InspectContainer(idStr)
if err == nil {
return !container.State.Running
return !container.State.Running || container.State.Restarting
}
if _, notThere := err.(*docker.NoSuchContainer); notThere {
return true
}
Log.Errorf("[docker] Could not check container status: %s", err)
c.errorf("Could not check container status: %s", err)
return false
}
// This is intended to find an IP address that we can reach the container on;
// if it is on the Docker bridge network then that address; if on the host network
// then localhost
func (c *Client) GetContainerIP(nameOrID string) (string, error) {
info, err := c.InspectContainer(nameOrID)
if err != nil {
return "", err
}
if info.NetworkSettings.Networks != nil {
if bridgeNetwork, ok := info.NetworkSettings.Networks["bridge"]; ok {
return bridgeNetwork.IPAddress, nil
} else if _, ok := info.NetworkSettings.Networks["host"]; ok {
return "127.0.0.1", nil
}
} else if info.HostConfig.NetworkMode == "host" {
return "127.0.0.1", nil
}
if info.NetworkSettings.IPAddress == "" {
return "", errors.New("No IP address found for container " + nameOrID)
}
return info.NetworkSettings.IPAddress, nil
}
// logging
func (c *Client) errorf(fmt string, args ...interface{}) {
common.Log.Errorf("[docker] "+fmt, args...)
}
+18
View File
@@ -0,0 +1,18 @@
package common
import (
"net/http"
)
type loggingHandler struct {
next http.Handler
}
func (l *loggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Log.Debugf("[http] %s %s", r.Method, r.URL.RequestURI())
l.next.ServeHTTP(w, r)
}
func LoggingHTTPHandler(h http.Handler) http.Handler {
return &loggingHandler{next: h}
}
+21
View File
@@ -3,6 +3,7 @@ package common
import (
"bytes"
"fmt"
"log"
"strings"
"github.com/Sirupsen/logrus"
@@ -64,3 +65,23 @@ func CheckWarn(e error) {
Log.Warnln(e)
}
}
// Adaptor type to go from Logrus to something expecting a standard library log.Logger
type logLogger struct {
logger *logrus.Logger
}
// io.Writer interface
func (l logLogger) Write(p []byte) (n int, err error) {
ln := len(p)
// Strip a trailing newline, because logrus formatter adds one
if ln > 0 && p[ln-1] == '\n' {
p = p[:ln-1]
}
l.logger.Info(string(p))
return ln, nil
}
func LogLogger() *log.Logger {
return log.New(logLogger{Log}, "", 0)
}
-31
View File
@@ -1,31 +0,0 @@
package mflagext
import (
"fmt"
"github.com/docker/docker/pkg/mflag"
)
type listOpts struct {
value *[]string
hasBeenSet bool
}
func ListVar(p *[]string, names []string, value []string, usage string) {
*p = value
mflag.Var(&listOpts{p, false}, names, usage)
}
func (opts *listOpts) Set(value string) error {
if opts.hasBeenSet {
(*opts.value) = append((*opts.value), value)
} else {
(*opts.value) = []string{value}
opts.hasBeenSet = true
}
return nil
}
func (opts *listOpts) String() string {
return fmt.Sprintf("%v", []string(*opts.value))
}
+15 -17
View File
@@ -10,49 +10,50 @@ import (
// ODP admin functionality
func CreateDatapath(dpname string) (err error, supported bool) {
func CreateDatapath(dpname string) (supported bool, err error) {
dpif, err := odp.NewDpif()
if err != nil {
if odp.IsKernelLacksODPError(err) {
return nil, false
return false, nil
}
return err, true
return true, err
}
defer dpif.Close()
dp, err := dpif.CreateDatapath(dpname)
if err != nil && !odp.IsDatapathNameAlreadyExistsError(err) {
return err, true
if err != nil {
if !odp.IsDatapathNameAlreadyExistsError(err) {
return true, err
}
if dp, err = dpif.LookupDatapath(dpname); err != nil {
return true, err
}
}
// Pick an ephemeral port number to use in probing for vxlan
// support.
udpconn, err := net.ListenUDP("udp4", nil)
if err != nil {
return err, true
return true, err
}
defer udpconn.Close()
// we leave the UDP socket open, so creating a vxlan vport on
// the same port number should fail. But that's fine: It's
// still sufficient to probe for support.
portno := uint16(udpconn.LocalAddr().(*net.UDPAddr).Port)
vpid, err := dp.CreateVport(odp.NewVxlanVportSpec(
fmt.Sprintf("vxlan-%d", portno), portno))
vpid, err := dp.CreateVport(odp.NewVxlanVportSpec(fmt.Sprintf("vxlan-%d", portno), portno))
if nlerr, ok := err.(odp.NetlinkError); ok {
if syscall.Errno(nlerr) == syscall.EAFNOSUPPORT {
dp.Delete()
return fmt.Errorf("kernel does not have Open vSwitch VXLAN support"), false
return false, fmt.Errorf("kernel does not have Open vSwitch VXLAN support")
}
}
if err == nil {
dp.DeleteVport(vpid)
}
udpconn.Close()
return nil, true
return true, nil
}
func DeleteDatapath(dpname string) error {
@@ -60,7 +61,6 @@ func DeleteDatapath(dpname string) error {
if err != nil {
return err
}
defer dpif.Close()
dp, err := dpif.LookupDatapath(dpname)
@@ -68,7 +68,6 @@ func DeleteDatapath(dpname string) error {
if odp.IsNoSuchDatapathError(err) {
return nil
}
return err
}
@@ -80,7 +79,6 @@ func AddDatapathInterface(dpname string, ifname string) error {
if err != nil {
return err
}
defer dpif.Close()
dp, err := dpif.LookupDatapath(dpname)
+27
View File
@@ -0,0 +1,27 @@
package common
import (
"os"
"strconv"
)
func AllPids(procRoot string) ([]int, error) {
fh, err := os.Open(procRoot)
if err != nil {
return nil, err
}
defer fh.Close()
dirNames, err := fh.Readdirnames(-1)
if err != nil {
return nil, err
}
pids := make([]int, len(dirNames))
for _, dirName := range dirNames {
pid, err := strconv.Atoi(dirName)
if err != nil { // Only interested in numeric entries - skip /proc/stat, etc.
continue
}
pids = append(pids, pid)
}
return pids, err
}
-32
View File
@@ -1,32 +0,0 @@
package common
import (
"os"
"os/signal"
"runtime"
"syscall"
)
// A subsystem/server/... that can be stopped or queried about the status with a signal
type SignalReceiver interface {
Stop() error
}
func SignalHandlerLoop(ss ...SignalReceiver) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
buf := make([]byte, 1<<20)
for {
switch <-sigs {
case syscall.SIGINT, syscall.SIGTERM:
Log.Infof("=== received SIGINT/SIGTERM ===\n*** exiting")
for _, subsystem := range ss {
subsystem.Stop()
}
return
case syscall.SIGQUIT:
stacklen := runtime.Stack(buf, true)
Log.Infof("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end", buf[:stacklen])
}
}
}
+1 -3
View File
@@ -1,8 +1,6 @@
package common
import (
"strings"
)
import "strings"
// Assert test is true, panic otherwise
func Assert(test bool) {
+109
View File
@@ -0,0 +1,109 @@
package db
import (
"bytes"
"encoding/gob"
"fmt"
"time"
"github.com/boltdb/bolt"
)
type DB interface {
Load(string, interface{}) (bool, error)
Save(string, interface{}) error
}
type BoltDB struct {
db *bolt.DB
}
var (
versionIdent = []byte("version")
persistenceVersion = []byte{1, 0} // major.minor
topBucket = []byte("top")
)
const (
NameIdent = "peername"
FileName = "data.db"
)
func NewBoltDB(dbPathname string) (*BoltDB, error) {
db, err := bolt.Open(dbPathname, 0660, nil)
if err != nil {
return nil, fmt.Errorf("[boltDB] Unable to open %s: %s", dbPathname, err)
}
err = db.Update(checkVersion(false))
return &BoltDB{db: db}, err
}
func NewBoltDBReadOnly(dbPathname string) (*BoltDB, error) {
options := bolt.Options{Timeout: time.Millisecond * 50, ReadOnly: true}
db, err := bolt.Open(dbPathname, 0660, &options)
if err != nil {
return nil, fmt.Errorf("[boltDB] Unable to open %s: %s", dbPathname, err)
}
err = db.View(checkVersion(true))
if err != nil {
return nil, fmt.Errorf("[boltDB] Cannot use persistence file %s: %s", dbPathname, err)
}
return &BoltDB{db: db}, nil
}
func checkVersion(readOnly bool) func(tx *bolt.Tx) error {
return func(tx *bolt.Tx) error {
if top := tx.Bucket(topBucket); top == nil {
if readOnly {
return fmt.Errorf("no top bucket")
}
top, err := tx.CreateBucket(topBucket)
if err != nil {
return err
}
if err := top.Put(versionIdent, persistenceVersion); err != nil {
return err
}
} else {
if checkVersion := top.Get(versionIdent); checkVersion != nil {
if checkVersion[0] != persistenceVersion[0] {
return fmt.Errorf("mismatched version %x", checkVersion)
}
}
}
return nil
}
}
func (d *BoltDB) Load(ident string, data interface{}) (bool, error) {
found := true
err := d.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(topBucket)
v := b.Get([]byte(ident))
if v == nil {
found = false
return nil
}
reader := bytes.NewReader(v)
decoder := gob.NewDecoder(reader)
err := decoder.Decode(data)
return err
})
return found, err
}
func (d *BoltDB) Save(ident string, data interface{}) error {
return d.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(topBucket)
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
if err := enc.Encode(data); err != nil {
return err
}
return b.Put([]byte(ident), buf.Bytes())
})
}
func (d *BoltDB) Close() error {
return d.db.Close()
}
+154
View File
@@ -0,0 +1,154 @@
This document describes implementation details of the fast datapath encryption.
# Overview
At the high level, we use the ESP protocol ([RFC 2406][esp]) in the Transport
mode. Each packet is encrypted with AES in GCM mode ([RFC 4106][aesgcm]), with
32byte key and 4byte salt. This combo provides the following security
properties:
* Data confidentiality.
* Data origin authentication.
* Integrity.
* Anti-replay service.
* Limited traffic flow confidentiality.
## Notation
* `SAin`: IPsec security association for inbound connections.
* `SAout`: IPsec security association for outbound connections.
* `SPout`: IPsec security policy for outbound connections. Used to match
outbound flows to SAout.
## SA Key Derivation
For each connection direction, a different AES-GCM key and salt is used.
The pairs are derived with HKDF ([RFC 5869][hkdf]):
```
SAin[KeyAndSalt] = HKDF(sha256, ikm=sessionKey, salt=nonceIn, info=localPeerName)
SAout[KeyAndSalt] = HKDF(sha256, ikm=sessionKey, salt=nonceOut, info=remotePeerName)
```
Where:
* the mutual `sessionKey` is derived by the [Mesh][mesh] library during
the control plane connection establishment between the local peer and
the remote peer.
* `nonceIn` and `nonceOut` are randomly generated 32byte nonces which
are exchanged over the encrypted control plane channel.
## SPI
A directional secure connection between two peers is identified with SPI.
The kernel requires the pair of SPI and dst IP to be unique among security
associations. Thus, to avoid collisions, we generate outbound SPI on a remote
peer.
## Connection Establishment
```
Peer A Peer B
-----------------------------------------------------------------------------------------------------------------
fastdp.fwd.Confirm():
install iptables blocking rules, fastdp.fwd.Confirm():
nonce_BA = rand(), install iptables blocking rules,
{key,salt}_BA = hkdf(sessionKey, nonce_BA, A), nonce_AB = rand(),
spi_BA = allocspi(), {key,salt}_AB = hkdf(sessionKey, nonce_AB, B),
create SA_BA(B<-A, spi_BA, key_BA, salt_BA), spi_AB = allocspi(),
send InitSARemote(spi_BA, nonce_BA). --> create SA_AB(A<-B, spi_AB, key_AB, salt_AB),
<-- send InitSARemote(spi_AB, nonce_AB).
--> recv InitSARemote(spi_BA, nonce_BA):
recv InitSARemote(spi_AB, nonce_AB): <-- {key,salt}_BA = hkdf(sessionKey, nonce_BA, A),
{key,salt}_AB = hkdf(sessionKey, nonce_AB, B), create SA_BA(B<-A, spi_BA, key_BA, salt_BA),
create SA_AB(A<-B, spi_AB, key_AB, salt_AB), create SP_BA(B<-A, spi_BA),
create SP_AB(A<-B, spi_AB), install marking rule.
install marking rule.
```
# Implementation Details
## XFRM
The implementation is based on the kernel IP packet transformation framework
called XFRM. Unfortunately, docs are barely existing and the complexity of
the framework is high. The best resource I found is Chapter 10 in
"Linux Kernel Networking: Implementation and Theory" by Rami Rosen.
## iptables Rules
The kernel VXLAN driver does not set a dst port of a tunnel in the ip flow
descriptor, thus XFRM policy lookup cannot match a policy (SPout) which includes
the port. This makes impossible to encrypt only tunneled traffic between
peers. To work around, we mark such outgoing packets with iptables and set
the same mark in the policy selector (funnily enough, `iptables_mangle` module
eventually sets the missing dst port in the flow descriptor). The challenge
here is to pick a mark that it would not interfere with other networking
applications before OUTPUT'ing a packet. For example, Kubernetes by default
uses 1<<14 and 1<<15 marks and we choose 1<<17 (0x20000). Additionally,
such workaround brings the requirement for at least the 4.2 kernel.
The marking rules are the following:
```
iptables -t mangle -A OUTPUT -j WEAVE-IPSEC-OUT
iptables -t mangle -A WEAVE-IPSEC-OUT -s ${LOCAL_PEER_IP} -d ${REMOTE_PEER_IP} \
-p udp --dport ${TUNNEL_PORT} -j WEAVE-IPSEC-OUT-MARK
iptables -t mangle -A WEAVE-IPSEC-OUT-MARK --set-xmark ${MARK} -j MARK
```
As Linux does not implement [IP Security Levels][ipseclevel], we install
additional iptables rules to prevent from accidentally sending unencrypted
traffic between peers which have previously established the secure connection.
For inbound traffic, we mark each ESP packet with the mark and drop non-marked
tunnel traffic:
```
iptables -t mangle -A INPUT -j WEAVE-IPSEC-IN
iptables -t mangle -A WEAVE-IPSEC-IN -s ${REMOTE_PEER_IP} -d ${LOCAL_PEER_IP} \
-m esp --espspi ${SPIin} -j WEAVE-IPSEC-IN-MARK
iptables -t mangle -A WEAVE-IPSEC-IN-MARK --set-xmark ${MARK} -j MARK
iptables -t filter -A INPUT -j WEAVE-IPSEC-IN
iptables -t filter -A WEAVE-IPSEC-IN -s ${REMOTE_PEER_IP} -d ${LOCAL_PEER_IP} \
-p udp --dport ${TUNNEL_PORT} -m mark ! --mark ${MARK} -j DROP
```
For outbound traffic, we drop marked traffic which does not match any SPout:
```
iptables -t filter -A OUTPUT ! -p esp -m policy --dir out --pol none \
-m mark --mark ${MARK} -j DROP
```
## ESN
To prevent from cycling SeqNo which makes replay attacks possible, we use
64-bit extended sequence numbers known as [ESN](esn).
## MTU
In addition to the VXLAN overhead, the MTU calculation should take into account
the ESP overhead which is 34-37 bytes (encrypted Payload is 4 bytes aligned) and
consists of:
* 4 bytes (SPI).
* 4 bytes (Sequence Number).
* 8 bytes (ESP IV).
* 1 byte (Pad Length).
* 1 byte (NextHeader).
* 16 bytes (ICV).
* 0-3 bytes (Padding).
[esp]: https://tools.ietf.org/html/rfc2406
[aesgcm]: https://tools.ietf.org/html/rfc4106
[hkdf]: https://tools.ietf.org/html/rfc5869
[esn]: https://tools.ietf.org/html/rfc4304
[ipseclevel]: https://tools.ietf.org/html/draft-mcdonald-simple-ipsec-api-01)
[mesh]: https://github.com/weaveworks/mesh
+170
View File
@@ -0,0 +1,170 @@
# Overlay Method Selection
Weave automatically selects the best working overlay implementation
when connecting to a new peer. It does this by initiating both
forwarders in parallel, eventually settling on the most preferred
established forwarder at which point the other forwarder is shut down,
assuming it had not failed already. In the event that the remaining
forwarder fails at a later time (e.g. because of a heartbeat timeout)
the control plane TCP connection will recycle allowing the selection
algorithm to run again. By default fast datapath is preferred over
Sleeve.
# Local Bridging
Unlike the weave bridge netdev used by Sleeve, the OVS datapath has no
inherent bridging capability. Consequently fastdp implements an
ethernet bridge in addition to the vxlan overlay, maintaining its own
forwarding database by learning MAC addresses and dispatching
broadcast, unicast & multicast traffic accordingly.
# Short Peer IDs
The router relies on having access to the source and destination peer
when deciding how to forward packets. When the Sleeve overlay is in
use this information is conveyed directly within the encapsulation by
including the names of the peers in question, a solution not
accommodated directly by the vxlan wire format. Fortunately vxlan does
have a twenty four bit segment ID field in the header we can use to
encode this data - the challenge is to identify peers uniquely with a
twelve bit identifier instead of the seventeen bytes used by Sleeve.
In practice this is achieved by peers adopting a random 'short ID' and
resolving ownership collisions of same via the existing gossip
mechanism.
# Heartbeats via vxlan
Heartbeats are implemented by sending an encapsulated ethernet frame
with source and destination MAC addresses of `00:00:00:00:00:00` and a
payload consisting of the connection UID and total ethernet frame
length. The vxlan vport miss handler on the receiving side detects the
all-zero addresses and acknowledges the heartbeat via the TCP control
channel after validating the connection UID and frame length against
their expected values.
# PMTU Discovery
The length of the heartbeat ethernet frame is set to the MTU of the
datapath interface. In the event the vxlan packet is dropped or
truncated, the heartbeat will not be acknowledged; this lack of
acknowledgement will cause the peers to fall back to the Sleeve
overlay, which has a more sophisticated dynamic mechanism for coping
with low path MTUs.
To avoid triggering this fallback in typical deployments, the datapath
interface is statically configured with an MTU of 1410 bytes allowing
it to work with most underlay network provider MTUs, including GCE at
1460 bytes (the fifty byte difference accommodates the vxlan overhead).
This value can be overridden by setting `WEAVE_MTU` at launch if
necessary.
# Virtual Ports
There are three kinds of virtual port associated with the weave
datapath:
* `internal` - one of these is created automatically, named after the
datapath. It corresponds to the network interface of the same name
that appears on the host when the datapath is created; it is the
ingress/egress port for `weave expose`
* `netdev` - one for each application container, corresponding to the
host end of the veth pair
* `vxlan` - one for each UDP port on which we are listening for vxlan
encapsulated packets. Typically there is only one of these, but
there may be more in a network in which peers do not all use the same
port configuration
# Misses and Flow Creation
As mentioned above, the datapath has no inherent behaviour - any
ingressing packet which does not match a flow is passed to a userspace
miss handler. The miss handler is then responsible for a) instructing
the datapath to take actions for the packet that caused the miss (for
example by copying it to one or more ports) and optionally b)
installing flow rules which will allow the datapath to act on similar
packets in future without invoking the miss handler.
At a high level the fast datapath implementation can be viewed as a
set of miss handlers that determine what actions the OVS datapath
should take based on router topology information, together with some
additional machinery that manages the expiry of resulting flows when
that state changes.
When a miss handler is invoked, it has two pieces of context: a byte
array containing the packet that triggered the miss, and a set of
'flow keys' that have been extracted from the packet by the kernel
module. The following flow keys are of interest to weave:
* `InPort` - the identifier of the ingress virtual port
* `Ethernet` - the source and destination MAC addresses of the
ethernet frame
* `Tunnel` - tunnel identifier (see section on short peer IDs above),
and source/dest IPv4 addresses. Only present for ingress via a vxlan
vport
Crucially, the router must use this information alone to determine
which actions to take - this allows the specification of a flow which
matches these keys and instructs the kernel to take action
automatically in future without further userspace involvement.
Two actions are of interest:
* `Output` - output the packet to the specified vport
* `SetTunnel` - update the effective vxlan tunnel parameters. Only
required prior to output from a vxlan vport
It is possible to have multiple actions in a flow, so the router can
for example create a single rule that copies broadcast traffic to all
'local' vports (save the ingress vport obviously) as well as to vxlan
vports for onward peers as dictated by the routing topology.
Every flow specified by the router has the following characteristics:
* An `InPort` key matching the ingress vport
* A `Tunnel` key if the ingress vport is of type vxlan
* An `Ethernet` key matching the source and destination MAC
* A list of `Output` (for internal and netdev vports) and
`SetTunnel`+`Output` (for vxlan vports) actions
Under certain circumstances the miss handler will instruct the
datapath to execute a set of actions for a packet without creating a
corresponding flow:
* When broadcasting packets to discover the path to unknown
destination MACs. This condition is transient in the overwhelming
majority of cases and so the benefit of creating a flow is
outweighed by the need to invalidate it once the MAC is learned
* When the packet also needs to be forwarded to one or more peers via
Sleeve. In this case the router needs to handle all subsequent
matching packets as there is no OVS flow action to do it without
userspace involvement
# Flow Invalidation
Once a flow has been created for a particular combination of keys, the
miss handler will never again be invoked for matching packets. It is
therefore extremely important that we detect events which invalidate
existing flow actions:
* Addition of netdev vports to the datapath
* Route invalidation (topology change)
* Short peer ID collision
The response in each case is the same - delete all flows from the
datapath, allowing them to be recreated taking into account the
updated state.
In addition to these event based invalidations there is an expiry
process that executes every five minutes. This process enumerates all
flows in the datapath, removing any which have not been used since the
last check; this cleans up:
* Flows referring to netdev vports which have been removed
* Flows created by forwarders which have been stopped
* Flows related to MAC addresses which have not communicated recently
Flows keyed on tunnel IPv4 address do not need to be cleared when a
peer appears to change IP address due to NAT; this will cause a miss
resulting in a new flow, and the old flow will expire naturally via
the timer mechanism.
-8
View File
@@ -210,11 +210,3 @@ reached the peer that does the `rmpeer`, then we get an inconsistent
ring. We could make it safe, up to partitions, by inquiring of every
live peer what its view of the dead peer is, and making sure we use
the latest info.)
## Limitations
Nothing is persisted. If one peer restarts it should receive gossip
from other peers showing what it used to own, and in that case it can
recover quite well. If, however, there are no peers left alive, or
this peer cannot establish network communication with those that are,
then it cannot recover.
+13 -3
View File
@@ -6,7 +6,6 @@
* Create a [github token for
github-release](https://help.github.com/articles/creating-an-access-token-for-command-line-use/);
set and export `$GITHUB_TOKEN` with this value
* Update all dependencies with `make update`
## Release Types
@@ -63,9 +62,10 @@ This has the following effects:
## Draft Phase
### Push Version Tag Upstream
First you must push your version tag upstream, so that an associated
GitHub release may be created:
First you must push your branch and version tag upstream, so that an
associated GitHub release may be created:
git push git@github.com:weaveworks/weave
git push git@github.com:weaveworks/weave $TAG
N.B. if you're testing the release process, push to your fork
@@ -128,6 +128,16 @@ Finally, for **Mainline** releases only:
* Images tagged `latest` are updated on DockerHub
### Finish up
* If not on master, merge branch into master and push to GitHub.
* Close the [milestone](https://github.com/weaveworks/weave/milestones) in GitHub and create the next milestone
* Update the `#weavenetwork` topic heading on freenode (requires 'chanops' permission)
* For a mainline release vX.Y.0, create a release branch X.Y from the
tag and push to GitHub - this will result in X.Y.0 site docs being
published to https://www.weave.works
* Add the new version of `weave-net` to the checkpoint system at
https://checkpoint-api.weave.works/admin
## Troubleshooting
@@ -9,7 +9,7 @@ The model is that each host has a service that is notified of
hostnames and weave addresses for containers on the host. Like IPAM,
this service is embedded within the router. It binds to
the host bridge to answer DNS queries from local containers; for
anything it can't answer, it uses the infomation in the host's
anything it can't answer, it uses the information in the host's
/etc/resolv.conf to query an 'fallback' server.
The service is comprised of a DNS server, which answers all DNS queries
@@ -33,7 +33,7 @@ are re-broadcast around the cluster.
The DNS server also listens to the Docker event stream, and removes
entries for containers when they die. Entries removed in this way are
tombstoned, and the tombstone lazily broadcast around the cluster.
After a short timeout the tombstones are independantly removed from
After a short timeout the tombstones are independently removed from
each host.
+100
View File
@@ -0,0 +1,100 @@
# Overview
# ipsets
The policy controller maintains a number of ipsets which are
subsequently referred to by the iptables rules used to effect network
policy specifications. These ipsets are created, modified and
destroyed automatically in response to Pod, Namespace and
NetworkPolicy object updates from the k8s API server:
* A `hash:ip` set per namespace, containing the IP addresses of all
pods in that namespace
* A `list:set` per distinct (across all network policies in all
namespaces) namespace selector mentioned in a network policy,
containing the names of any of the above hash:ip sets whose
corresponding namespace labels match the selector
* A `hash:ip` set for each distinct (within the scope of the
containing network policy's namespace) pod selector mentioned in a
network policy, containing the IP addresses of all pods in the
namespace whose labels match that selector
ipset names are generated deterministically from a string
representation of the corresponding label selector. Because ipset
names are limited to 31 characters in length, this is done by taking a
SHA hash of the selector string and then printing that out as a base
85 string with a "weave-" prefix e.g.:
weave-k?Z;25^M}|1s7P3|H9i;*;MhG
Because pod selectors are scoped to a namespace, we need to make sure
that if the same selector definition is used in different namespaces
that we maintain distinct ipsets. Consequently, for such selectors the
namespace name is prepended to the label selector string before
hashing to avoid clashes.
# iptables chains
The policy controller maintains two iptables chains in response to
changes to pods, namespaces and network policies. One chain contains
the ingress rules that implement the network policy specifications,
and the other is used to bypass the ingress rules for namespaces which
have an ingress isolation policy of `DefaultAllow`.
## Dynamically maintained `WEAVE-NPC-DEFAULT` chain
The policy controller maintains a rule in this chain for every
namespace whose ingress isolation policy is `DefaultAllow`. The
purpose of this rule is simply to ACCEPT any traffic destined for such
namespaces before it reaches the ingress chain.
```
iptables -A WEAVE-NPC-DEFAULT -m set --match-set $NSIPSET dst -j ACCEPT
```
## Dynamically maintained `WEAVE-NPC-INGRESS` chain
For each namespace network policy ingress rule peer/port combination:
```
iptables -A WEAVE-NPC-INGRESS -p $PROTO [-m set --match-set $SRCSET] -m set --match-set $DSTSET --dport $DPORT -j ACCEPT
```
## Static `WEAVE-NPC` chain
Static configuration:
```
iptables -A WEAVE-NPC -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A WEAVE-NPC -m state --state NEW -j WEAVE-NPC-DEFAULT
iptables -A WEAVE-NPC -m state --state NEW -j WEAVE-NPC-INGRESS
```
# Steering traffic into the policy engine
To direct traffic into the policy engine:
iptables -A FORWARD -o weave -m physdev ! --physdev-out vethwe-bridge -j WEAVE-NPC
iptables -A FORWARD -o weave -m physdev ! --physdev-out vethwe-bridge -j DROP
Note this only affects traffic which egresses the bridge on a physical
port which is not the Weave Net router - in other words, it is
destined for an application container veth. The following traffic is
affected:
* Traffic bridged between local application containers
* Traffic bridged from the router to a local application container
* Traffic originating from the internet destined for nodeports - this
is routed via the FORWARD chain to a container pod IP after DNAT
The following traffic is NOT affected:
* Traffic bridged from a local application container to the router
* Traffic originating from processes in the host network namespace
(e.g. kubelet health checks)
* Traffic routed from an application container to the internet
See these resources for helpful context:
* http://ebtables.netfilter.org/br_fw_ia/br_fw_ia.html
* https://commons.wikimedia.org/wiki/File:Netfilter-packet-flow.svg
+19 -10
View File
@@ -3,6 +3,7 @@ package ipam
import (
"fmt"
"github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/net/address"
)
@@ -14,7 +15,8 @@ type allocateResult struct {
type allocate struct {
resultChan chan<- allocateResult
ident string
r address.Range // Range we are trying to allocate within
r address.CIDR // Subnet we are trying to allocate within
isContainer bool
hasBeenCancelled func() bool
}
@@ -25,29 +27,36 @@ func (g *allocate) Try(alloc *Allocator) bool {
return true
}
if addr, found := alloc.lookupOwned(g.ident, g.r); found {
g.resultChan <- allocateResult{addr, nil}
if addrs := alloc.ownedInRange(g.ident, g.r.Range()); len(addrs) > 0 {
// If we had heard that this container died, resurrect it
delete(alloc.dead, g.ident) // delete is no-op if key not in map
g.resultChan <- allocateResult{addrs[0].Addr, nil}
return true
}
if !alloc.universe.Overlaps(g.r) {
g.resultChan <- allocateResult{0, fmt.Errorf("range %s out of bounds: %s", g.r, alloc.universe)}
if !alloc.universe.Range().Overlaps(g.r.Range()) {
g.resultChan <- allocateResult{err: fmt.Errorf("range %s out of bounds: %s", g.r, alloc.universe)}
return true
}
alloc.establishRing()
if ok, addr := alloc.space.Allocate(g.r); ok {
if ok, addr := alloc.space.Allocate(g.r.HostRange()); ok {
// If caller hasn't supplied a unique ID, file it under the IP address
// which lets the caller then release the address using DELETE /ip/address
if g.ident == api.NoContainerID {
g.ident = addr.String()
}
alloc.debugln("Allocated", addr, "for", g.ident, "in", g.r)
alloc.addOwned(g.ident, addr)
alloc.addOwned(g.ident, address.MakeCIDR(g.r, addr), g.isContainer)
g.resultChan <- allocateResult{addr, nil}
return true
}
// out of space
donors := alloc.ring.ChoosePeersToAskForSpace(g.r.Start, g.r.End)
donors := alloc.ring.ChoosePeersToAskForSpace(g.r.Addr, g.r.Range().End)
for _, donor := range donors {
if err := alloc.sendSpaceRequest(donor, g.r); err != nil {
if err := alloc.sendSpaceRequest(donor, g.r.Range()); err != nil {
alloc.debugln("Problem asking peer", donor, "for space:", err)
} else {
alloc.debugln("Decided to ask peer", donor, "for space in range", g.r)
@@ -59,7 +68,7 @@ func (g *allocate) Try(alloc *Allocator) bool {
}
func (g *allocate) Cancel() {
g.resultChan <- allocateResult{0, &errorCancelled{"Allocate", g.ident}}
g.resultChan <- allocateResult{err: &errorCancelled{"Allocate", g.ident}}
}
func (g *allocate) ForContainer(ident string) bool {
+507 -185
View File
@@ -7,11 +7,14 @@ import (
"sort"
"time"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/db"
"github.com/weaveworks/weave/ipam/paxos"
"github.com/weaveworks/weave/ipam/ring"
"github.com/weaveworks/weave/ipam/space"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/ipam/tracker"
"github.com/weaveworks/weave/net/address"
)
@@ -21,8 +24,9 @@ const (
msgRingUpdate
msgSpaceRequestDenied
paxosInterval = time.Second * 5
MinSubnetSize = 4 // first and last addresses are excluded, so 2 would be too small
tickInterval = time.Second * 5
MinSubnetSize = 4 // first and last addresses are excluded, so 2 would be too small
containerDiedTimeout = time.Second * 30
)
// operation represents something which Allocator wants to do, but
@@ -38,52 +42,135 @@ type operation interface {
ForContainer(ident string) bool
}
// This type is persisted hence all fields exported
type ownedData struct {
IsContainer bool
Cidrs []address.CIDR
}
// Allocator brings together Ring and space.Set, and does the
// necessary plumbing. Runs as a single-threaded Actor, so no locks
// are used around data structures.
type Allocator struct {
actionChan chan<- func()
ourName mesh.PeerName
universe address.Range // superset of all ranges
ring *ring.Ring // information on ranges owned by all peers
space space.Space // more detail on ranges owned by us
owned map[string][]address.Address // who owns what addresses, indexed by container-ID
nicknames map[mesh.PeerName]string // so we can map nicknames for rmpeer
pendingAllocates []operation // held until we get some free space
pendingClaims []operation // held until we know who owns the space
gossip mesh.Gossip // our link to the outside world for sending messages
paxos *paxos.Node
paxosTicker *time.Ticker
shuttingDown bool // to avoid doing any requests while trying to shut down
isKnownPeer func(mesh.PeerName) bool
now func() time.Time
actionChan chan<- func()
stopChan chan<- struct{}
ourName mesh.PeerName
seed []mesh.PeerName // optional user supplied ring seed
universe address.CIDR // superset of all ranges
ring *ring.Ring // information on ranges owned by all peers
space space.Space // more detail on ranges owned by us
owned map[string]ownedData // who owns what addresses, indexed by container-ID
nicknames map[mesh.PeerName]string // so we can map nicknames for rmpeer
pendingAllocates []operation // held until we get some free space
pendingClaims []operation // held until we know who owns the space
pendingPrimes []operation // held while our ring is empty
dead map[string]time.Time // containers we heard were dead, and when
db db.DB // persistence
gossip mesh.Gossip // our link to the outside world for sending messages
paxos paxos.Participant
awaitingConsensus bool
ticker *time.Ticker
shuttingDown bool // to avoid doing any requests while trying to shut down
isKnownPeer func(mesh.PeerName) bool
quorum func() uint
now func() time.Time
}
type Config struct {
OurName mesh.PeerName
OurUID mesh.PeerUID
OurNickname string
Seed []mesh.PeerName
Universe address.CIDR
IsObserver bool
Quorum func() uint
Db db.DB
IsKnownPeer func(name mesh.PeerName) bool
Tracker tracker.LocalRangeTracker
}
// NewAllocator creates and initialises a new Allocator
func NewAllocator(ourName mesh.PeerName, ourUID mesh.PeerUID, ourNickname string, universe address.Range, quorum uint, isKnownPeer func(name mesh.PeerName) bool) *Allocator {
return &Allocator{
ourName: ourName,
universe: universe,
ring: ring.New(universe.Start, universe.End, ourName),
owned: make(map[string][]address.Address),
paxos: paxos.NewNode(ourName, ourUID, quorum),
nicknames: map[mesh.PeerName]string{ourName: ourNickname},
isKnownPeer: isKnownPeer,
func NewAllocator(config Config) *Allocator {
var participant paxos.Participant
var alloc *Allocator
var onUpdate ring.OnUpdate
if config.IsObserver {
participant = paxos.NewObserver()
} else {
participant = paxos.NewNode(config.OurName, config.OurUID, 0)
}
if config.Tracker != nil {
onUpdate = func(prev []address.Range, curr []address.Range, local bool) {
if err := config.Tracker.HandleUpdate(prev, curr, local); err != nil {
alloc.errorf("HandleUpdate failed: %s", err)
}
}
}
alloc = &Allocator{
ourName: config.OurName,
seed: config.Seed,
universe: config.Universe,
ring: ring.New(config.Universe.Range().Start, config.Universe.Range().End, config.OurName, onUpdate),
owned: make(map[string]ownedData),
db: config.Db,
paxos: participant,
nicknames: map[mesh.PeerName]string{config.OurName: config.OurNickname},
isKnownPeer: config.IsKnownPeer,
quorum: config.Quorum,
dead: make(map[string]time.Time),
now: time.Now,
}
return alloc
}
func ParseCIDRSubnet(cidrStr string) (cidr address.CIDR, err error) {
cidr, err = address.ParseCIDR(cidrStr)
if err != nil {
return
}
if !cidr.IsSubnet() {
err = fmt.Errorf("invalid subnet - bits after network prefix are not all zero: %s", cidrStr)
}
if cidr.Size() < MinSubnetSize {
err = fmt.Errorf("invalid subnet - smaller than minimum size %d: %s", MinSubnetSize, cidrStr)
}
return
}
// Start runs the allocator goroutine
func (alloc *Allocator) Start() {
loadedPersistedData := alloc.loadPersistedData()
switch {
case loadedPersistedData && len(alloc.seed) != 0:
alloc.infof("Found persisted IPAM data, ignoring supplied IPAM seed")
case loadedPersistedData:
alloc.infof("Initialising with persisted data")
case len(alloc.seed) != 0:
alloc.infof("Initialising with supplied IPAM seed")
alloc.createRing(alloc.seed)
case alloc.paxos.IsElector():
alloc.infof("Initialising via deferred consensus")
default:
alloc.infof("Initialising as observer - awaiting IPAM data from another peer")
}
actionChan := make(chan func(), mesh.ChannelSize)
stopChan := make(chan struct{})
alloc.actionChan = actionChan
go alloc.actorLoop(actionChan)
alloc.stopChan = stopChan
alloc.ticker = time.NewTicker(tickInterval)
go alloc.actorLoop(actionChan, stopChan)
}
// Stop makes the actor routine exit, for test purposes ONLY because any
// calls after this is processed will hang. Async.
func (alloc *Allocator) Stop() {
alloc.actionChan <- nil
select {
case alloc.stopChan <- struct{}{}:
default:
}
}
// Operation life cycle
@@ -140,35 +227,31 @@ func (alloc *Allocator) cancelOpsFor(ops *[]operation, ident string) bool {
return found
}
// Try all pending operations
func (alloc *Allocator) tryPendingOps() {
// The slightly different semantics requires us to operate on 'claims' and
// 'allocates' separately:
// Claims must be tried before Allocates
for i := 0; i < len(alloc.pendingClaims); {
op := alloc.pendingClaims[i]
// Try all operations in a queue
func (alloc *Allocator) tryOps(ops *[]operation) {
for i := 0; i < len(*ops); {
op := (*ops)[i]
if !op.Try(alloc) {
i++
continue
}
alloc.pendingClaims = append(alloc.pendingClaims[:i], alloc.pendingClaims[i+1:]...)
*ops = append((*ops)[:i], (*ops)[i+1:]...)
}
}
// When the first Allocate fails, bail - no need to
// send too many begs for space.
for i := 0; i < len(alloc.pendingAllocates); {
op := alloc.pendingAllocates[i]
if !op.Try(alloc) {
break
}
alloc.pendingAllocates = append(alloc.pendingAllocates[:i], alloc.pendingAllocates[i+1:]...)
}
// Try all pending operations
func (alloc *Allocator) tryPendingOps() {
// Unblock pending primes first
alloc.tryOps(&alloc.pendingPrimes)
// Process existing claims before servicing new allocations
alloc.tryOps(&alloc.pendingClaims)
alloc.tryOps(&alloc.pendingAllocates)
}
func (alloc *Allocator) spaceRequestDenied(sender mesh.PeerName, r address.Range) {
for i := 0; i < len(alloc.pendingClaims); {
claim := alloc.pendingClaims[i].(*claim)
if r.Contains(claim.addr) {
if r.Contains(claim.cidr.Addr) {
claim.deniedBy(alloc, sender)
alloc.pendingClaims = append(alloc.pendingClaims[:i], alloc.pendingClaims[i+1:]...)
continue
@@ -188,87 +271,135 @@ func (e *errorCancelled) Error() string {
// Actor client API
// Prime (Sync) - wait for consensus
func (alloc *Allocator) Prime() {
resultChan := make(chan struct{})
op := &prime{resultChan: resultChan}
alloc.doOperation(op, &alloc.pendingPrimes)
<-resultChan
}
// Allocate (Sync) - get new IP address for container with given name in range
// if there isn't any space in that range we block indefinitely
func (alloc *Allocator) Allocate(ident string, r address.Range, hasBeenCancelled func() bool) (address.Address, error) {
func (alloc *Allocator) Allocate(ident string, r address.CIDR, isContainer bool, hasBeenCancelled func() bool) (address.Address, error) {
resultChan := make(chan allocateResult)
op := &allocate{resultChan: resultChan, ident: ident, r: r, hasBeenCancelled: hasBeenCancelled}
op := &allocate{
resultChan: resultChan,
ident: ident,
r: r,
isContainer: isContainer,
hasBeenCancelled: hasBeenCancelled,
}
alloc.doOperation(op, &alloc.pendingAllocates)
result := <-resultChan
return result.addr, result.err
}
// Lookup (Sync) - get existing IP address for container with given name in range
func (alloc *Allocator) Lookup(ident string, r address.Range) (address.Address, error) {
resultChan := make(chan allocateResult)
// Lookup (Sync) - get existing IP addresses for container with given name in range
func (alloc *Allocator) Lookup(ident string, r address.Range) ([]address.CIDR, error) {
resultChan := make(chan []address.CIDR)
alloc.actionChan <- func() {
if addr, found := alloc.lookupOwned(ident, r); found {
resultChan <- allocateResult{addr: addr}
return
}
resultChan <- allocateResult{err: fmt.Errorf("lookup: no address found for %s in range %s", ident, r)}
resultChan <- alloc.ownedInRange(ident, r)
}
result := <-resultChan
return result.addr, result.err
return <-resultChan, nil
}
// Claim an address that we think we should own (Sync)
func (alloc *Allocator) Claim(ident string, addr address.Address, noErrorOnUnknown bool) error {
func (alloc *Allocator) Claim(ident string, cidr address.CIDR, isContainer, noErrorOnUnknown bool, hasBeenCancelled func() bool) error {
resultChan := make(chan error)
op := &claim{resultChan: resultChan, ident: ident, addr: addr, noErrorOnUnknown: noErrorOnUnknown}
op := &claim{
resultChan: resultChan,
ident: ident,
cidr: cidr,
isContainer: isContainer,
noErrorOnUnknown: noErrorOnUnknown,
hasBeenCancelled: hasBeenCancelled,
}
alloc.doOperation(op, &alloc.pendingClaims)
return <-resultChan
}
// ContainerDied is provided to satisfy the updater interface; does a 'Delete' underneath. Sync.
// ContainerDied called from the updater interface. Async.
func (alloc *Allocator) ContainerDied(ident string) {
if err := alloc.Delete(ident); err == nil {
alloc.debugln("Container", ident, "died; released addresses")
alloc.actionChan <- func() {
if alloc.hasOwnedByContainer(ident) {
alloc.debugln("Container", ident, "died; noting to remove later")
alloc.dead[ident] = alloc.now()
}
// Also remove any pending ops
alloc.cancelOpsFor(&alloc.pendingAllocates, ident)
alloc.cancelOpsFor(&alloc.pendingClaims, ident)
}
}
func (alloc *Allocator) ContainerStarted(ident string) {}
// ContainerDestroyed called from the updater interface. Async.
func (alloc *Allocator) ContainerDestroyed(ident string) {
alloc.actionChan <- func() {
if alloc.hasOwnedByContainer(ident) {
alloc.debugln("Container", ident, "destroyed; removing addresses")
alloc.delete(ident)
delete(alloc.dead, ident)
}
}
}
func (alloc *Allocator) removeDeadContainers() {
cutoff := alloc.now().Add(-containerDiedTimeout)
for ident, timeOfDeath := range alloc.dead {
if timeOfDeath.Before(cutoff) {
if err := alloc.delete(ident); err == nil {
alloc.debugln("Removed addresses for container", ident)
}
delete(alloc.dead, ident)
}
}
}
func (alloc *Allocator) ContainerStarted(ident string) {
alloc.actionChan <- func() {
delete(alloc.dead, ident) // delete is no-op if key not in map
}
}
func (alloc *Allocator) PruneOwned(ids []string) {
idmap := make(map[string]struct{}, len(ids))
for _, id := range ids {
idmap[id] = struct{}{}
}
alloc.actionChan <- func() {
alloc.pruneOwned(idmap)
}
}
// Delete (Sync) - release all IP addresses for container with given name
func (alloc *Allocator) Delete(ident string) error {
errChan := make(chan error)
alloc.actionChan <- func() {
addrs, found := alloc.owned[ident]
for _, addr := range addrs {
alloc.space.Free(addr)
}
delete(alloc.owned, ident)
// Also remove any pending ops
found = alloc.cancelOpsFor(&alloc.pendingAllocates, ident) || found
found = alloc.cancelOpsFor(&alloc.pendingClaims, ident) || found
if !found {
errChan <- fmt.Errorf("Delete: no addresses for %s", ident)
return
}
errChan <- nil
errChan <- alloc.delete(ident)
}
return <-errChan
}
func (alloc *Allocator) delete(ident string) error {
cidrs := alloc.removeAllOwned(ident)
if len(cidrs) == 0 {
return fmt.Errorf("Delete: no addresses for %s", ident)
}
for _, cidr := range cidrs {
alloc.space.Free(cidr.Addr)
}
return nil
}
// Free (Sync) - release single IP address for container
func (alloc *Allocator) Free(ident string, addrToFree address.Address) error {
errChan := make(chan error)
alloc.actionChan <- func() {
addrs := alloc.owned[ident]
for i, ownedAddr := range addrs {
if ownedAddr == addrToFree {
alloc.debugln("Freed", addrToFree, "for", ident)
if len(addrs) == 1 {
delete(alloc.owned, ident)
} else {
alloc.owned[ident] = append(addrs[:i], addrs[i+1:]...)
}
alloc.space.Free(addrToFree)
errChan <- nil
return
}
if alloc.removeOwned(ident, addrToFree) {
alloc.debugln("Freed", addrToFree, "for", ident)
alloc.space.Free(addrToFree)
errChan <- nil
return
}
errChan <- fmt.Errorf("Free: address %s not found for %s", addrToFree, ident)
@@ -299,7 +430,7 @@ func (alloc *Allocator) pickPeerForTransfer() mesh.PeerName {
if heir := alloc.ring.PickPeerForTransfer(t); heir != mesh.UnknownPeerName {
return heir
}
// finally, disappeared peers that that passively participated in IPAM
// finally, disappeared peers that passively participated in IPAM
return alloc.pickPeerFromNicknames(t)
}
@@ -311,37 +442,53 @@ func (alloc *Allocator) Shutdown() {
alloc.shuttingDown = true
alloc.cancelOps(&alloc.pendingClaims)
alloc.cancelOps(&alloc.pendingAllocates)
if heir := alloc.pickPeerForTransfer(); heir != mesh.UnknownPeerName {
alloc.ring.Transfer(alloc.ourName, heir)
alloc.space.Clear()
alloc.cancelOps(&alloc.pendingPrimes)
heir := alloc.pickPeerForTransfer()
alloc.ring.Transfer(alloc.ourName, heir)
alloc.space.Clear()
if heir != mesh.UnknownPeerName {
alloc.persistRing()
alloc.gossip.GossipBroadcast(alloc.Gossip())
time.Sleep(100 * time.Millisecond)
}
doneChan <- struct{}{}
}
<-doneChan
}
// AdminTakeoverRanges (Sync) - take over the ranges owned by a given peer.
// Only done on adminstrator command.
func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) error {
resultChan := make(chan error)
// AdminTakeoverRanges (Sync) - take over the ranges owned by a given
// peer, and return how much space was transferred in the process.
// Only done on administrator command.
func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) address.Count {
resultChan := make(chan address.Count)
alloc.actionChan <- func() {
peername, err := alloc.lookupPeername(peerNameOrNickname)
if err != nil {
resultChan <- fmt.Errorf("Cannot find peer '%s'", peerNameOrNickname)
alloc.warnf("attempt to take over range from unknown peer '%s'", peerNameOrNickname)
resultChan <- address.Count(0)
return
}
alloc.debugln("AdminTakeoverRanges:", peername)
if peername == alloc.ourName {
resultChan <- fmt.Errorf("Cannot take over ranges from yourself!")
alloc.warnf("attempt to take over range from ourself")
resultChan <- address.Count(0)
return
}
newRanges, err := alloc.ring.Transfer(peername, alloc.ourName)
alloc.space.AddRanges(newRanges)
resultChan <- err
newRanges := alloc.ring.Transfer(peername, alloc.ourName)
if len(newRanges) == 0 {
resultChan <- address.Count(0)
return
}
before := alloc.space.NumFreeAddresses()
alloc.ringUpdated()
after := alloc.space.NumFreeAddresses()
alloc.gossip.GossipBroadcast(alloc.Gossip())
resultChan <- after - before
}
return <-resultChan
}
@@ -382,6 +529,22 @@ func (alloc *Allocator) annotatePeernames(names []mesh.PeerName) []string {
return res
}
// PeerGone removes nicknames of peers which are no longer mentioned
// in the ring. Async.
//
// NB: the function is invoked by the gossip library routines and should be
// registered manually.
func (alloc *Allocator) PeerGone(peerName mesh.PeerName) {
alloc.debugf("PeerGone: peer %s", peerName)
alloc.actionChan <- func() {
ringPeers := alloc.ring.PeerNames()
if _, ok := ringPeers[peerName]; !ok {
delete(alloc.nicknames, peerName)
}
}
}
func decodeRange(msg []byte) (r address.Range, err error) {
decoder := gob.NewDecoder(bytes.NewReader(msg))
return r, decoder.Decode(&r)
@@ -394,9 +557,11 @@ func (alloc *Allocator) OnGossipUnicast(sender mesh.PeerName, msg []byte) error
alloc.actionChan <- func() {
switch msg[0] {
case msgSpaceRequest:
// some other peer asked us for space
alloc.debugln("Peer", sender, "asked me for space")
r, err := decodeRange(msg[1:])
if err == nil {
// If we don't have a ring, just ignore a request for space.
// They'll probably ask again later.
if err == nil && !alloc.ring.Empty() {
alloc.donateSpace(r, sender)
}
resultChan <- err
@@ -425,7 +590,7 @@ func (alloc *Allocator) OnGossipBroadcast(sender mesh.PeerName, msg []byte) (mes
type gossipState struct {
// We send a timstamp along with the information to be
// gossipped in order to detect skewed clocks
// gossipped for backwards-compatibility (previously to detect skewed clocks)
Now int64
Nicknames map[mesh.PeerName]string
@@ -440,6 +605,9 @@ func (alloc *Allocator) encode() []byte {
}
// We're only interested in Paxos until we have a Ring.
// Non-electing participants (e.g. observers) return
// a nil gossip state in order to provoke a unicast ring
// update from electing peers who have reached consensus.
if alloc.ring.Empty() {
data.Paxos = alloc.paxos.GossipState()
} else {
@@ -478,8 +646,8 @@ type ipamGossipData struct {
alloc *Allocator
}
func (d *ipamGossipData) Merge(other mesh.GossipData) {
// no-op
func (d *ipamGossipData) Merge(other mesh.GossipData) mesh.GossipData {
return d // no-op
}
func (d *ipamGossipData) Encode() [][]byte {
@@ -499,21 +667,22 @@ func (alloc *Allocator) SetInterfaces(gossip mesh.Gossip) {
// ACTOR server
func (alloc *Allocator) actorLoop(actionChan <-chan func()) {
func (alloc *Allocator) actorLoop(actionChan <-chan func(), stopChan <-chan struct{}) {
defer alloc.ticker.Stop()
for {
var tickChan <-chan time.Time
if alloc.paxosTicker != nil {
tickChan = alloc.paxosTicker.C
}
select {
case action := <-actionChan:
if action == nil {
return
}
action()
case <-tickChan:
alloc.propose()
case <-stopChan:
return
case <-alloc.ticker.C:
// Retry things in case messages got lost between here and recipients
if alloc.awaitingConsensus {
alloc.propose()
} else {
alloc.tryPendingOps()
}
alloc.removeDeadContainers()
}
alloc.assertInvariants()
@@ -525,39 +694,35 @@ func (alloc *Allocator) actorLoop(actionChan <-chan func()) {
// Ensure we are making progress towards an established ring
func (alloc *Allocator) establishRing() {
if !alloc.ring.Empty() || alloc.paxosTicker != nil {
if !alloc.ring.Empty() || alloc.awaitingConsensus {
return
}
alloc.awaitingConsensus = true
alloc.paxos.SetQuorum(alloc.quorum())
alloc.propose()
if ok, cons := alloc.paxos.Consensus(); ok {
// If the quorum was 1, then proposing immediately
// leads to consensus
alloc.createRing(cons.Value)
} else {
// re-try until we get consensus
alloc.paxosTicker = time.NewTicker(paxosInterval)
}
}
func (alloc *Allocator) createRing(peers []mesh.PeerName) {
alloc.debugln("Paxos consensus:", peers)
alloc.ring.ClaimForPeers(normalizeConsensus(peers))
alloc.gossip.GossipBroadcast(alloc.Gossip())
alloc.ringUpdated()
alloc.gossip.GossipBroadcast(alloc.Gossip())
}
func (alloc *Allocator) ringUpdated() {
// When we have a ring, we don't need paxos any more
if alloc.paxos != nil {
if alloc.awaitingConsensus {
alloc.awaitingConsensus = false
alloc.paxos = nil
if alloc.paxosTicker != nil {
alloc.paxosTicker.Stop()
alloc.paxosTicker = nil
}
}
alloc.persistRing()
alloc.space.UpdateRanges(alloc.ring.OwnedRanges())
alloc.tryPendingOps()
}
@@ -626,27 +791,27 @@ func (alloc *Allocator) update(sender mesh.PeerName, msg []byte) error {
reader := bytes.NewReader(msg)
decoder := gob.NewDecoder(reader)
var data gossipState
var err error
if err := decoder.Decode(&data); err != nil {
return err
}
deltat := time.Unix(data.Now, 0).Sub(alloc.now())
if deltat > time.Hour || -deltat > time.Hour {
return fmt.Errorf("clock skew of %v detected, ignoring update", deltat)
}
// Merge nicknames
for peer, nickname := range data.Nicknames {
alloc.nicknames[peer] = nickname
}
// only one of Ring and Paxos should be present. And we
// shouldn't get updates for a empty Ring. But tolerate
// them just in case.
if data.Ring != nil {
switch err = alloc.ring.Merge(*data.Ring); err {
switch {
// If someone sent us a ring, merge it into ours. Note this will move us
// out of the awaiting-consensus state if we didn't have a ring already.
case data.Ring != nil:
updated, err := alloc.ring.Merge(*data.Ring)
switch err {
case nil:
if updated {
alloc.pruneNicknames()
alloc.ringUpdated()
}
case ring.ErrDifferentSeeds:
return fmt.Errorf("IP allocation was seeded by different peers (received: %v, ours: %v)",
alloc.annotatePeernames(data.Ring.Seeds), alloc.annotatePeernames(alloc.ring.Seeds))
@@ -654,31 +819,44 @@ func (alloc *Allocator) update(sender mesh.PeerName, msg []byte) error {
return fmt.Errorf("Incompatible IP allocation ranges (received: %s, ours: %s)",
data.Ring.Range().AsCIDRString(), alloc.ring.Range().AsCIDRString())
default:
if err == nil && !alloc.ring.Empty() {
alloc.pruneNicknames()
alloc.ringUpdated()
}
return err
}
}
if data.Paxos != nil {
if alloc.ring.Empty() {
if alloc.paxos.Update(data.Paxos) {
if alloc.paxos.Think() {
// If something important changed, broadcast
alloc.gossip.GossipBroadcast(alloc.Gossip())
}
if ok, cons := alloc.paxos.Consensus(); ok {
alloc.createRing(cons.Value)
}
}
} else if sender != mesh.UnknownPeerName {
// Sender is trying to initialize a ring, but we have one
// already - send it straight back
// If we reach this point we know the sender is either an elector
// broadcasting a paxos proposal to form a ring or a non-elector
// broadcasting a ring request. If we have a ring already we can just send
// it back regardless.
case !alloc.ring.Empty():
if sender != mesh.UnknownPeerName {
alloc.sendRingUpdate(sender)
}
// Otherwise, we need to react according to whether or not we received a
// paxos proposal.
case data.Paxos != nil:
// Process the proposal (this is a no-op if we're an observer)
if alloc.paxos.Update(data.Paxos) {
if alloc.paxos.Think() {
// If something important changed, broadcast
alloc.gossip.GossipBroadcast(alloc.Gossip())
}
if ok, cons := alloc.paxos.Consensus(); ok {
alloc.createRing(cons.Value)
}
}
// No paxos proposal present, so sender is a non-elector. We don't have a
// ring to send, so attempt to establish one on their behalf. NB we only do
// this:
//
// * On an explicit broadcast request triggered by a remote allocation attempt
// (if we did so on periodic gossip we would force consensus unnecessarily)
// * If we are an elector (to avoid a broadcast storm of ring request messages)
default:
if alloc.paxos.IsElector() && sender != mesh.UnknownPeerName {
alloc.establishRing()
}
}
return nil
@@ -686,13 +864,12 @@ func (alloc *Allocator) update(sender mesh.PeerName, msg []byte) error {
func (alloc *Allocator) donateSpace(r address.Range, to mesh.PeerName) {
// No matter what we do, we'll send a unicast gossip
// of our ring back to tha chap who asked for space.
// of our ring back to the chap who asked for space.
// This serves to both tell him of any space we might
// have given him, or tell him where he might find some
// more.
defer alloc.sendRingUpdate(to)
alloc.debugln("Peer", to, "asked me for space")
chunk, ok := alloc.space.Donate(r)
if !ok {
free := alloc.space.NumFreeAddressesInRange(r)
@@ -705,7 +882,7 @@ func (alloc *Allocator) donateSpace(r address.Range, to mesh.PeerName) {
}
alloc.debugln("Giving range", chunk, "to", to)
alloc.ring.GrantRangeToHost(chunk.Start, chunk.End, to)
alloc.sendRingUpdate(to)
alloc.persistRing()
}
func (alloc *Allocator) assertInvariants() {
@@ -731,33 +908,145 @@ func (alloc *Allocator) reportFreeSpace() {
return
}
freespace := make(map[address.Address]address.Offset)
freespace := make(map[address.Address]address.Count)
for _, r := range ranges {
freespace[r.Start] = alloc.space.NumFreeAddressesInRange(r)
}
alloc.ring.ReportFree(freespace)
if alloc.ring.ReportFree(freespace) {
alloc.persistRing()
}
}
// Persistent data
const (
ringIdent = "ring"
ownedIdent = "ownedAddresses"
)
func (alloc *Allocator) persistRing() {
// It would be better if these two Save operations happened in the same transaction
if err := alloc.db.Save(db.NameIdent, alloc.ourName); err != nil {
alloc.fatalf("Error persisting ring data: %s", err)
return
}
if err := alloc.db.Save(ringIdent, alloc.ring); err != nil {
alloc.fatalf("Error persisting ring data: %s", err)
}
}
// Returns true if persisted data is to be used, otherwise false
func (alloc *Allocator) loadPersistedData() bool {
var checkPeerName mesh.PeerName
nameFound, err := alloc.db.Load(db.NameIdent, &checkPeerName)
if err != nil {
alloc.fatalf("Error loading persisted peer name: %s", err)
}
var persistedRing *ring.Ring
ringFound, err := alloc.db.Load(ringIdent, &persistedRing)
if err != nil {
alloc.fatalf("Error loading persisted IPAM data: %s", err)
}
var persistedOwned map[string]ownedData
ownedFound, err := alloc.db.Load(ownedIdent, &persistedOwned)
if err != nil {
alloc.fatalf("Error loading persisted address data: %s", err)
}
overwritePersisted := func(fmt string, args ...interface{}) {
alloc.infof(fmt, args...)
alloc.persistRing()
alloc.persistOwned()
}
if !nameFound || !ringFound {
overwritePersisted("No valid persisted data")
return false
}
if checkPeerName != alloc.ourName {
overwritePersisted("Deleting persisted data for peername %s", checkPeerName)
return false
}
if persistedRing.Range() != alloc.universe.Range() {
overwritePersisted("Deleting persisted data for IPAM range %s; our range is %s", persistedRing.Range(), alloc.universe)
return false
}
alloc.ring.Restore(persistedRing)
alloc.space.UpdateRanges(alloc.ring.OwnedRanges())
if ownedFound {
alloc.owned = persistedOwned
for _, d := range alloc.owned {
for _, cidr := range d.Cidrs {
alloc.space.Claim(cidr.Addr)
}
}
}
return true
}
func (alloc *Allocator) persistOwned() {
if err := alloc.db.Save(ownedIdent, alloc.owned); err != nil {
alloc.fatalf("Error persisting address data: %s", err)
}
}
// Owned addresses
// NB: addr must not be owned by ident already
func (alloc *Allocator) addOwned(ident string, addr address.Address) {
alloc.owned[ident] = append(alloc.owned[ident], addr)
func (alloc *Allocator) hasOwnedByContainer(ident string) bool {
d, b := alloc.owned[ident]
return b && d.IsContainer
}
func (alloc *Allocator) lookupOwned(ident string, r address.Range) (address.Address, bool) {
for _, addr := range alloc.owned[ident] {
if r.Contains(addr) {
return addr, true
// NB: addr must not be owned by ident already
func (alloc *Allocator) addOwned(ident string, cidr address.CIDR, isContainer bool) {
d := alloc.owned[ident]
d.IsContainer = isContainer
d.Cidrs = append(d.Cidrs, cidr)
alloc.owned[ident] = d
alloc.persistOwned()
}
func (alloc *Allocator) removeAllOwned(ident string) []address.CIDR {
a := alloc.owned[ident]
delete(alloc.owned, ident)
alloc.persistOwned()
return a.Cidrs
}
func (alloc *Allocator) removeOwned(ident string, addrToFree address.Address) bool {
d := alloc.owned[ident]
for i, ownedCidr := range d.Cidrs {
if ownedCidr.Addr == addrToFree {
if len(d.Cidrs) == 1 {
delete(alloc.owned, ident)
} else {
d.Cidrs = append(d.Cidrs[:i], d.Cidrs[i+1:]...)
alloc.owned[ident] = d
}
alloc.persistOwned()
return true
}
}
return 0, false
return false
}
func (alloc *Allocator) ownedInRange(ident string, r address.Range) []address.CIDR {
var c []address.CIDR
for _, cidr := range alloc.owned[ident].Cidrs {
if r.Contains(cidr.Addr) {
c = append(c, cidr)
}
}
return c
}
func (alloc *Allocator) findOwner(addr address.Address) string {
for ident, addrs := range alloc.owned {
for _, candidate := range addrs {
if candidate == addr {
for ident, d := range alloc.owned {
for _, candidate := range d.Cidrs {
if candidate.Addr == addr {
return ident
}
}
@@ -765,14 +1054,47 @@ func (alloc *Allocator) findOwner(addr address.Address) string {
return ""
}
// For each ID in the 'owned' map, remove the entry if it isn't in the map
func (alloc *Allocator) pruneOwned(ids map[string]struct{}) {
changed := false
for ident, d := range alloc.owned {
if !d.IsContainer {
continue
}
if _, found := ids[ident]; !found {
for _, cidr := range d.Cidrs {
alloc.space.Free(cidr.Addr)
}
alloc.debugf("Deleting old entry %s: %v", ident, d.Cidrs)
delete(alloc.owned, ident)
changed = true
}
}
if changed {
alloc.persistOwned()
}
}
// Logging
func (alloc *Allocator) fatalf(fmt string, args ...interface{}) {
alloc.logf(common.Log.Fatalf, fmt, args...)
}
func (alloc *Allocator) warnf(fmt string, args ...interface{}) {
alloc.logf(common.Log.Warnf, fmt, args...)
}
func (alloc *Allocator) errorf(fmt string, args ...interface{}) {
common.Log.Errorf("[allocator %s] "+fmt, append([]interface{}{alloc.ourName}, args...)...)
}
func (alloc *Allocator) infof(fmt string, args ...interface{}) {
common.Log.Infof("[allocator %s] "+fmt, append([]interface{}{alloc.ourName}, args...)...)
alloc.logf(common.Log.Infof, fmt, args...)
}
func (alloc *Allocator) debugf(fmt string, args ...interface{}) {
alloc.logf(common.Log.Debugf, fmt, args...)
}
func (alloc *Allocator) logf(f func(string, ...interface{}), fmt string, args ...interface{}) {
f("[allocator %s] "+fmt, append([]interface{}{alloc.ourName}, args...)...)
}
func (alloc *Allocator) debugln(args ...interface{}) {
common.Log.Debugln(append([]interface{}{fmt.Sprintf("[allocator %s]:", alloc.ourName)}, args...)...)
}
func (alloc *Allocator) debugf(fmt string, args ...interface{}) {
common.Log.Debugf("[allocator %s] "+fmt, append([]interface{}{alloc.ourName}, args...)...)
}
+160 -90
View File
@@ -22,6 +22,14 @@ const (
func returnFalse() bool { return false }
func (alloc *Allocator) SimplyAllocate(ident string, cidr address.CIDR) (address.Address, error) {
return alloc.Allocate(ident, cidr, true, returnFalse)
}
func (alloc *Allocator) SimplyClaim(ident string, cidr address.CIDR) error {
return alloc.Claim(ident, cidr, true, true, returnFalse)
}
func TestAllocFree(t *testing.T) {
const (
container1 = "abcdef"
@@ -37,40 +45,54 @@ func TestAllocFree(t *testing.T) {
alloc, subnet := makeAllocatorWithMockGossip(t, "01:00:00:01:00:00", universe, 1)
defer alloc.Stop()
_, cidr1, _ := address.ParseCIDR(subnet1)
_, cidr2, _ := address.ParseCIDR(subnet2)
cidr1, _ := address.ParseCIDR(subnet1)
cidr2, _ := address.ParseCIDR(subnet2)
alloc.claimRingForTesting()
addr1, err := alloc.Allocate(container1, cidr1.HostRange(), returnFalse)
addr1, err := alloc.SimplyAllocate(container1, cidr1)
require.NoError(t, err)
require.Equal(t, testAddr1, addr1.String(), "address")
addr2, err := alloc.Allocate(container1, cidr2.HostRange(), returnFalse)
addr2, err := alloc.SimplyAllocate(container1, cidr2)
require.NoError(t, err)
require.Equal(t, testAddr2, addr2.String(), "address")
addrs, err := alloc.Lookup(container1, subnet.Range())
require.NoError(t, err)
require.Equal(t, []address.CIDR{address.MakeCIDR(cidr1, addr1), address.MakeCIDR(cidr2, addr2)}, addrs)
// Ask for another address for a different container and check it's different
addr1b, _ := alloc.Allocate(container2, cidr1.HostRange(), returnFalse)
addr1b, _ := alloc.SimplyAllocate(container2, cidr1)
if addr1b.String() == testAddr1 {
t.Fatalf("Expected different address but got %s", addr1b.String())
}
// Ask for the first container again and we should get the same addresses again
addr1a, _ := alloc.Allocate(container1, cidr1.HostRange(), returnFalse)
addr1a, _ := alloc.SimplyAllocate(container1, cidr1)
require.Equal(t, testAddr1, addr1a.String(), "address")
addr2a, _ := alloc.Allocate(container1, cidr2.HostRange(), returnFalse)
addr2a, _ := alloc.SimplyAllocate(container1, cidr2)
require.Equal(t, testAddr2, addr2a.String(), "address")
// Now delete the first container, and we should get its addresses back
require.NoError(t, alloc.Delete(container1))
addr3, _ := alloc.Allocate(container3, cidr1.HostRange(), returnFalse)
addr3, _ := alloc.SimplyAllocate(container3, cidr1)
require.Equal(t, testAddr1, addr3.String(), "address")
addr4, _ := alloc.Allocate(container3, cidr2.HostRange(), returnFalse)
addr4, _ := alloc.SimplyAllocate(container3, cidr2)
require.Equal(t, testAddr2, addr4.String(), "address")
alloc.ContainerDied(container2)
// Resurrect
addr1c, err := alloc.SimplyAllocate(container2, cidr1)
require.NoError(t, err)
require.Equal(t, addr1b, addr1c, "address")
alloc.ContainerDied(container3)
require.Equal(t, address.Offset(spaceSize), alloc.NumFreeAddresses(subnet))
alloc.Encode() // sync up
// Move the clock forward and clear out the dead container
alloc.actionChan <- func() { alloc.now = func() time.Time { return time.Now().Add(containerDiedTimeout * 2) } }
alloc.actionChan <- func() { alloc.removeDeadContainers() }
require.Equal(t, address.Count(spaceSize+1), alloc.NumFreeAddresses(subnet.Range()))
}
func TestBootstrap(t *testing.T) {
@@ -95,7 +117,7 @@ func TestBootstrap(t *testing.T) {
ExpectBroadcastMessage(alloc1, nil) // alloc1 will try to form consensus
done := make(chan bool)
go func() {
alloc1.Allocate("somecontainer", subnet, returnFalse)
alloc1.Allocate("somecontainer", subnet, true, returnFalse)
done <- true
}()
time.Sleep(100 * time.Millisecond)
@@ -103,6 +125,7 @@ func TestBootstrap(t *testing.T) {
CheckAllExpectedMessagesSent(alloc1, alloc2)
// Check that tryPendingOps doesn't cause anything to happen here
alloc1.actionChan <- func() { alloc1.tryPendingOps() }
AssertNothingSent(t, done)
@@ -115,14 +138,24 @@ func TestBootstrap(t *testing.T) {
ExpectBroadcastMessage(alloc1, nil)
alloc1.OnGossipBroadcast(alloc2.ourName, alloc2.Encode())
// both nodes will get consensus now so initialize the ring
ExpectBroadcastMessage(alloc2, nil)
CheckAllExpectedMessagesSent(alloc1, alloc2)
// at this point, both nodes have seen each other, but don't have a valid proposal
// so there is another exchange of messages
ExpectBroadcastMessage(alloc2, nil)
alloc2.OnGossipBroadcast(alloc1.ourName, alloc1.Encode())
// we have consensus now so alloc1 will initialize the ring
ExpectBroadcastMessage(alloc1, nil)
alloc1.OnGossipBroadcast(alloc2.ourName, alloc2.Encode())
CheckAllExpectedMessagesSent(alloc1, alloc2)
// alloc2 receives the ring and does not reply
alloc2.OnGossipBroadcast(alloc1.ourName, alloc1.Encode())
CheckAllExpectedMessagesSent(alloc1, alloc2)
alloc1.OnGossipBroadcast(alloc2.ourName, alloc2.Encode())
// now alloc1 should have space
AssertSent(t, done)
@@ -135,42 +168,42 @@ func TestAllocatorClaim(t *testing.T) {
container1 = "abcdef"
container3 = "b01df00d"
universe = "10.0.3.0/24"
testAddr1 = "10.0.3.2"
testAddr2 = "10.0.4.2"
testAddr1 = "10.0.3.2/24"
testAddr2 = "10.0.4.2/24"
)
allocs, _, subnet := makeNetworkOfAllocators(2, universe)
allocs, router, subnet := makeNetworkOfAllocators(2, universe)
defer stopNetworkOfAllocators(allocs, router)
alloc := allocs[1]
defer alloc.Stop()
addr1, _ := address.ParseIP(testAddr1)
addr1, _ := address.ParseCIDR(testAddr1)
// First claim should trigger "dunno, I'm going to wait"
err := alloc.Claim(container3, addr1, true)
err := alloc.SimplyClaim(container3, addr1)
require.NoError(t, err)
// Do one allocate to ensure paxos is all done
alloc.Allocate("unused", subnet, returnFalse)
alloc.Prime()
// Do an allocate on the other peer, which we will try to claim later
addrx, err := allocs[0].Allocate(container1, subnet, returnFalse)
addrx, err := allocs[0].Allocate(container1, subnet, true, returnFalse)
router.Flush()
// Now try the claim again
err = alloc.Claim(container3, addr1, true)
err = alloc.SimplyClaim(container3, addr1)
require.NoError(t, err)
// Check we get this address back if we try an allocate
addr3, _ := alloc.Allocate(container3, subnet, returnFalse)
require.Equal(t, testAddr1, addr3.String(), "address")
addr3, _ := alloc.SimplyAllocate(container3, subnet)
require.Equal(t, testAddr1, address.MakeCIDR(subnet, addr3).String(), "address")
// one more claim should still work
err = alloc.Claim(container3, addr1, true)
err = alloc.SimplyClaim(container3, addr1)
require.NoError(t, err)
// claim for a different container should fail
err = alloc.Claim(container1, addr1, true)
err = alloc.SimplyClaim(container1, addr1)
require.Error(t, err)
// claiming the address allocated on the other peer should fail
err = alloc.Claim(container1, addrx, true)
err = alloc.SimplyClaim(container1, address.MakeCIDR(subnet, addrx))
require.Error(t, err, "claiming address allocated on other peer should fail")
// Check an address outside of our universe
addr2, _ := address.ParseIP(testAddr2)
err = alloc.Claim(container1, addr2, true)
addr2, _ := address.ParseCIDR(testAddr2)
err = alloc.SimplyClaim(container1, addr2)
require.NoError(t, err)
}
@@ -187,16 +220,13 @@ func (alloc *Allocator) pause() func() {
}
func TestCancel(t *testing.T) {
const (
CIDR = "10.0.1.7/26"
)
const cidr = "10.0.4.0/26"
router := gossip.NewTestRouter(0.0)
alloc1, subnet := makeAllocator("01:00:00:02:00:00", CIDR, 2)
alloc1, subnet := makeAllocator("01:00:00:02:00:00", cidr, 2)
alloc1.SetInterfaces(router.Connect(alloc1.ourName, alloc1))
alloc2, _ := makeAllocator("02:00:00:02:00:00", CIDR, 2)
alloc2, _ := makeAllocator("02:00:00:02:00:00", cidr, 2)
alloc2.SetInterfaces(router.Connect(alloc2.ourName, alloc2))
alloc1.claimRingForTesting(alloc1, alloc2)
alloc2.claimRingForTesting(alloc1, alloc2)
@@ -208,9 +238,9 @@ func TestCancel(t *testing.T) {
alloc1.OnGossipBroadcast(alloc2.ourName, alloc2.Encode())
// Get some IPs, so each allocator has some space
res1, _ := alloc1.Allocate("foo", subnet, returnFalse)
res1, _ := alloc1.Allocate("foo", subnet, true, returnFalse)
common.Log.Debugf("res1 = %s", res1.String())
res2, _ := alloc2.Allocate("bar", subnet, returnFalse)
res2, _ := alloc2.Allocate("bar", subnet, true, returnFalse)
common.Log.Debugf("res2 = %s", res2.String())
if res1 == res2 {
require.FailNow(t, "Error: got same ips!")
@@ -221,13 +251,13 @@ func TestCancel(t *testing.T) {
unpause := alloc2.pause()
// Use up all the IPs that alloc1 owns, so the allocation after this will prompt a request to alloc2
for i := 0; alloc1.NumFreeAddresses(subnet) > 0; i++ {
alloc1.Allocate(fmt.Sprintf("tmp%d", i), subnet, returnFalse)
for i := 0; alloc1.NumFreeAddresses(subnet.HostRange()) > 0; i++ {
alloc1.Allocate(fmt.Sprintf("tmp%d", i), subnet, true, returnFalse)
}
cancelChan := make(chan bool, 1)
doneChan := make(chan bool)
go func() {
_, ok := alloc1.Allocate("baz", subnet,
_, ok := alloc1.Allocate("baz", subnet, true,
func() bool {
select {
case <-cancelChan:
@@ -251,18 +281,18 @@ func TestCancel(t *testing.T) {
func TestCancelOnDied(t *testing.T) {
const (
CIDR = "10.0.1.7/26"
cidr = "10.0.4.0/26"
container1 = "abcdef"
)
router := gossip.NewTestRouter(0.0)
alloc1, subnet := makeAllocator("01:00:00:02:00:00", CIDR, 2)
alloc1, subnet := makeAllocator("01:00:00:02:00:00", cidr, 2)
alloc1.SetInterfaces(router.Connect(alloc1.ourName, alloc1))
alloc1.Start()
doneChan := make(chan bool)
f := func() {
_, ok := alloc1.Allocate(container1, subnet, returnFalse)
_, ok := alloc1.Allocate(container1, subnet, true, returnFalse)
doneChan <- ok == nil
}
@@ -293,62 +323,80 @@ func TestGossipShutdown(t *testing.T) {
defer alloc.Stop()
alloc.claimRingForTesting()
alloc.Allocate(container1, subnet, returnFalse)
alloc.SimplyAllocate(container1, subnet)
alloc.Shutdown()
_, err := alloc.Allocate(container2, subnet, returnFalse) // trying to allocate after shutdown should fail
_, err := alloc.SimplyAllocate(container2, subnet) // trying to allocate after shutdown should fail
require.False(t, err == nil, "no address")
CheckAllExpectedMessagesSent(alloc)
}
func TestNoFrag(t *testing.T) {
const cidr = "10.0.4.0/22"
resultChan := make(chan int)
for i := 0; i < 100; i++ {
allocs, router, subnet := makeNetworkOfAllocators(3, cidr)
allocs[1].Allocate("foo", subnet, true, returnFalse)
allocs[2].Allocate("bar", subnet, true, returnFalse)
allocs[2].actionChan <- func() {
resultChan <- len(allocs[2].ring.Entries)
}
require.True(t, <-resultChan < 6, "excessive ring fragmentation")
stopNetworkOfAllocators(allocs, router)
}
}
func TestTransfer(t *testing.T) {
const (
cidr = "10.0.1.7/22"
)
const cidr = "10.0.4.0/22"
allocs, router, subnet := makeNetworkOfAllocators(3, cidr)
alloc1 := allocs[0]
alloc2 := allocs[1]
alloc3 := allocs[2] // This will be 'master' and get the first range
defer stopNetworkOfAllocators(allocs, router)
alloc0 := allocs[0]
alloc1 := allocs[1]
alloc2 := allocs[2]
_, err := alloc2.Allocate("foo", subnet, returnFalse)
_, err := alloc1.Allocate("foo", subnet, true, returnFalse)
require.True(t, err == nil, "Failed to get address")
_, err = alloc3.Allocate("bar", subnet, returnFalse)
_, err = alloc2.Allocate("bar", subnet, true, returnFalse)
require.True(t, err == nil, "Failed to get address")
// simulation of periodic gossip
alloc2.gossip.GossipBroadcast(alloc2.Gossip())
router.Flush()
alloc2.gossip.GossipBroadcast(alloc3.Gossip())
alloc1.gossip.GossipBroadcast(alloc1.Gossip())
router.Flush()
free1 := alloc1.NumFreeAddresses(subnet.Range())
free2 := alloc2.NumFreeAddresses(subnet.Range())
router.RemovePeer(alloc1.ourName)
router.RemovePeer(alloc2.ourName)
router.RemovePeer(alloc3.ourName)
alloc2.Stop()
alloc3.Stop()
router.Flush()
require.NoError(t, alloc1.AdminTakeoverRanges(alloc2.ourName.String()))
require.NoError(t, alloc1.AdminTakeoverRanges(alloc3.ourName.String()))
router.Flush()
require.Equal(t, address.Offset(1022), alloc1.NumFreeAddresses(subnet))
_, err = alloc1.Allocate("foo", subnet, returnFalse)
require.True(t, err == nil, "Failed to get address")
alloc1.Stop()
alloc2.Stop()
router.Flush()
require.Equal(t, free1+1, alloc0.AdminTakeoverRanges(alloc1.ourName.String()))
require.Equal(t, free2+1, alloc0.AdminTakeoverRanges(alloc2.ourName.String()))
router.Flush()
require.Equal(t, address.Count(1024), alloc0.NumFreeAddresses(subnet.Range()))
_, err = alloc0.Allocate("foo", subnet, true, returnFalse)
require.True(t, err == nil, "Failed to get address")
alloc0.Stop()
}
func TestFakeRouterSimple(t *testing.T) {
const (
cidr = "10.0.1.7/22"
)
allocs, _, subnet := makeNetworkOfAllocators(2, cidr)
defer stopNetworkOfAllocators(allocs)
const cidr = "10.0.4.0/22"
allocs, router, subnet := makeNetworkOfAllocators(2, cidr)
defer stopNetworkOfAllocators(allocs, router)
alloc1 := allocs[0]
//alloc2 := allocs[1]
_, err := alloc1.Allocate("foo", subnet, returnFalse)
_, err := alloc1.Allocate("foo", subnet, true, returnFalse)
require.NoError(t, err, "Failed to get address")
}
@@ -359,10 +407,10 @@ func TestAllocatorFuzz(t *testing.T) {
nodes = 5
maxAddresses = 1000
concurrency = 5
cidr = "10.0.1.7/22"
cidr = "10.0.4.0/22"
)
allocs, _, subnet := makeNetworkOfAllocators(nodes, cidr)
defer stopNetworkOfAllocators(allocs)
allocs, router, subnet := makeNetworkOfAllocators(nodes, cidr)
defer stopNetworkOfAllocators(allocs, router)
// Test state
// For each IP issued we store the allocator
@@ -429,7 +477,7 @@ func TestAllocatorFuzz(t *testing.T) {
allocIndex := rand.Int31n(nodes)
alloc := allocs[allocIndex]
//common.Log.Infof("Allocate: asking allocator %d", allocIndex)
addr, err := alloc.Allocate(name, subnet, returnFalse)
addr, err := alloc.SimplyAllocate(name, subnet)
if err != nil {
panic(fmt.Sprintf("Could not allocate addr"))
@@ -486,7 +534,7 @@ func TestAllocatorFuzz(t *testing.T) {
//common.Log.Infof("Asking for %s (%s) on allocator %d again", res.name, addr, res.alloc)
newAddr, _ := alloc.Allocate(res.name, subnet, returnFalse)
newAddr, _ := alloc.SimplyAllocate(res.name, subnet)
oldAddr, _ := address.ParseIP(addr)
if newAddr != oldAddr {
panic(fmt.Sprintf("Got different address for repeat request for %s: %s != %s", res.name, newAddr, oldAddr))
@@ -506,8 +554,8 @@ func TestAllocatorFuzz(t *testing.T) {
allocIndex := rand.Int31n(nodes)
addressIndex := rand.Int31n(int32(subnet.Size()))
alloc := allocs[allocIndex]
addr := address.Add(subnet.Start, address.Offset(addressIndex))
err := alloc.Claim(name, addr, true)
addr := address.Add(subnet.Addr, address.Offset(addressIndex))
err := alloc.SimplyClaim(name, address.MakeCIDR(subnet, addr))
if err == nil {
noteAllocation(allocIndex, name, addr)
}
@@ -563,14 +611,36 @@ func TestAllocatorFuzz(t *testing.T) {
})
}
func TestGossipSkew(t *testing.T) {
alloc1, _ := makeAllocatorWithMockGossip(t, "01:00:00:01:00:00", "10.0.1.0/22", 2)
defer alloc1.Stop()
alloc2, _ := makeAllocatorWithMockGossip(t, "02:00:00:02:00:00", "10.0.1.0/22", 2)
alloc2.now = func() time.Time { return time.Now().Add(time.Hour * 2) }
defer alloc2.Stop()
func TestSpaceRequest(t *testing.T) {
const (
container1 = "cont-1"
container2 = "cont-2"
universe = "10.32.0.0/12"
)
allocs, router, subnet := makeNetworkOfAllocators(1, universe)
defer stopNetworkOfAllocators(allocs, router)
alloc1 := allocs[0]
if _, err := alloc1.OnGossipBroadcast(alloc2.ourName, alloc2.Encode()); err == nil {
t.Fail()
}
addr, err := alloc1.Allocate(container1, subnet, true, returnFalse)
require.Nil(t, err, "")
// free it again so the donation splits the range neatly
err = alloc1.Free(container1, addr)
require.Nil(t, err, "")
require.Equal(t, cidrRanges(universe), alloc1.OwnedRanges(), "")
// Start a new peer
alloc2, _ := makeAllocator("02:00:00:02:00:00", universe, 2)
alloc2.SetInterfaces(router.Connect(alloc2.ourName, alloc2))
alloc2.Start()
defer alloc2.Stop()
alloc2.Allocate(container2, subnet, true, returnFalse)
// Test whether the universe has been split into two equal halves (GH #2009)
require.Equal(t, cidrRanges("10.32.0.0/13"), alloc1.OwnedRanges(), "")
require.Equal(t, cidrRanges("10.40.0.0/13"), alloc2.OwnedRanges(), "")
}
func cidrRanges(s string) []address.Range {
c, _ := address.ParseCIDR(s)
return []address.Range{c.Range()}
}
+46 -19
View File
@@ -3,16 +3,20 @@ package ipam
import (
"fmt"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/net/address"
)
type claim struct {
resultChan chan<- error
ident string
addr address.Address
cidr address.CIDR
isContainer bool
noErrorOnUnknown bool
hasBeenCancelled func() bool
}
// Send an error (or nil for success) back to caller listening on resultChan
@@ -31,33 +35,41 @@ func (c *claim) sendResult(result error) {
// Try returns true for success (or failure), false if we need to try again later
func (c *claim) Try(alloc *Allocator) bool {
if !alloc.ring.Contains(c.addr) {
if c.hasBeenCancelled() {
c.Cancel()
return true
}
if !alloc.ring.Contains(c.cidr.Addr) {
// Address not within our universe; assume user knows what they are doing
alloc.infof("Ignored address %s claimed by %s - not in our universe", c.addr, c.ident)
alloc.infof("Address %s claimed by %s - not in our range", c.cidr, c.ident)
alloc.addOwned(c.ident, c.cidr, c.isContainer)
c.sendResult(nil)
return true
}
alloc.establishRing()
switch owner := alloc.ring.Owner(c.addr); owner {
// If we had heard that this container died, resurrect it
delete(alloc.dead, c.ident) // (delete is no-op if key not in map)
switch owner := alloc.ring.Owner(c.cidr.Addr); owner {
case alloc.ourName:
// success
case mesh.UnknownPeerName:
// If our ring doesn't know, it must be empty.
alloc.infof("Claim %s for %s: is in the range %s, but the allocator is not initialized yet; will try later.",
c.cidr, c.ident, alloc.universe)
if c.noErrorOnUnknown {
alloc.infof("Claim %s for %s: address allocator still initializing; will try later.", c.addr, c.ident)
c.sendResult(nil)
} else {
c.sendResult(fmt.Errorf("%s is in the range %s, but the allocator is not initialized yet", c.addr, alloc.universe.AsCIDRString()))
}
return false
default:
alloc.debugf("requesting address %s from other peer %s", c.addr, owner)
err := alloc.sendSpaceRequest(owner, address.NewRange(c.addr, 1))
alloc.debugf("requesting address %s from other peer %s", c.cidr, owner)
err := alloc.sendSpaceRequest(owner, address.NewRange(c.cidr.Addr, 1))
if err != nil { // can't speak to owner right now
if c.noErrorOnUnknown {
alloc.infof("Claim %s for %s: %s; will try later.", c.addr, c.ident, err)
alloc.infof("Claim %s for %s: %s; will try later.", c.cidr, c.ident, err)
c.sendResult(nil)
} else { // just tell the user they can't do this.
c.deniedBy(alloc, owner)
@@ -67,21 +79,36 @@ func (c *claim) Try(alloc *Allocator) bool {
}
// We are the owner, check we haven't given it to another container
switch existingIdent := alloc.findOwner(c.addr); existingIdent {
case "":
if err := alloc.space.Claim(c.addr); err == nil {
alloc.debugln("Claimed", c.addr, "for", c.ident)
alloc.addOwned(c.ident, c.addr)
existingIdent := alloc.findOwner(c.cidr.Addr)
switch {
case existingIdent == "":
// Unused address, we try to claim it:
if err := alloc.space.Claim(c.cidr.Addr); err == nil {
alloc.debugln("Claimed", c.cidr, "for", c.ident)
if c.ident == api.NoContainerID {
alloc.addOwned(c.cidr.Addr.String(), c.cidr, c.isContainer)
} else {
alloc.addOwned(c.ident, c.cidr, c.isContainer)
}
c.sendResult(nil)
} else {
c.sendResult(err)
}
case c.ident:
case (existingIdent == c.ident) || (c.ident == api.NoContainerID && existingIdent == c.cidr.Addr.String()):
// same identifier is claiming same address; that's OK
alloc.debugln("Re-Claimed", c.cidr, "for", c.ident)
c.sendResult(nil)
case existingIdent == c.cidr.Addr.String():
// Address already allocated via api.NoContainerID name and current ID is a real container ID:
c.sendResult(fmt.Errorf("address %s already in use", c.cidr))
case c.ident == api.NoContainerID:
// We do not know whether this is the same container or another one,
// but we also cannot prove otherwise, so we let it reclaim the address:
alloc.debugln("Re-Claimed", c.cidr, "for ID", c.ident, "having existing ID as", existingIdent)
c.sendResult(nil)
default:
// Addr already owned by container on this machine
c.sendResult(fmt.Errorf("address %s is already owned by %s", c.addr.String(), existingIdent))
c.sendResult(fmt.Errorf("address %s is already owned by %s", c.cidr.String(), existingIdent))
}
return true
}
@@ -91,7 +118,7 @@ func (c *claim) deniedBy(alloc *Allocator, owner mesh.PeerName) {
if found {
name = " (" + name + ")"
}
c.sendResult(fmt.Errorf("address %s is owned by other peer %s%s", c.addr.String(), owner, name))
c.sendResult(fmt.Errorf("address %s is owned by other peer %s%s", c.cidr.String(), owner, name))
}
func (c *claim) Cancel() {
+81 -48
View File
@@ -16,87 +16,120 @@ func badRequest(w http.ResponseWriter, err error) {
common.Log.Warningln("[allocator]:", err.Error())
}
func parseCIDR(w http.ResponseWriter, cidrStr string) (address.CIDR, bool) {
subnetAddr, cidr, err := address.ParseCIDR(cidrStr)
func parseCIDR(w http.ResponseWriter, cidrStr string, net bool) (address.CIDR, bool) {
var cidr address.CIDR
var err error
if net {
cidr, err = ParseCIDRSubnet(cidrStr)
} else {
cidr, err = address.ParseCIDR(cidrStr)
}
if err != nil {
badRequest(w, err)
return address.CIDR{}, false
}
if cidr.Start != subnetAddr {
badRequest(w, fmt.Errorf("Invalid subnet %s - bits after network prefix are not all zero", cidrStr))
return address.CIDR{}, false
}
return cidr, true
}
func writeAddresses(w http.ResponseWriter, cidrs []address.CIDR) {
for i, cidr := range cidrs {
fmt.Fprint(w, cidr)
if i < len(cidrs)-1 {
w.Write([]byte{' '})
}
}
}
func hasBeenCancelled(dockerCli *docker.Client, closedChan <-chan bool, ident string, checkAlive bool) func() bool {
return func() bool {
select {
case <-closedChan:
return true
default:
res := checkAlive && dockerCli != nil && dockerCli.IsContainerNotRunning(ident)
checkAlive = false // we check only once; if the container dies later we learn about that through events
return res
}
}
}
func cancellationErr(w http.ResponseWriter, err error) bool {
if _, ok := err.(*errorCancelled); ok {
common.Log.Infoln("[allocator]:", err.Error())
fmt.Fprint(w, "cancelled")
return true
}
return false
}
func (alloc *Allocator) handleHTTPAllocate(dockerCli *docker.Client, w http.ResponseWriter, ident string, checkAlive bool, subnet address.CIDR) {
closedChan := w.(http.CloseNotifier).CloseNotify()
addr, err := alloc.Allocate(ident, subnet.HostRange(),
func() bool {
select {
case <-closedChan:
return true
default:
res := checkAlive && dockerCli != nil && dockerCli.IsContainerNotRunning(ident)
checkAlive = false // we check only once; if the container dies later we learn about that through events
return res
}
})
addr, err := alloc.Allocate(ident, subnet, checkAlive,
hasBeenCancelled(dockerCli, w.(http.CloseNotifier).CloseNotify(), ident, checkAlive))
if err != nil {
if _, ok := err.(*errorCancelled); ok { // cancellation is not really an error
common.Log.Infoln("[allocator]:", err.Error())
fmt.Fprint(w, "cancelled")
return
if !cancellationErr(w, err) {
badRequest(w, err)
}
badRequest(w, err)
return
}
fmt.Fprintf(w, "%s/%d", addr, subnet.PrefixLen)
}
// HandleHTTP wires up ipams HTTP endpoints to the provided mux.
func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CIDR, dockerCli *docker.Client) {
router.Methods("PUT").Path("/ip/{id}/{ip}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
ident := vars["id"]
ipStr := vars["ip"]
noErrorOnUnknown := r.FormValue("noErrorOnUnknown") == "true"
if ip, err := address.ParseIP(ipStr); err != nil {
badRequest(w, err)
return
} else if err := alloc.Claim(ident, ip, noErrorOnUnknown); err != nil {
func (alloc *Allocator) handleHTTPClaim(dockerCli *docker.Client, w http.ResponseWriter, ident string, cidr address.CIDR, checkAlive, noErrorOnUnknown bool) {
err := alloc.Claim(ident, cidr, checkAlive, noErrorOnUnknown,
hasBeenCancelled(dockerCli, w.(http.CloseNotifier).CloseNotify(), ident, checkAlive))
if err != nil {
if !cancellationErr(w, err) {
badRequest(w, fmt.Errorf("Unable to claim: %s", err))
return
}
return
}
w.WriteHeader(204)
}
w.WriteHeader(204)
// HandleHTTP wires up ipams HTTP endpoints to the provided mux.
func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CIDR, tracker string, dockerCli *docker.Client) {
router.Methods("GET").Path("/ipinfo/defaultsubnet").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s", defaultSubnet)
})
router.Methods("PUT").Path("/ip/{id}/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
if cidr, ok := parseCIDR(w, vars["ip"]+"/"+vars["prefixlen"], false); ok {
ident := vars["id"]
checkAlive := r.FormValue("check-alive") == "true"
noErrorOnUnknown := r.FormValue("noErrorOnUnknown") == "true"
alloc.handleHTTPClaim(dockerCli, w, ident, cidr, checkAlive, noErrorOnUnknown)
}
})
router.Methods("GET").Path("/ring").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
alloc.Prime()
})
router.Methods("GET").Path("/ip/{id}/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
if subnet, ok := parseCIDR(w, vars["ip"]+"/"+vars["prefixlen"]); ok {
addr, err := alloc.Lookup(vars["id"], subnet.HostRange())
if subnet, ok := parseCIDR(w, vars["ip"]+"/"+vars["prefixlen"], true); ok {
cidrs, err := alloc.Lookup(vars["id"], subnet.HostRange())
if err != nil {
http.NotFound(w, r)
return
}
fmt.Fprintf(w, "%s/%d", addr, subnet.PrefixLen)
writeAddresses(w, cidrs)
}
})
router.Methods("GET").Path("/ip/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
addr, err := alloc.Lookup(mux.Vars(r)["id"], defaultSubnet.HostRange())
addrs, err := alloc.Lookup(mux.Vars(r)["id"], defaultSubnet.HostRange())
if err != nil {
http.NotFound(w, r)
return
}
fmt.Fprintf(w, "%s/%d", addr, defaultSubnet.PrefixLen)
writeAddresses(w, addrs)
})
router.Methods("POST").Path("/ip/{id}/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
if subnet, ok := parseCIDR(w, vars["ip"]+"/"+vars["prefixlen"]); ok {
if subnet, ok := parseCIDR(w, vars["ip"]+"/"+vars["prefixlen"], true); ok {
alloc.handleHTTPAllocate(dockerCli, w, vars["id"], r.FormValue("check-alive") == "true", subnet)
}
})
@@ -138,11 +171,11 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID
router.Methods("DELETE").Path("/peer/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ident := mux.Vars(r)["id"]
if err := alloc.AdminTakeoverRanges(ident); err != nil {
badRequest(w, err)
return
}
transferred := alloc.AdminTakeoverRanges(ident)
fmt.Fprintf(w, "%d IPs taken over from %s\n", transferred, ident)
})
w.WriteHeader(204)
router.Methods("GET").Path("/ipinfo/tracker").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, tracker)
})
}
+14 -25
View File
@@ -14,7 +14,6 @@ import (
"github.com/stretchr/testify/require"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/net/address"
wt "github.com/weaveworks/weave/testing"
)
func HTTPPost(t *testing.T, url string) string {
@@ -44,7 +43,7 @@ func listenHTTP(alloc *Allocator, subnet address.CIDR) int {
router.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, fmt.Sprintln(alloc))
})
alloc.HandleHTTP(router, subnet, nil)
alloc.HandleHTTP(router, subnet, "", nil)
httpListener, err := net.Listen("tcp", ":0")
if err != nil {
@@ -81,7 +80,7 @@ func TestHttp(t *testing.T) {
)
alloc, _ := makeAllocatorWithMockGossip(t, "08:00:27:01:c3:9a", universe, 1)
_, cidr, _ := address.ParseCIDR(universe)
cidr, _ := address.ParseCIDR(universe)
port := listenHTTP(alloc, cidr)
alloc.claimRingForTesting()
@@ -123,7 +122,7 @@ func TestBadHttp(t *testing.T) {
alloc, _ := makeAllocatorWithMockGossip(t, "08:00:27:01:c3:9a", testCIDR1, 1)
defer alloc.Stop()
_, cidr, _ := address.ParseCIDR(testCIDR1)
cidr, _ := address.ParseCIDR(testCIDR1)
port := listenHTTP(alloc, cidr)
alloc.claimRingForTesting()
@@ -145,40 +144,30 @@ func TestBadHttp(t *testing.T) {
}
func TestHTTPCancel(t *testing.T) {
wt.RunWithTimeout(t, 2*time.Second, func() {
impTestHTTPCancel(t)
})
}
func impTestHTTPCancel(t *testing.T) {
var (
containerID = "deadbeef"
testCIDR1 = "10.0.3.0/29"
)
alloc, _ := makeAllocatorWithMockGossip(t, "08:00:27:01:c3:9a", testCIDR1, 1)
// Say quorum=2, so the allocate won't go ahead
alloc, _ := makeAllocatorWithMockGossip(t, "08:00:27:01:c3:9a", testCIDR1, 2)
defer alloc.Stop()
alloc.claimRingForTesting()
_, cidr, _ := address.ParseCIDR(testCIDR1)
ExpectBroadcastMessage(alloc, nil) // trying to form consensus
cidr, _ := address.ParseCIDR(testCIDR1)
port := listenHTTP(alloc, cidr)
// Stop the alloc so nothing actually works
unpause := alloc.pause()
// Ask the http server for a new address
done := make(chan *http.Response)
req, _ := http.NewRequest("POST", allocURL(port, testCIDR1, containerID), nil)
// On another goroutine, wait for a bit then cancel the request
go func() {
res, _ := http.DefaultClient.Do(req)
done <- res
time.Sleep(100 * time.Millisecond)
common.Log.Debug("Cancelling allocate")
http.DefaultTransport.(*http.Transport).CancelRequest(req)
}()
time.Sleep(100 * time.Millisecond)
fmt.Println("Cancelling allocate")
http.DefaultTransport.(*http.Transport).CancelRequest(req)
unpause()
res := <-done
res, _ := http.DefaultClient.Do(req)
if res != nil {
require.FailNow(t, "Error: Allocate returned non-nil")
body, _ := ioutil.ReadAll(res.Body)
require.FailNow(t, "Error: Allocate returned non-nil", string(body))
}
}
+44
View File
@@ -0,0 +1,44 @@
package paxos
type Participant interface {
GossipState() GossipState
Update(from GossipState) bool
SetQuorum(uint)
Propose()
Think() bool
Consensus() (bool, AcceptedValue)
IsElector() bool
}
type Observer struct {
}
func NewObserver() Participant {
return &Observer{}
}
func (observer *Observer) GossipState() GossipState {
return nil
}
func (observer *Observer) Update(from GossipState) bool {
return false
}
func (observer *Observer) Propose() {
}
func (observer *Observer) SetQuorum(uint) {
}
func (observer *Observer) Think() bool {
return false
}
func (observer *Observer) Consensus() (bool, AcceptedValue) {
return false, AcceptedValue{}
}
func (observer *Observer) IsElector() bool {
return false
}
+17 -5
View File
@@ -1,7 +1,7 @@
package paxos
import (
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/mesh"
)
// The node identifier. The use of the UID here is important: Paxos
@@ -80,6 +80,10 @@ func NewNode(name mesh.PeerName, uid mesh.PeerUID, quorum uint) *Node {
}
}
func (node *Node) SetQuorum(quorum uint) {
node.quorum = quorum
}
func (node *Node) GossipState() GossipState {
return node.knows
}
@@ -124,6 +128,9 @@ func max(a uint, b uint) uint {
// simply a matter of gossipping a new proposal that supersedes all
// others.
func (node *Node) Propose() {
if node.quorum == 0 {
panic("Paxos node.Propose() called with no quorum set")
}
// Find the highest round number around
round := uint(0)
@@ -234,6 +241,9 @@ func (node *Node) pickValue() Value {
// Has a consensus been reached, based on the known claims of other nodes?
func (node *Node) Consensus() (bool, AcceptedValue) {
if node.quorum == 0 {
return false, AcceptedValue{}
}
counts := map[ProposalID]uint{}
for _, claims := range node.knows {
@@ -250,14 +260,16 @@ func (node *Node) Consensus() (bool, AcceptedValue) {
return false, AcceptedValue{}
}
func (node *Node) IsElector() bool {
return true
}
type Status struct {
Elector bool
KnownNodes int
Quorum uint
}
func NewStatus(node *Node) *Status {
if node == nil {
return nil
}
return &Status{len(node.knows), node.quorum}
return &Status{true, len(node.knows), node.quorum}
}
+3 -3
View File
@@ -6,7 +6,7 @@ import (
"testing"
"time"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/mesh"
)
type TestNode struct {
@@ -300,14 +300,14 @@ func (m *Model) validate() {
for i := range m.nodes {
ok, val := m.nodes[i].Consensus()
if !ok {
//m.dump()
m.dump()
m.t.Fatal("Node doesn't know about consensus")
}
firstConsensus := m.nodes[i].firstConsensus
if firstConsensus.Origin.valid() &&
firstConsensus.Origin != val.Origin {
//m.dump()
m.dump()
m.t.Fatal("Consensus mismatch")
}
+24
View File
@@ -0,0 +1,24 @@
package ipam
type prime struct {
resultChan chan<- struct{}
}
func (c *prime) Try(alloc *Allocator) bool {
if !alloc.ring.Empty() {
close(c.resultChan)
return true
}
alloc.establishRing()
return false
}
func (c *prime) Cancel() {
close(c.resultChan)
}
func (c *prime) ForContainer(ident string) bool {
return false
}
+4 -3
View File
@@ -3,8 +3,9 @@ package ring
import (
"sort"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/net/address"
)
@@ -13,7 +14,7 @@ type entry struct {
Token address.Address // The start of this range
Peer mesh.PeerName // Who owns this range
Version uint32 // Version of this range
Free address.Offset // Number of free IPs in this range
Free address.Count // Number of free IPs in this range
}
func (e *entry) Equal(e2 *entry) bool {
@@ -21,7 +22,7 @@ func (e *entry) Equal(e2 *entry) bool {
e.Version == e2.Version
}
func (e *entry) update(peername mesh.PeerName, free address.Offset) {
func (e *entry) update(peername mesh.PeerName, free address.Count) {
e.Peer = peername
e.Version++
e.Free = free
-31
View File
@@ -1,31 +0,0 @@
package ring
/* Exported variables for monitoring and management */
import (
"expvar"
"strconv"
)
var (
expRingSize = expvar.NewMap("ipam.ringSize")
expRingEntries = expvar.NewMap("ipam.ringEntries")
)
type _int int
func (i _int) String() string {
return strconv.Itoa(int(i))
}
type _uint32 uint32
func (i _uint32) String() string {
return strconv.FormatUint(uint64(i), 10)
}
func (r *Ring) updateExportedVariables() {
ringName := r.Start.String()
expRingSize.Set(ringName, _uint32(r.End-r.Start))
expRingEntries.Set(ringName, _int(len(r.Entries)))
}
+175 -107
View File
@@ -12,17 +12,21 @@ import (
"sort"
"time"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/net/address"
)
type OnUpdate func(prev, curr []address.Range, local bool)
// Ring represents the ring itself
type Ring struct {
Start, End address.Address // [min, max) tokens in this ring. Due to wrapping, min == max (effectively)
Peer mesh.PeerName // name of peer owning this ring instance
Entries entries // list of entries sorted by token
Seeds []mesh.PeerName // peers with which the ring was seeded
onUpdate OnUpdate
}
func (r *Ring) assertInvariants() {
@@ -37,42 +41,52 @@ var (
ErrNotSorted = errors.New("Ring not sorted")
ErrTokenRepeated = errors.New("Token appears twice in ring")
ErrTokenOutOfRange = errors.New("Token is out of range")
ErrDifferentSeeds = errors.New("Received ring was seeded differently from ours!")
ErrDifferentRange = errors.New("Received range differs from ours!")
ErrNewerVersion = errors.New("Received new version for entry I own!")
ErrInvalidEntry = errors.New("Received invalid state update!")
ErrEntryInMyRange = errors.New("Received new entry in my range!")
ErrNotFound = errors.New("No entries for peer found")
ErrDifferentSeeds = errors.New("Received ring was seeded differently from ours")
ErrDifferentRange = errors.New("Received range differs from ours")
)
func errInconsistentEntry(mine, theirs *entry) error {
return fmt.Errorf("Inconsistent entries for %s: owned by %s but incoming message says %s", mine.Token, mine.Peer, theirs.Peer)
}
func errEntryInMyRange(theirs *entry) error {
return fmt.Errorf("Peer %s says it owns the IP range from %s, which I think I own", theirs.Peer, theirs.Token)
}
func errNewerVersion(mine, theirs *entry) error {
return fmt.Errorf("Received update for IP range I own at %s v%d: incoming message says owner %s v%d", mine.Token, mine.Version, theirs.Peer, theirs.Version)
}
func (r *Ring) checkInvariants() error {
if !sort.IsSorted(r.Entries) {
return r.checkEntries(r.Entries)
}
func (r *Ring) checkEntries(entries entries) error {
if !sort.IsSorted(entries) {
return ErrNotSorted
}
// Check no token appears twice
// We know it's sorted...
for i := 1; i < len(r.Entries); i++ {
if r.Entries[i-1].Token == r.Entries[i].Token {
for i := 1; i < len(entries); i++ {
if entries[i-1].Token == entries[i].Token {
return ErrTokenRepeated
}
}
if len(r.Entries) == 0 {
if len(entries) == 0 {
return nil
}
// Check tokens are in range
if r.Entries.entry(0).Token < r.Start {
if entries.entry(0).Token < r.Start {
return ErrTokenOutOfRange
}
if r.Entries.entry(-1).Token >= r.End {
if entries.entry(-1).Token >= r.End {
return ErrTokenOutOfRange
}
// Check all the freespaces are in range
for i, entry := range r.Entries {
next := r.Entries.entry(i + 1)
for i, entry := range entries {
next := entries.entry(i + 1)
distance := r.distance(entry.Token, next.Token)
if entry.Free > distance {
@@ -83,27 +97,46 @@ func (r *Ring) checkInvariants() error {
return nil
}
func (r *Ring) trackUpdates() func() {
return r.trackUpdatesOfPeer(r.Peer)
}
func (r *Ring) trackUpdatesOfPeer(peer mesh.PeerName) func() {
if r.onUpdate == nil {
return func() {}
}
ranges := r.OwnedRangesOfPeer(peer)
return func() { r.onUpdate(ranges, r.OwnedRangesOfPeer(peer), peer == r.Peer) }
}
// New creates an empty ring belonging to peer.
func New(start, end address.Address, peer mesh.PeerName) *Ring {
func New(start, end address.Address, peer mesh.PeerName, f OnUpdate) *Ring {
common.Assert(start < end)
ring := &Ring{Start: start, End: end, Peer: peer, Entries: make([]*entry, 0)}
ring.updateExportedVariables()
ring := &Ring{Start: start, End: end, Peer: peer, Entries: make([]*entry, 0), onUpdate: f}
return ring
}
func (r *Ring) Restore(other *Ring) {
defer r.trackUpdates()()
onUpdate := r.onUpdate
*r = *other
r.onUpdate = onUpdate
}
func (r *Ring) Range() address.Range {
return address.Range{Start: r.Start, End: r.End}
}
// Returns the distance between two tokens on this ring, dealing
// with ranges which cross the origin
func (r *Ring) distance(start, end address.Address) address.Offset {
func (r *Ring) distance(start, end address.Address) address.Count {
if end > start {
return address.Offset(end - start)
return address.Count(end - start)
}
return address.Offset((r.End - start) + (end - r.Start))
return address.Count((r.End - start) + (end - r.Start))
}
// GrantRangeToHost modifies the ring such that range [start, end)
@@ -115,8 +148,8 @@ func (r *Ring) GrantRangeToHost(start, end address.Address, peer mesh.PeerName)
//fmt.Printf("%s GrantRangeToHost [%v,%v) -> %s\n", r.Peer, start, end, peer)
r.assertInvariants()
defer r.trackUpdates()()
defer r.assertInvariants()
defer r.updateExportedVariables()
// ----------------- Start of Checks -----------------
@@ -178,43 +211,69 @@ func (r *Ring) GrantRangeToHost(start, end address.Address, peer mesh.PeerName)
r.Entries.insert(entry{Token: end, Peer: r.Peer, Free: endFree})
}
// Merge the given ring into this ring and return any new ranges added
func (r *Ring) Merge(gossip Ring) error {
// Merge the given ring into this ring and indicate whether this ring
// got updated as a result.
func (r *Ring) Merge(gossip Ring) (bool, error) {
r.assertInvariants()
defer r.assertInvariants()
defer r.updateExportedVariables()
defer r.trackUpdates()()
// Don't panic when checking the gossiped in ring.
// In this case just return any error found.
if err := gossip.checkInvariants(); err != nil {
return err
return false, err
}
if len(gossip.Seeds) > 0 && len(r.Seeds) > 0 {
if len(gossip.Seeds) != len(r.Seeds) {
return ErrDifferentSeeds
return false, ErrDifferentSeeds
}
for i, seed := range gossip.Seeds {
if seed != r.Seeds[i] {
return ErrDifferentSeeds
return false, ErrDifferentSeeds
}
}
}
if r.Start != gossip.Start || r.End != gossip.End {
return ErrDifferentRange
return false, ErrDifferentRange
}
// Now merge their ring with yours, in a temporary ring.
var result entries
addToResult := func(e entry) { result = append(result, &e) }
result, updated, err := r.Entries.merge(gossip.Entries, r.Peer)
if err != nil {
return false, err
}
if err := r.checkEntries(result); err != nil {
return false, fmt.Errorf("Merge of incoming data causes: %s", err)
}
if len(r.Seeds) == 0 {
r.Seeds = gossip.Seeds
}
r.Entries = result
return updated, nil
}
// Merge other entries into ours, and complain when that stomps on
// entries belonging to ourPeer. Returns the merged entries and an
// indication whether the merge resulted in any changes, i.e. the
// result differs from the original.
func (es entries) merge(other entries, ourPeer mesh.PeerName) (result entries, updated bool, err error) {
var mine, theirs *entry
var previousOwner *mesh.PeerName
// i is index into r.Entries; j is index into gossip.Entries
addToResult := func(e entry) { result = append(result, &e) }
addTheirs := func(e entry) {
addToResult(e)
updated = true
previousOwner = nil
}
// i is index into es; j is index into other
var i, j int
for i < len(r.Entries) && j < len(gossip.Entries) {
mine, theirs = r.Entries[i], gossip.Entries[j]
for i < len(es) && j < len(other) {
mine, theirs = es[i], other[j]
switch {
case mine.Token < theirs.Token:
addToResult(*mine)
@@ -222,56 +281,52 @@ func (r *Ring) Merge(gossip Ring) error {
i++
case mine.Token > theirs.Token:
// insert, checking that a range owned by us hasn't been split
if previousOwner != nil && *previousOwner == r.Peer && theirs.Peer != r.Peer {
return ErrEntryInMyRange
if previousOwner != nil && *previousOwner == ourPeer && theirs.Peer != ourPeer {
err = errEntryInMyRange(theirs)
return
}
addToResult(*theirs)
previousOwner = nil
addTheirs(*theirs)
j++
case mine.Token == theirs.Token:
// merge
switch {
case mine.Version >= theirs.Version:
if mine.Version == theirs.Version && !mine.Equal(theirs) {
common.Log.Debugf("Error merging entries at %s - %v != %v", mine.Token, mine, theirs)
return ErrInvalidEntry
err = errInconsistentEntry(mine, theirs)
return
}
addToResult(*mine)
previousOwner = &mine.Peer
case mine.Version < theirs.Version:
if mine.Peer == r.Peer { // We shouldn't receive updates to our own tokens
return ErrNewerVersion
if mine.Peer == ourPeer { // We shouldn't receive updates to our own tokens
err = errNewerVersion(mine, theirs)
return
}
addToResult(*theirs)
previousOwner = nil
addTheirs(*theirs)
}
i++
j++
}
}
// At this point, either i is at the end of r or j is at the end
// of gossip, so copy over the remaining entries.
// At this point, either i is at the end of es or j is at the end
// of other, so copy over the remaining entries.
for ; i < len(r.Entries); i++ {
mine = r.Entries[i]
for ; i < len(es); i++ {
mine = es[i]
addToResult(*mine)
}
for ; j < len(gossip.Entries); j++ {
theirs = gossip.Entries[j]
if previousOwner != nil && *previousOwner == r.Peer && theirs.Peer != r.Peer {
return ErrEntryInMyRange
for ; j < len(other); j++ {
theirs = other[j]
if previousOwner != nil && *previousOwner == ourPeer && theirs.Peer != ourPeer {
err = errEntryInMyRange(theirs)
return
}
addToResult(*theirs)
previousOwner = nil
addTheirs(*theirs)
}
if len(r.Seeds) == 0 {
r.Seeds = gossip.Seeds
}
r.Entries = result
return nil
return
}
// Empty returns true if the ring has no entries
@@ -304,10 +359,14 @@ func (r *Ring) splitRangesOverZero(ranges []address.Range) []address.Range {
// ranges are owned by this peer. Will split ranges which
// span 0 in the ring.
func (r *Ring) OwnedRanges() (result []address.Range) {
return r.OwnedRangesOfPeer(r.Peer)
}
func (r *Ring) OwnedRangesOfPeer(peer mesh.PeerName) (result []address.Range) {
r.assertInvariants()
for i, entry := range r.Entries {
if entry.Peer == r.Peer {
if entry.Peer == peer {
nextEntry := r.Entries.entry(i + 1)
result = append(result, address.Range{Start: entry.Token, End: nextEntry.Token})
}
@@ -316,40 +375,57 @@ func (r *Ring) OwnedRanges() (result []address.Range) {
return r.splitRangesOverZero(result)
}
// For printing status
type RangeInfo struct {
Peer mesh.PeerName
address.Range
Version uint32
}
func (r *Ring) AllRangeInfo() (result []RangeInfo) {
for i, entry := range r.Entries {
nextEntry := r.Entries.entry(i + 1)
ranges := []address.Range{{Start: entry.Token, End: nextEntry.Token}}
ranges = r.splitRangesOverZero(ranges)
for _, r := range ranges {
result = append(result, RangeInfo{entry.Peer, r, entry.Version})
}
}
return
}
// ClaimForPeers claims the entire ring for the array of peers passed
// in. Only works for empty rings.
// in. Only works for empty rings. Each claimed range is CIDR-aligned.
func (r *Ring) ClaimForPeers(peers []mesh.PeerName) {
common.Assert(r.Empty())
defer r.trackUpdates()()
defer r.assertInvariants()
defer r.updateExportedVariables()
totalSize := r.distance(r.Start, r.End)
share := totalSize/address.Offset(len(peers)) + 1
remainder := totalSize % address.Offset(len(peers))
pos := r.Start
for i, peer := range peers {
if address.Offset(i) == remainder {
share--
if share == 0 {
break
}
}
if e, found := r.Entries.get(pos); found {
e.update(peer, share)
} else {
r.Entries.insert(entry{Token: pos, Peer: peer, Free: share})
}
pos += address.Address(share)
}
common.Assert(pos == r.End)
defer func() {
e := r.Entries[len(r.Entries)-1]
common.Assert(address.Add(e.Token, address.Offset(e.Free)) == r.End)
}()
r.subdivide(r.Start, r.End, peers)
r.Seeds = peers
}
// subdivide subdivides the [from,to) CIDR for the given peers into
// CIDR-aligned subranges.
func (r *Ring) subdivide(from, to address.Address, peers []mesh.PeerName) {
share := address.Length(to, from)
if share == 0 {
return
}
if share == 1 || len(peers) == 1 {
r.Entries.insert(entry{Token: from, Peer: peers[0], Free: share})
return
}
mid := address.Add(from, address.Offset(share/2))
r.subdivide(from, mid, peers[:len(peers)/2])
r.subdivide(address.Add(mid, address.Offset(share%2)), to, peers[len(peers)/2:])
}
func (r *Ring) FprintWithNicknames(w io.Writer, m map[mesh.PeerName]string) {
for _, entry := range r.Entries {
nickname, found := m[entry.Peer]
@@ -371,11 +447,10 @@ func (r *Ring) String() string {
// ReportFree is used by the allocator to tell the ring how many free
// ips are in a given range, so that ChoosePeersToAskForSpace can make
// more intelligent decisions.
func (r *Ring) ReportFree(freespace map[address.Address]address.Offset) {
// more intelligent decisions. Returns true if any changes made.
func (r *Ring) ReportFree(freespace map[address.Address]address.Count) (updated bool) {
r.assertInvariants()
defer r.assertInvariants()
defer r.updateExportedVariables()
common.Assert(!r.Empty())
entries := r.Entries
@@ -402,15 +477,17 @@ func (r *Ring) ReportFree(freespace map[address.Address]address.Offset) {
// Check we're not reporting more space than the range
entry, next := entries.entry(i), entries.entry(i+1)
maxSize := r.distance(entry.Token, next.Token)
common.Assert(free <= maxSize)
common.Assert(free <= address.Count(maxSize))
if entries[i].Free == free {
return
continue
}
entries[i].Free = free
entries[i].Version++
updated = true
}
return
}
type weightedPeer struct {
@@ -427,10 +504,7 @@ func (ws weightedPeers) Swap(i, j int) { ws[i], ws[j] = ws[j], ws[i] }
// ChoosePeersToAskForSpace returns all peers we can ask for space in
// the range [start, end), in weighted-random order. Assumes start<end.
func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []mesh.PeerName {
var (
sum address.Offset
totalSpacePerPeer = make(map[mesh.PeerName]address.Offset) // Compute total free space per peer
)
totalSpacePerPeer := make(map[mesh.PeerName]address.Count)
// iterate through tokens
for i, entry := range r.Entries {
@@ -452,7 +526,6 @@ func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []mesh.PeerN
}
totalSpacePerPeer[entry.Peer] += entry.Free
sum += entry.Free
}
// Compute weighted random numbers, then sort.
@@ -481,28 +554,23 @@ func (r *Ring) PickPeerForTransfer(isValid func(mesh.PeerName) bool) mesh.PeerNa
// Transfer will mark all entries associated with 'from' peer as owned by 'to' peer
// and return ranges indicating the new space we picked up
func (r *Ring) Transfer(from, to mesh.PeerName) ([]address.Range, error) {
func (r *Ring) Transfer(from, to mesh.PeerName) []address.Range {
r.assertInvariants()
defer r.trackUpdates()()
defer r.trackUpdatesOfPeer(from)()
defer r.assertInvariants()
defer r.updateExportedVariables()
var newRanges []address.Range
found := false
for i, entry := range r.Entries {
if entry.Peer == from {
found = true
entry.Peer = to
entry.Version++
newRanges = append(newRanges, address.Range{Start: entry.Token, End: r.Entries.entry(i + 1).Token})
}
}
if !found {
return nil, ErrNotFound
}
return r.splitRangesOverZero(newRanges), nil
return r.splitRangesOverZero(newRanges)
}
// Contains returns true if addr is in this ring
+160 -113
View File
@@ -8,8 +8,9 @@ import (
"testing"
"github.com/stretchr/testify/require"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/net/address"
)
@@ -18,7 +19,8 @@ var (
peer2name, _ = mesh.PeerNameFromString("02:00:00:00:02:00")
peer3name, _ = mesh.PeerNameFromString("03:00:00:00:02:00")
start, end = ParseIP("10.0.0.0"), ParseIP("10.0.0.255")
start, end = ParseIP("10.0.0.0"), ParseIP("10.0.1.0")
dot8 = ParseIP("10.0.0.8")
dot10, dot245 = ParseIP("10.0.0.10"), ParseIP("10.0.0.245")
dot250 = ParseIP("10.0.0.250")
middle = ParseIP("10.0.0.128")
@@ -29,8 +31,17 @@ func ParseIP(s string) address.Address {
return addr
}
func merge(r1, r2 *Ring) error {
_, err := r1.Merge(*r2)
return err
}
func NewRing(start, end address.Address, peer mesh.PeerName) *Ring {
return New(start, end, peer, nil)
}
func TestInvariants(t *testing.T) {
ring := New(start, end, peer1name)
ring := NewRing(start, end, peer1name)
// Check ring is sorted
ring.Entries = []*entry{{Token: dot245, Peer: peer1name}, {Token: dot10, Peer: peer2name}}
@@ -41,7 +52,7 @@ func TestInvariants(t *testing.T) {
require.True(t, ring.checkInvariants() == ErrTokenRepeated, "Expected error")
// Check tokens are in bounds
ring = New(dot10, dot245, peer1name)
ring = NewRing(dot10, dot245, peer1name)
ring.Entries = []*entry{{Token: start, Peer: peer1name}}
require.True(t, ring.checkInvariants() == ErrTokenOutOfRange, "Expected error")
@@ -50,7 +61,7 @@ func TestInvariants(t *testing.T) {
}
func TestInsert(t *testing.T) {
ring := New(start, end, peer1name)
ring := NewRing(start, end, peer1name)
ring.Entries = []*entry{{Token: start, Peer: peer1name, Free: 255}}
require.Panics(t, func() {
@@ -59,17 +70,23 @@ func TestInsert(t *testing.T) {
ring.Entries.entry(0).Free = 0
ring.Entries.insert(entry{Token: dot245, Peer: peer1name})
ring2 := New(start, end, peer1name)
ring2.Entries = []*entry{{Token: start, Peer: peer1name, Free: 0}, {Token: dot245, Peer: peer1name}}
require.Equal(t, ring2, ring)
check := []RangeInfo{
{Peer: peer1name, Range: address.Range{Start: start, End: dot245}},
{Peer: peer1name, Range: address.Range{Start: dot245, End: end}},
}
require.Equal(t, check, ring.AllRangeInfo())
ring.Entries.insert(entry{Token: dot10, Peer: peer1name})
ring2.Entries = []*entry{{Token: start, Peer: peer1name, Free: 0}, {Token: dot10, Peer: peer1name}, {Token: dot245, Peer: peer1name}}
require.Equal(t, ring2, ring)
check2 := []RangeInfo{
{Peer: peer1name, Range: address.Range{Start: start, End: dot10}},
{Peer: peer1name, Range: address.Range{Start: dot10, End: dot245}},
{Peer: peer1name, Range: address.Range{Start: dot245, End: end}},
}
require.Equal(t, check2, ring.AllRangeInfo())
}
func TestBetween(t *testing.T) {
ring1 := New(start, end, peer1name)
ring1 := NewRing(start, end, peer1name)
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 255}}
// First off, in a ring where everything is owned by the peer
@@ -111,29 +128,29 @@ func TestBetween(t *testing.T) {
}
func TestGrantSimple(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
// Claim everything for peer1
ring1.ClaimItAll()
require.Equal(t, entries{{Token: start, Peer: peer1name, Free: 255}}, ring1.Entries)
require.Equal(t, entries{{Token: start, Peer: peer1name, Free: 256}}, ring1.Entries)
// Now grant everything to peer2
ring1.GrantRangeToHost(start, end, peer2name)
ring2.Entries = []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}}
ring2.Entries = []*entry{{Token: start, Peer: peer2name, Free: 256, Version: 1}}
require.Equal(t, ring2.Entries, ring1.Entries)
// Now spint back to peer 1
ring2.GrantRangeToHost(dot10, end, peer1name)
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 10, Version: 2},
{Token: dot10, Peer: peer1name, Free: 245}}
{Token: dot10, Peer: peer1name, Free: 246}}
require.Equal(t, ring2.Entries, ring1.Entries)
// And spint back to peer 2 again
ring1.GrantRangeToHost(dot245, end, peer2name)
require.Equal(t, entries{{Token: start, Peer: peer2name, Free: 10, Version: 2},
{Token: dot10, Peer: peer1name, Free: 235, Version: 1},
{Token: dot245, Peer: peer2name, Free: 10}}, ring1.Entries)
{Token: dot245, Peer: peer2name, Free: 11}}, ring1.Entries)
// Grant range spanning a live token
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 10, Version: 2},
@@ -146,19 +163,19 @@ func TestGrantSimple(t *testing.T) {
}
func TestGrantSplit(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
// Claim everything for peer1
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 255}}
ring2.Merge(*ring1)
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 256}}
merge(ring2, ring1)
require.Equal(t, ring2.Entries, ring1.Entries)
// Now grant a split range to peer2
ring1.GrantRangeToHost(dot10, dot245, peer2name)
require.Equal(t, entries{{Token: start, Peer: peer1name, Free: 10, Version: 1},
{Token: dot10, Peer: peer2name, Free: 235},
{Token: dot245, Peer: peer1name, Free: 10}}, ring1.Entries)
{Token: dot245, Peer: peer1name, Free: 11}}, ring1.Entries)
ring1.assertInvariants()
@@ -169,22 +186,22 @@ func TestGrantSplit(t *testing.T) {
require.Equal(t, entries{{Token: start, Peer: peer1name, Free: 10, Version: 2},
{Token: dot10, Peer: peer2name, Free: 118, Version: 1},
{Token: middle, Peer: peer2name, Free: 117, Version: 1},
{Token: dot245, Peer: peer1name, Free: 10, Version: 0}}, ring1.Entries)
{Token: dot245, Peer: peer1name, Free: 11, Version: 0}}, ring1.Entries)
ring1.assertInvariants()
}
func TestMergeSimple(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
// Claim everything for peer1
ring1.ClaimItAll()
ring1.GrantRangeToHost(middle, end, peer2name)
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
require.Equal(t, entries{{Token: start, Peer: peer1name, Free: 128, Version: 1},
{Token: middle, Peer: peer2name, Free: 127}}, ring1.Entries)
{Token: middle, Peer: peer2name, Free: 128}}, ring1.Entries)
require.Equal(t, ring2.Entries, ring1.Entries)
@@ -193,47 +210,48 @@ func TestMergeSimple(t *testing.T) {
ring1.GrantRangeToHost(start, middle, peer2name)
ring2.GrantRangeToHost(middle, end, peer1name)
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, ring1.Merge(*ring2))
require.NoError(t, merge(ring2, ring1))
require.NoError(t, merge(ring1, ring2))
require.Equal(t, entries{{Token: start, Peer: peer2name, Free: 128, Version: 2},
{Token: middle, Peer: peer1name, Free: 127, Version: 1}}, ring1.Entries)
{Token: middle, Peer: peer1name, Free: 128, Version: 1}}, ring1.Entries)
require.Equal(t, ring2.Entries, ring1.Entries)
}
func TestMergeErrors(t *testing.T) {
// Cannot Merge in an invalid ring
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
ring2.Entries = []*entry{{Token: middle, Peer: peer2name}, {Token: start, Peer: peer2name}}
require.True(t, ring1.Merge(*ring2) == ErrNotSorted, "Expected ErrNotSorted")
require.True(t, merge(ring1, ring2) == ErrNotSorted, "Expected ErrNotSorted")
// Should Merge two rings for different ranges
ring2 = New(start, middle, peer2name)
ring2 = NewRing(start, middle, peer2name)
ring2.Entries = []*entry{}
require.True(t, ring1.Merge(*ring2) == ErrDifferentRange, "Expected ErrDifferentRange")
require.True(t, merge(ring1, ring2) == ErrDifferentRange, "Expected ErrDifferentRange")
// Cannot Merge newer version of entry I own
ring2 = New(start, end, peer2name)
ring2 = NewRing(start, end, peer2name)
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
ring2.Entries = []*entry{{Token: start, Peer: peer1name, Version: 1}}
require.True(t, ring1.Merge(*ring2) == ErrNewerVersion, "Expected ErrNewerVersion")
fmt.Println(merge(ring1, ring2))
require.Error(t, merge(ring1, ring2), "Expected error")
// Cannot Merge two entries with same version but different hosts
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
ring2.Entries = []*entry{{Token: start, Peer: peer2name}}
require.True(t, ring1.Merge(*ring2) == ErrInvalidEntry, "Expected ErrInvalidEntry")
require.Error(t, merge(ring1, ring2), "Expected error")
// Cannot Merge an entry into a range I own
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
ring2.Entries = []*entry{{Token: middle, Peer: peer2name}}
require.True(t, ring1.Merge(*ring2) == ErrEntryInMyRange, "Expected ErrEntryInMyRange")
require.Error(t, merge(ring1, ring2), "Expected error")
}
func TestMergeMore(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
assertRing := func(ring *Ring, entries entries) {
require.Equal(t, entries, ring.Entries)
@@ -244,74 +262,74 @@ func TestMergeMore(t *testing.T) {
// Claim everything for peer1
ring1.ClaimItAll()
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 256}})
assertRing(ring2, []*entry{})
// Check the Merge sends it to the other ring
require.NoError(t, ring2.Merge(*ring1))
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 255}})
require.NoError(t, merge(ring2, ring1))
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 256}})
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 256}})
// Give everything to peer2
ring1.GrantRangeToHost(start, end, peer2name)
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 255}})
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 256, Version: 1}})
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 256}})
require.NoError(t, ring2.Merge(*ring1))
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
require.NoError(t, merge(ring2, ring1))
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 256, Version: 1}})
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 256, Version: 1}})
// And carve off some space
ring2.GrantRangeToHost(middle, end, peer1name)
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
{Token: middle, Peer: peer1name, Free: 127}})
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
{Token: middle, Peer: peer1name, Free: 128}})
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 256, Version: 1}})
// And Merge back
require.NoError(t, ring1.Merge(*ring2))
require.NoError(t, merge(ring1, ring2))
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
{Token: middle, Peer: peer1name, Free: 127}})
{Token: middle, Peer: peer1name, Free: 128}})
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
{Token: middle, Peer: peer1name, Free: 127}})
{Token: middle, Peer: peer1name, Free: 128}})
// This should be a no-op
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
{Token: middle, Peer: peer1name, Free: 127}})
{Token: middle, Peer: peer1name, Free: 128}})
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
{Token: middle, Peer: peer1name, Free: 127}})
{Token: middle, Peer: peer1name, Free: 128}})
}
func TestMergeSplit(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
// Claim everything for peer2
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 255}}
require.NoError(t, ring2.Merge(*ring1))
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 256}}
require.NoError(t, merge(ring2, ring1))
require.Equal(t, ring2.Entries, ring1.Entries)
// Now grant a split range to peer1
ring2.GrantRangeToHost(dot10, dot245, peer1name)
require.Equal(t, entries{{Token: start, Peer: peer2name, Free: 10, Version: 1},
{Token: dot10, Peer: peer1name, Free: 235},
{Token: dot245, Peer: peer2name, Free: 10}}, ring2.Entries)
{Token: dot245, Peer: peer2name, Free: 11}}, ring2.Entries)
require.NoError(t, ring1.Merge(*ring2))
require.NoError(t, merge(ring1, ring2))
require.Equal(t, entries{{Token: start, Peer: peer2name, Free: 10, Version: 1},
{Token: dot10, Peer: peer1name, Free: 235},
{Token: dot245, Peer: peer2name, Free: 10}}, ring1.Entries)
{Token: dot245, Peer: peer2name, Free: 11}}, ring1.Entries)
require.Equal(t, ring2.Entries, ring1.Entries)
}
func TestMergeSplit2(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
// Claim everything for peer2
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 250}, {Token: dot250, Peer: peer2name, Free: 5}}
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
require.Equal(t, ring2.Entries, ring1.Entries)
// Now grant a split range to peer1
@@ -320,7 +338,7 @@ func TestMergeSplit2(t *testing.T) {
{Token: dot10, Peer: peer1name, Free: 235},
{Token: dot245, Peer: peer2name, Free: 5}, {Token: dot250, Peer: peer2name, Free: 5}}, ring2.Entries)
require.NoError(t, ring1.Merge(*ring2))
require.NoError(t, merge(ring1, ring2))
require.Equal(t, entries{{Token: start, Peer: peer2name, Free: 10, Version: 1},
{Token: dot10, Peer: peer1name, Free: 235},
{Token: dot245, Peer: peer2name, Free: 5}, {Token: dot250, Peer: peer2name, Free: 5}}, ring1.Entries)
@@ -330,8 +348,8 @@ func TestMergeSplit2(t *testing.T) {
// A simple test, very similar to above, but using the marshalling to byte[]s
func TestGossip(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
assertRing := func(ring *Ring, entries entries) {
require.Equal(t, entries, ring.Entries)
@@ -342,13 +360,13 @@ func TestGossip(t *testing.T) {
// Claim everything for peer1
ring1.ClaimItAll()
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 256}})
assertRing(ring2, []*entry{})
// Check the Merge sends it to the other ring
require.NoError(t, ring2.Merge(*ring1))
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 255}})
require.NoError(t, merge(ring2, ring1))
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 256}})
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 256}})
}
func assertPeersWithSpace(t *testing.T, ring *Ring, start, end address.Address, expected int) []mesh.PeerName {
@@ -358,7 +376,7 @@ func assertPeersWithSpace(t *testing.T, ring *Ring, start, end address.Address,
}
func TestFindFree(t *testing.T) {
ring1 := New(start, end, peer1name)
ring1 := NewRing(start, end, peer1name)
assertPeersWithSpace(t, ring1, start, end, 0)
@@ -366,7 +384,7 @@ func TestFindFree(t *testing.T) {
assertPeersWithSpace(t, ring1, start, end, 0)
// We shouldn't return outselves
ring1.ReportFree(map[address.Address]address.Offset{start: 10})
ring1.ReportFree(map[address.Address]address.Count{start: 10})
assertPeersWithSpace(t, ring1, start, end, 0)
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 1},
@@ -394,14 +412,14 @@ func TestFindFree(t *testing.T) {
}
func TestReportFree(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
ring1.ClaimItAll()
ring1.GrantRangeToHost(middle, end, peer2name)
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
freespace := make(map[address.Address]address.Offset)
freespace := make(map[address.Address]address.Count)
for _, r := range ring2.OwnedRanges() {
freespace[r.Start] = 0
}
@@ -409,7 +427,7 @@ func TestReportFree(t *testing.T) {
}
func TestMisc(t *testing.T) {
ring := New(start, end, peer1name)
ring := NewRing(start, end, peer1name)
require.True(t, ring.Empty(), "empty")
@@ -418,38 +436,38 @@ func TestMisc(t *testing.T) {
}
func TestEmptyGossip(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
ring1.ClaimItAll()
// This used to panic, and it shouldn't
require.NoError(t, ring1.Merge(*ring2))
require.NoError(t, merge(ring1, ring2))
}
func TestMergeOldMessage(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
ring1.ClaimItAll()
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
ring1.GrantRangeToHost(middle, end, peer1name)
require.NoError(t, ring1.Merge(*ring2))
require.NoError(t, merge(ring1, ring2))
}
func TestSplitRangeAtBeginning(t *testing.T) {
ring1 := New(start, end, peer1name)
ring2 := New(start, end, peer2name)
ring1 := NewRing(start, end, peer1name)
ring2 := NewRing(start, end, peer2name)
ring1.ClaimItAll()
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
ring1.GrantRangeToHost(start, middle, peer2name)
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
}
func TestOwnedRange(t *testing.T) {
ring1 := New(start, end, peer1name)
ring1 := NewRing(start, end, peer1name)
ring1.ClaimItAll()
require.Equal(t, []address.Range{{Start: start, End: end}}, ring1.OwnedRanges())
@@ -457,8 +475,8 @@ func TestOwnedRange(t *testing.T) {
ring1.GrantRangeToHost(middle, end, peer2name)
require.Equal(t, []address.Range{{Start: start, End: middle}}, ring1.OwnedRanges())
ring2 := New(start, end, peer2name)
ring2.Merge(*ring1)
ring2 := NewRing(start, end, peer2name)
merge(ring2, ring1)
require.Equal(t, []address.Range{{Start: middle, End: end}}, ring2.OwnedRanges())
ring2.Entries = []*entry{{Token: middle, Peer: peer2name}}
@@ -472,24 +490,24 @@ func TestOwnedRange(t *testing.T) {
func TestTransfer(t *testing.T) {
// First test just checks if we can grant some range to a host, when we transfer it, we get it back
ring1 := New(start, end, peer1name)
ring1 := NewRing(start, end, peer1name)
ring1.ClaimItAll()
ring1.GrantRangeToHost(middle, end, peer2name)
ring1.Transfer(peer2name, peer1name)
require.Equal(t, []address.Range{{start, middle}, {middle, end}}, ring1.OwnedRanges())
require.Equal(t, []address.Range{{Start: start, End: middle}, {Start: middle, End: end}}, ring1.OwnedRanges())
// Second test is what happens when a token exists at the end of a range but is transferred
// - does it get resurrected correctly?
ring1 = New(start, end, peer1name)
ring1 = NewRing(start, end, peer1name)
ring1.ClaimItAll()
ring1.GrantRangeToHost(middle, end, peer2name)
ring1.Transfer(peer2name, peer1name)
ring1.GrantRangeToHost(dot10, middle, peer2name)
require.Equal(t, []address.Range{{start, dot10}, {middle, end}}, ring1.OwnedRanges())
require.Equal(t, []address.Range{{Start: start, End: dot10}, {Start: middle, End: end}}, ring1.OwnedRanges())
}
func TestOwner(t *testing.T) {
ring1 := New(start, end, peer1name)
ring1 := NewRing(start, end, peer1name)
require.True(t, ring1.Contains(start), "start should be in ring")
require.False(t, ring1.Contains(end), "end should not be in ring")
@@ -505,6 +523,36 @@ func TestOwner(t *testing.T) {
}
func makePeerName(i int) mesh.PeerName {
if i >= 10000 {
panic("makePeerName: invalid value")
}
peer, _ := mesh.PeerNameFromString(fmt.Sprintf("%02d:%02d:00:00:00:ff", i/100, i%100))
return peer
}
func makePeers(numPeers int) []mesh.PeerName {
peers := make([]mesh.PeerName, numPeers)
for i := 0; i < numPeers; i++ {
peers[i] = makePeerName(i)
}
return peers
}
func TestClaimForPeers(t *testing.T) {
const numPeers = 12
// Different end to usual so we get a number of addresses that a)
// is smaller than the max number of peers, and b) is divisible by
// some number of peers. This maximises coverage of edge cases.
end := dot8
peers := makePeers(numPeers)
// Test for a range of peer counts
for i := 0; i < numPeers; i++ {
ring := NewRing(start, end, peers[0])
ring.ClaimForPeers(peers[:i+1])
}
}
type addressSlice []address.Address
func (s addressSlice) Len() int { return len(s) }
@@ -519,8 +567,7 @@ func TestFuzzRing(t *testing.T) {
peers := make([]mesh.PeerName, numPeers)
for i := 0; i < numPeers; i++ {
peer, _ := mesh.PeerNameFromString(fmt.Sprintf("%02d:00:00:00:02:00", i))
peers[i] = peer
peers[i] = makePeerName(i)
}
// Make a valid, random ring
@@ -539,7 +586,7 @@ func TestFuzzRing(t *testing.T) {
sort.Sort(addressSlice(tokens))
peer := peers[rand.Intn(len(peers))]
ring := New(start, end, peer)
ring := NewRing(start, end, peer)
for _, token := range tokens {
peer = peers[rand.Intn(len(peers))]
ring.Entries = append(ring.Entries, &entry{Token: start + token, Peer: peer})
@@ -556,7 +603,7 @@ func TestFuzzRing(t *testing.T) {
// Merge them - this might fail, we don't care
// We just want to make sure it doesn't panic
ring1.Merge(*ring2)
merge(ring1, ring2)
// Check whats left still passes assertions
ring1.assertInvariants()
@@ -573,7 +620,7 @@ func TestFuzzRing(t *testing.T) {
}
peer := peers[rand.Intn(len(peers))]
ring := New(start, end, peer)
ring := NewRing(start, end, peer)
for _, token := range tokens {
peer = peers[rand.Intn(len(peers))]
ring.Entries = append(ring.Entries, &entry{Token: start + token, Peer: peer})
@@ -589,7 +636,7 @@ func TestFuzzRing(t *testing.T) {
// Merge them - this might fail, we don't care
// We just want to make sure it doesn't panic
ring1.Merge(*ring2)
merge(ring1, ring2)
// Check whats left still passes assertions
ring1.assertInvariants()
@@ -607,11 +654,11 @@ func TestFuzzRingHard(t *testing.T) {
)
addPeer := func() {
peer, _ := mesh.PeerNameFromString(fmt.Sprintf("%02d:%02d:00:00:00:00", nextPeerID/10, nextPeerID%10))
peer := makePeerName(nextPeerID)
common.Log.Debugf("%s: Adding peer", peer)
nextPeerID++
peers = append(peers, peer)
rings = append(rings, New(start, end, peer))
rings = append(rings, NewRing(start, end, peer))
}
for i := 0; i < numPeers; i++ {
@@ -650,7 +697,7 @@ func TestFuzzRingHard(t *testing.T) {
// We need to be in a ~converged ring to rmpeer
for _, ring := range rings {
require.NoError(t, otherRing.Merge(*ring))
require.NoError(t, merge(otherRing, ring))
}
common.Log.Debugf("%s: transferring from peer %s", otherPeername, peername)
@@ -664,7 +711,7 @@ func TestFuzzRingHard(t *testing.T) {
// And now tell everyone about the transfer - rmpeer is
// not partition safe
for i, ring := range rings {
require.NoError(t, ring.Merge(*otherRing))
require.NoError(t, merge(ring, otherRing))
theRanges[i] = ring.OwnedRanges()
}
}
@@ -693,7 +740,7 @@ func TestFuzzRingHard(t *testing.T) {
// Now 'gossip' this to a random host (note, note could be same host as above)
otherIndex, _, otherRing := randomPeer(-1)
common.Log.Debugf("%s: 'Gossiping' to %s", ring.Peer, otherRing.Peer)
require.NoError(t, otherRing.Merge(*ring))
require.NoError(t, merge(otherRing, ring))
theRanges[indexWithRanges] = ring.OwnedRanges()
theRanges[otherIndex] = otherRing.OwnedRanges()
@@ -712,7 +759,7 @@ func TestFuzzRingHard(t *testing.T) {
ring1 := ringsWithEntries[rand.Intn(len(ringsWithEntries))]
ring2index, _, ring2 := randomPeer(-1)
common.Log.Debugf("%s: 'Gossiping' to %s", ring1.Peer, ring2.Peer)
require.NoError(t, ring2.Merge(*ring1))
require.NoError(t, merge(ring2, ring1))
theRanges[ring2index] = ring2.OwnedRanges()
}
+31 -9
View File
@@ -31,8 +31,8 @@ func (s *Space) Add(start address.Address, size address.Offset) {
// Clear removes all spaces from this space set. Used during node shutdown.
func (s *Space) Clear() {
s.free = s.free[:0]
s.ours = s.ours[:0]
s.free = s.free[:0]
}
// Walk down the free list calling f() on the in-range portions, until
@@ -88,8 +88,24 @@ func (s *Space) Claim(addr address.Address) error {
return nil
}
func (s *Space) NumFreeAddressesInRange(r address.Range) address.Offset {
res := address.Offset(0)
func (s *Space) NumOwnedAddresses() address.Count {
res := address.Count(0)
for i := 0; i < len(s.ours); i += 2 {
res += address.Length(s.ours[i+1], s.ours[i])
}
return res
}
func (s *Space) NumFreeAddresses() address.Count {
res := address.Count(0)
for i := 0; i < len(s.free); i += 2 {
res += address.Length(s.free[i+1], s.free[i])
}
return res
}
func (s *Space) NumFreeAddressesInRange(r address.Range) address.Count {
res := address.Count(0)
s.walkFree(r, func(chunk address.Range) bool {
res += chunk.Size()
return false
@@ -111,11 +127,14 @@ func (s *Space) Free(addr address.Address) error {
}
func (s *Space) biggestFreeRange(r address.Range) (biggest address.Range) {
biggestSize := address.Offset(0)
biggestSize := address.Count(0)
s.walkFree(r, func(chunk address.Range) bool {
if size := chunk.Size(); size >= biggestSize {
biggest = chunk
biggestSize = size
chunk = chunk.BiggestCIDRRange()
if size = chunk.Size(); size >= biggestSize {
biggest = chunk
biggestSize = size
}
}
return false
})
@@ -129,9 +148,12 @@ func (s *Space) Donate(r address.Range) (address.Range, bool) {
return address.Range{}, false
}
// Donate half of that biggest free range. Note size/2 rounds down, so
// the resulting donation size rounds up, and in particular can't be empty.
biggest.Start = address.Add(biggest.Start, biggest.Size()/2)
// Donate no more than half what we have available
if biggest.Size() > s.NumFreeAddressesInRange(r)/2 {
// Note size/2 rounds down, so the resulting donation size
// rounds up, and in particular can't be empty.
biggest.Start = address.Add(biggest.Start, address.Offset(biggest.Size()/2))
}
s.ours = subtract(s.ours, biggest.Start, biggest.End)
s.free = subtract(s.free, biggest.Start, biggest.End)
+56 -62
View File
@@ -19,16 +19,6 @@ func ip(s string) address.Address {
return addr
}
// Helper function to avoid 'NumFreeAddressesInRange(start, end)'
// dozens of times in tests
func (s *Space) NumFreeAddresses() address.Offset {
res := address.Offset(0)
for i := 0; i < len(s.free); i += 2 {
res += address.Subtract(s.free[i+1], s.free[i])
}
return res
}
func TestLowlevel(t *testing.T) {
a := []address.Address{}
a = add(a, 100, 200)
@@ -61,24 +51,24 @@ func TestLowlevel(t *testing.T) {
require.Equal(t, []address.Address{}, a)
s := New()
require.Equal(t, address.Offset(0), s.NumFreeAddresses())
require.Equal(t, address.Count(0), s.NumFreeAddresses())
ok, got := s.Allocate(address.NewRange(0, 1000))
require.False(t, ok, "allocate in empty space should fail")
s.Add(100, 100)
require.Equal(t, address.Offset(100), s.NumFreeAddresses())
require.Equal(t, address.Count(100), s.NumFreeAddresses())
ok, got = s.Allocate(address.NewRange(0, 1000))
require.True(t, ok && got == 100, "allocate")
require.Equal(t, address.Offset(99), s.NumFreeAddresses())
require.Equal(t, address.Count(99), s.NumFreeAddresses())
require.NoError(t, s.Claim(150))
require.Equal(t, address.Offset(98), s.NumFreeAddresses())
require.Equal(t, address.Count(98), s.NumFreeAddresses())
require.NoError(t, s.Free(100))
require.Equal(t, address.Offset(99), s.NumFreeAddresses())
require.Equal(t, address.Count(99), s.NumFreeAddresses())
wt.AssertErrorInterface(t, (*error)(nil), s.Free(0), "free not allocated")
wt.AssertErrorInterface(t, (*error)(nil), s.Free(100), "double free")
r, ok := s.Donate(address.NewRange(0, 1000))
require.True(t, ok && r.Start == 125 && r.Size() == 25, "donate")
require.Equal(t, address.NewRange(0xa0, 0x20), r, "donate")
// test Donate when addresses are scarce
s = New()
@@ -88,7 +78,7 @@ func TestLowlevel(t *testing.T) {
require.NoError(t, s.Claim(0))
require.NoError(t, s.Claim(2))
r, ok = s.Donate(address.NewRange(0, 1000))
require.True(t, ok && r.Start == 1 && r.End == 2, "donate")
require.Equal(t, address.NewRange(1, 1), r, "donate")
r, ok = s.Donate(address.NewRange(0, 1000))
require.True(t, !ok, "donate should fail")
}
@@ -107,19 +97,22 @@ func TestSpaceAllocate(t *testing.T) {
)
space1 := makeSpace(start, size)
require.Equal(t, address.Offset(20), space1.NumFreeAddresses())
require.Equal(t, address.Count(20), space1.NumFreeAddresses())
require.Equal(t, address.Count(0), space1.NumOwnedAddresses())
space1.assertInvariants()
_, addr1 := space1.Allocate(address.NewRange(start, size))
require.Equal(t, testAddr1, addr1.String(), "address")
require.Equal(t, address.Offset(19), space1.NumFreeAddresses())
require.Equal(t, address.Count(19), space1.NumFreeAddresses())
require.Equal(t, address.Count(1), space1.NumOwnedAddresses())
space1.assertInvariants()
_, addr2 := space1.Allocate(address.NewRange(start, size))
require.False(t, addr2.String() == testAddr1, "address")
require.Equal(t, address.Offset(18), space1.NumFreeAddresses())
require.Equal(t, address.Offset(13), space1.NumFreeAddressesInRange(address.Range{Start: ip(testAddr1), End: ip(testAddrx)}))
require.Equal(t, address.Offset(18), space1.NumFreeAddressesInRange(address.Range{Start: ip(testAddr1), End: ip(testAddry)}))
require.Equal(t, address.Count(18), space1.NumFreeAddresses())
require.Equal(t, address.Count(2), space1.NumOwnedAddresses())
require.Equal(t, address.Count(13), space1.NumFreeAddressesInRange(address.Range{Start: ip(testAddr1), End: ip(testAddrx)}))
require.Equal(t, address.Count(18), space1.NumFreeAddressesInRange(address.Range{Start: ip(testAddr1), End: ip(testAddry)}))
space1.assertInvariants()
space1.Free(addr2)
@@ -134,20 +127,21 @@ func TestSpaceAllocate(t *testing.T) {
func TestSpaceFree(t *testing.T) {
const (
testAddr1 = "10.0.3.4"
testAddr1 = "10.0.3.16"
testAddrx = "10.0.3.19"
testAddry = "10.0.9.19"
containerID = "deadbeef"
size = 16
)
entireRange := address.NewRange(ip(testAddr1), 20)
space := makeSpace(ip(testAddr1), 20)
entireRange := address.NewRange(ip(testAddr1), size)
space := makeSpace(ip(testAddr1), size)
// Check we are prepared to give up the entire space
r := space.biggestFreeRange(entireRange)
require.True(t, r.Start == ip(testAddr1) && r.Size() == 20, "Wrong space")
require.Equal(t, address.NewRange(ip(testAddr1), size), r, "Wrong space")
for i := 0; i < 20; i++ {
for i := 0; i < size; i++ {
ok, _ := space.Allocate(entireRange)
require.True(t, ok, "Failed to get address")
}
@@ -155,48 +149,48 @@ func TestSpaceFree(t *testing.T) {
// Check we are full
ok, _ := space.Allocate(entireRange)
require.True(t, !ok, "Should have failed to get address")
r, ok = space.Donate(entireRange)
r, _ = space.Donate(entireRange)
require.True(t, r.Size() == 0, "Wrong space")
// Free in the middle
require.NoError(t, space.Free(ip("10.0.3.13")))
r = space.biggestFreeRange(entireRange)
require.True(t, r.Start == ip("10.0.3.13") && r.Size() == 1, "Wrong space")
// Free one at the end
require.NoError(t, space.Free(ip("10.0.3.23")))
r = space.biggestFreeRange(entireRange)
require.True(t, r.Start == ip("10.0.3.23") && r.Size() == 1, "Wrong space")
// Free one at the end
require.NoError(t, space.Free(ip("10.0.3.31")))
r = space.biggestFreeRange(entireRange)
require.True(t, r.Start == ip("10.0.3.31") && r.Size() == 1, "Wrong space")
// Now free a few at the end
require.NoError(t, space.Free(ip("10.0.3.30")))
require.NoError(t, space.Free(ip("10.0.3.29")))
require.Equal(t, address.Count(4), space.NumFreeAddresses())
// Now get the biggest free space; should be 3.30
r = space.biggestFreeRange(entireRange)
require.Equal(t, address.NewRange(ip("10.0.3.30"), 2), r, "Wrong space")
// Now free a few in the middle
require.NoError(t, space.Free(ip("10.0.3.24")))
require.NoError(t, space.Free(ip("10.0.3.22")))
require.NoError(t, space.Free(ip("10.0.3.21")))
require.Equal(t, address.Offset(4), space.NumFreeAddresses())
require.Equal(t, address.Count(7), space.NumFreeAddresses())
// Now get the biggest free space; should be 3.21
// Now get the biggest free space; should be 3.30
r = space.biggestFreeRange(entireRange)
require.True(t, r.Start == ip("10.0.3.21") && r.Size() == 3, "Wrong space")
require.Equal(t, address.NewRange(ip("10.0.3.30"), 2), r, "Wrong space")
// Now free a few in the middle
require.NoError(t, space.Free(ip("10.0.3.12")))
require.NoError(t, space.Free(ip("10.0.3.11")))
require.NoError(t, space.Free(ip("10.0.3.10")))
require.Equal(t, address.Offset(7), space.NumFreeAddresses())
// Now get the biggest free space; should be 3.21
r = space.biggestFreeRange(entireRange)
require.True(t, r.Start == ip("10.0.3.10") && r.Size() == 4, "Wrong space")
require.Equal(t, []address.Range{{Start: ip("10.0.3.4"), End: ip("10.0.3.24")}}, space.OwnedRanges())
require.Equal(t, []address.Range{{Start: ip("10.0.3.16"), End: ip("10.0.3.32")}}, space.OwnedRanges())
}
func TestDonateSimple(t *testing.T) {
const (
testAddr1 = "10.0.1.0"
testAddr2 = "10.0.1.32"
size = 48
size = 64
)
var (
@@ -209,9 +203,9 @@ func TestDonateSimple(t *testing.T) {
r, ok := ps1.Donate(address.NewRange(ip(testAddr1), size))
numGivenUp := r.Size()
require.True(t, ok, "Donate result")
require.Equal(t, "10.0.1.24", r.Start.String(), "Invalid start")
require.Equal(t, address.Offset(size/2), numGivenUp)
require.Equal(t, address.Offset(size/2), ps1.NumFreeAddresses())
require.Equal(t, "10.0.1.32", r.Start.String(), "Invalid start")
require.Equal(t, address.Count(size/2), numGivenUp)
require.Equal(t, address.Count(size/2), ps1.NumFreeAddresses())
// Now check we can give the rest up.
count := 0 // count to avoid infinite loop
@@ -222,8 +216,8 @@ func TestDonateSimple(t *testing.T) {
}
numGivenUp += r.Size()
}
require.Equal(t, address.Offset(0), ps1.NumFreeAddresses())
require.Equal(t, address.Offset(size), numGivenUp)
require.Equal(t, address.Count(0), ps1.NumFreeAddresses())
require.Equal(t, address.Count(size), numGivenUp)
}
func TestDonateHard(t *testing.T) {
@@ -240,7 +234,7 @@ func TestDonateHard(t *testing.T) {
require.True(t, ok, "Failed to get IP!")
}
require.Equal(t, address.Offset(0), spaceset.NumFreeAddresses())
require.Equal(t, address.Count(0), spaceset.NumFreeAddresses())
// Now free all but the last address
// this will force us to split the free list
@@ -251,13 +245,13 @@ func TestDonateHard(t *testing.T) {
// Now split
newRange, ok := spaceset.Donate(address.NewRange(start, size))
require.True(t, ok, "GiveUpSpace result")
require.Equal(t, ip("10.0.1.23"), newRange.Start)
require.Equal(t, address.Offset(24), newRange.Size())
require.Equal(t, address.Offset(23), spaceset.NumFreeAddresses())
require.Equal(t, address.NewRange(ip("10.0.1.16"), 16), newRange, "Wrong space")
require.Equal(t, address.Count(31), spaceset.NumFreeAddresses())
//Space set should now have 2 spaces
expected := New()
expected.Add(start, 23)
expected.ours = add(nil, ip("10.0.1.47"), ip("10.0.1.48"))
//Space set should now have 3 spaces
expected := &Space{
ours: add(nil, ip("10.0.1.47"), ip("10.0.1.48")),
free: add(add(nil, ip("10.0.1.0"), ip("10.0.1.16")), ip("10.0.1.32"), ip("10.0.1.47")),
}
require.Equal(t, expected, spaceset)
}
+32 -11
View File
@@ -1,6 +1,7 @@
package ipam
import (
"fmt"
"github.com/weaveworks/weave/ipam/paxos"
"github.com/weaveworks/weave/net/address"
)
@@ -8,6 +9,8 @@ import (
type Status struct {
Paxos *paxos.Status
Range string
RangeNumIPs int
ActiveIPs int
DefaultSubnet string
Entries []EntryStatus
PendingClaims []ClaimStatus
@@ -15,14 +18,17 @@ type Status struct {
}
type EntryStatus struct {
Token string
Peer string
Version uint32
Token string
Size uint32
Peer string
Nickname string
IsKnownPeer bool
Version uint32
}
type ClaimStatus struct {
Ident string
Address address.Address
Ident string
CIDR address.CIDR
}
func NewStatus(allocator *Allocator, defaultSubnet address.CIDR) *Status {
@@ -31,8 +37,14 @@ func NewStatus(allocator *Allocator, defaultSubnet address.CIDR) *Status {
}
var paxosStatus *paxos.Status
if allocator.paxosTicker != nil {
paxosStatus = paxos.NewStatus(allocator.paxos)
if allocator.awaitingConsensus && allocator.paxos != nil {
if allocator.paxos.IsElector() {
if node, ok := allocator.paxos.(*paxos.Node); ok {
paxosStatus = paxos.NewStatus(node)
}
} else {
paxosStatus = &paxos.Status{Elector: false}
}
}
resultChan := make(chan *Status)
@@ -40,6 +52,8 @@ func NewStatus(allocator *Allocator, defaultSubnet address.CIDR) *Status {
resultChan <- &Status{
paxosStatus,
allocator.universe.String(),
int(allocator.universe.Size()),
int(allocator.space.NumOwnedAddresses()),
defaultSubnet.String(),
newEntryStatusSlice(allocator),
newClaimStatusSlice(allocator),
@@ -56,8 +70,15 @@ func newEntryStatusSlice(allocator *Allocator) []EntryStatus {
return slice
}
for _, entry := range allocator.ring.Entries {
slice = append(slice, EntryStatus{entry.Token.String(), entry.Peer.String(), entry.Version})
for _, r := range allocator.ring.AllRangeInfo() {
slice = append(slice, EntryStatus{
Token: r.Start.String(),
Size: uint32(r.Size()),
Peer: r.Peer.String(),
Nickname: allocator.nicknames[r.Peer],
IsKnownPeer: allocator.isKnownPeer(r.Peer),
Version: r.Version,
})
}
return slice
@@ -67,7 +88,7 @@ func newClaimStatusSlice(allocator *Allocator) []ClaimStatus {
var slice []ClaimStatus
for _, op := range allocator.pendingClaims {
claim := op.(*claim)
slice = append(slice, ClaimStatus{claim.ident, claim.addr})
slice = append(slice, ClaimStatus{claim.ident, claim.cidr})
}
return slice
}
@@ -76,7 +97,7 @@ func newAllocateIdentSlice(allocator *Allocator) []string {
var slice []string
for _, op := range allocator.pendingAllocates {
allocate := op.(*allocate)
slice = append(slice, allocate.ident)
slice = append(slice, fmt.Sprintf("%s %s", allocate.ident, allocate.r.String()))
}
return slice
}
+37 -15
View File
@@ -7,8 +7,9 @@ import (
"testing"
"time"
"github.com/weaveworks/mesh"
"github.com/stretchr/testify/require"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/net/address"
"github.com/weaveworks/weave/testing/gossip"
)
@@ -48,7 +49,7 @@ func (m *mockGossipComms) String() string {
// that the contents of messages are never re-ordered. Which, for instance,
// requires they are not based off iterating through a map.
func (m *mockGossipComms) GossipBroadcast(update mesh.GossipData) error {
func (m *mockGossipComms) GossipBroadcast(update mesh.GossipData) {
m.Lock()
defer m.Unlock()
buf := []byte{}
@@ -62,7 +63,6 @@ func (m *mockGossipComms) GossipBroadcast(update mesh.GossipData) error {
// Swallow this message
m.messages = m.messages[1:]
}
return nil
}
func equalByteBuffer(a, b []byte) bool {
@@ -123,24 +123,35 @@ func CheckAllExpectedMessagesSent(allocs ...*Allocator) {
}
}
func makeAllocator(name string, cidrStr string, quorum uint) (*Allocator, address.Range) {
type mockDB struct{}
func (d *mockDB) Load(_ string, _ interface{}) (bool, error) { return false, nil }
func (d *mockDB) Save(_ string, _ interface{}) error { return nil }
func makeAllocator(name string, cidrStr string, quorum uint) (*Allocator, address.CIDR) {
peername, err := mesh.PeerNameFromString(name)
if err != nil {
panic(err)
}
_, cidr, err := address.ParseCIDR(cidrStr)
cidr, err := address.ParseCIDR(cidrStr)
if err != nil {
panic(err)
}
alloc := NewAllocator(peername, mesh.PeerUID(rand.Int63()),
"nick-"+name, cidr.Range(), quorum, func(mesh.PeerName) bool { return true })
return alloc, cidr.HostRange()
return NewAllocator(Config{
OurName: peername,
OurUID: mesh.PeerUID(rand.Int63()),
OurNickname: "nick-" + name,
Universe: cidr,
IsObserver: quorum == 0,
Quorum: func() uint { return quorum },
Db: new(mockDB),
IsKnownPeer: func(mesh.PeerName) bool { return true },
}), cidr
}
func makeAllocatorWithMockGossip(t *testing.T, name string, universeCIDR string, quorum uint) (*Allocator, address.Range) {
func makeAllocatorWithMockGossip(t *testing.T, name string, universeCIDR string, quorum uint) (*Allocator, address.CIDR) {
alloc, subnet := makeAllocator(name, universeCIDR, quorum)
gossip := &mockGossipComms{T: t, name: name}
alloc.SetInterfaces(gossip)
@@ -157,14 +168,22 @@ func (alloc *Allocator) claimRingForTesting(allocs ...*Allocator) {
alloc.space.AddRanges(alloc.ring.OwnedRanges())
}
func (alloc *Allocator) NumFreeAddresses(r address.Range) address.Offset {
resultChan := make(chan address.Offset)
func (alloc *Allocator) NumFreeAddresses(r address.Range) address.Count {
resultChan := make(chan address.Count)
alloc.actionChan <- func() {
resultChan <- alloc.space.NumFreeAddressesInRange(r)
}
return <-resultChan
}
func (alloc *Allocator) OwnedRanges() (result []address.Range) {
resultChan := make(chan []address.Range)
alloc.actionChan <- func() {
resultChan <- alloc.ring.OwnedRanges()
}
return <-resultChan
}
// Check whether or not something was sent on a channel
func AssertSent(t *testing.T, ch <-chan bool) {
timeout := time.After(10 * time.Second)
@@ -194,10 +213,10 @@ func AssertNothingSentErr(t *testing.T, ch <-chan error) {
}
}
func makeNetworkOfAllocators(size int, cidr string) ([]*Allocator, *gossip.TestRouter, address.Range) {
func makeNetworkOfAllocators(size int, cidr string) ([]*Allocator, *gossip.TestRouter, address.CIDR) {
gossipRouter := gossip.NewTestRouter(0.0)
allocs := make([]*Allocator, size)
var subnet address.Range
var subnet address.CIDR
for i := 0; i < size; i++ {
var alloc *Allocator
@@ -213,7 +232,10 @@ func makeNetworkOfAllocators(size int, cidr string) ([]*Allocator, *gossip.TestR
return allocs, gossipRouter, subnet
}
func stopNetworkOfAllocators(allocs []*Allocator) {
func stopNetworkOfAllocators(allocs []*Allocator, gossipRouter *gossip.TestRouter) {
// NB: We must stop the router first since ipam gossip makes
// synchronous calls into the allocator.
gossipRouter.Stop()
for _, alloc := range allocs {
alloc.Stop()
}
+285
View File
@@ -0,0 +1,285 @@
package tracker
// The AWSVPC tracker tracks the IPAM ring changes and accordingly updates
// the AWS VPC route table and, if the announced change is local
// (denoted by local=true) to the host, the host route table.
//
// During the initialization, the tracker detects AWS VPC route table id which
// is associated with the host's subnet on the AWS network. If such a table does
// not exist, the default VPC route table is used.
//
// When a host A donates a range to a host B, the necessary route table
// updates (removal) happen on the host A first, and afterwards on
// the host B (installation).
//
// NB: there is a hard limit for 50 routes within any VPC route table
// (practically, it is 48, because one route is used by the AWS Internet GW and
// one by the AWS host subnet), therefore it is suggested to avoid
// an excessive fragmentation within the IPAM ring which might happen due to
// the claim operations or uneven distribution of containers across the hosts.
import (
"fmt"
"net"
"syscall"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/vishvananda/netlink"
"github.com/weaveworks/weave/common"
wnet "github.com/weaveworks/weave/net"
"github.com/weaveworks/weave/net/address"
)
type AWSVPCTracker struct {
ec2 *ec2.EC2
instanceID string // EC2 Instance ID
routeTableID string // VPC Route Table ID
linkIndex int // The weave bridge link index
}
// NewAWSVPCTracker creates and initialises AWS VPC based tracker.
func NewAWSVPCTracker() (*AWSVPCTracker, error) {
var (
err error
session = session.New()
t = &AWSVPCTracker{}
)
// Detect region and instance id
meta := ec2metadata.New(session)
t.instanceID, err = meta.GetMetadata("instance-id")
if err != nil {
return nil, fmt.Errorf("cannot detect instance-id: %s", err)
}
region, err := meta.Region()
if err != nil {
return nil, fmt.Errorf("cannot detect region: %s", err)
}
t.ec2 = ec2.New(session, aws.NewConfig().WithRegion(region))
routeTableID, err := t.detectRouteTableID()
if err != nil {
return nil, err
}
t.routeTableID = *routeTableID
// Detect Weave bridge link index
link, err := netlink.LinkByName(wnet.WeaveBridgeName)
if err != nil {
return nil, fmt.Errorf("cannot find \"%s\" interface: %s", wnet.WeaveBridgeName, err)
}
t.linkIndex = link.Attrs().Index
t.infof("AWSVPC has been initialized on %s instance for %s route table at %s region",
t.instanceID, t.routeTableID, region)
return t, nil
}
// HandleUpdate method updates the AWS VPC and the host route tables.
func (t *AWSVPCTracker) HandleUpdate(prevRanges, currRanges []address.Range, local bool) error {
t.debugf("replacing %q by %q; local(%t)", prevRanges, currRanges, local)
prev, curr := removeCommon(address.NewCIDRs(merge(prevRanges)), address.NewCIDRs(merge(currRanges)))
// It might make sense to do the removal first and then add entries
// because of the 50 routes limit. However, in such case a container might
// not be reachable for a short period of time which is not a desired behavior.
// Add new entries
for _, cidr := range curr {
cidrStr := cidr.String()
t.debugf("adding route %s to %s", cidrStr, t.instanceID)
if _, err := t.createVPCRoute(cidrStr); err != nil {
return fmt.Errorf("createVPCRoutes failed: %s", err)
}
if local {
if err := t.createHostRoute(cidrStr); err != nil {
if errno, ok := err.(syscall.Errno); !(ok && errno == syscall.EEXIST) {
return fmt.Errorf("createHostRoute failed: %s", err)
}
}
}
}
// Remove obsolete entries
for _, cidr := range prev {
cidrStr := cidr.String()
t.debugf("removing %s route", cidrStr)
if _, err := t.deleteVPCRoute(cidrStr); err != nil {
return fmt.Errorf("deleteVPCRoute failed: %s", err)
}
if local {
if err := t.deleteHostRoute(cidrStr); err != nil {
return fmt.Errorf("deleteHostRoute failed: %s", err)
}
}
}
return nil
}
func (t *AWSVPCTracker) createVPCRoute(cidr string) (*ec2.CreateRouteOutput, error) {
route := &ec2.CreateRouteInput{
RouteTableId: &t.routeTableID,
InstanceId: &t.instanceID,
DestinationCidrBlock: &cidr,
}
return t.ec2.CreateRoute(route)
}
func (t *AWSVPCTracker) createHostRoute(cidr string) error {
dst, err := parseCIDR(cidr)
if err != nil {
return err
}
route := &netlink.Route{
LinkIndex: t.linkIndex,
Dst: dst,
Scope: netlink.SCOPE_LINK,
}
return netlink.RouteAdd(route)
}
func (t *AWSVPCTracker) deleteVPCRoute(cidr string) (*ec2.DeleteRouteOutput, error) {
route := &ec2.DeleteRouteInput{
RouteTableId: &t.routeTableID,
DestinationCidrBlock: &cidr,
}
return t.ec2.DeleteRoute(route)
}
func (t *AWSVPCTracker) deleteHostRoute(cidr string) error {
dst, err := parseCIDR(cidr)
if err != nil {
return err
}
route := &netlink.Route{
LinkIndex: t.linkIndex,
Dst: dst,
Scope: netlink.SCOPE_LINK,
}
return netlink.RouteDel(route)
}
// detectRouteTableID detects AWS VPC Route Table ID of the given tracker instance.
func (t *AWSVPCTracker) detectRouteTableID() (*string, error) {
instancesParams := &ec2.DescribeInstancesInput{
InstanceIds: []*string{aws.String(t.instanceID)},
}
instancesResp, err := t.ec2.DescribeInstances(instancesParams)
if err != nil {
return nil, fmt.Errorf("DescribeInstances failed: %s", err)
}
if len(instancesResp.Reservations) == 0 ||
len(instancesResp.Reservations[0].Instances) == 0 {
return nil, fmt.Errorf("cannot find %s instance within reservations", t.instanceID)
}
vpcID := instancesResp.Reservations[0].Instances[0].VpcId
subnetID := instancesResp.Reservations[0].Instances[0].SubnetId
// First try to find a routing table associated with the subnet of the instance
tablesParams := &ec2.DescribeRouteTablesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("association.subnet-id"),
Values: []*string{subnetID},
},
},
}
tablesResp, err := t.ec2.DescribeRouteTables(tablesParams)
if err != nil {
return nil, fmt.Errorf("DescribeRouteTables failed: %s", err)
}
if len(tablesResp.RouteTables) != 0 {
return tablesResp.RouteTables[0].RouteTableId, nil
}
// Fallback to the default routing table
tablesParams = &ec2.DescribeRouteTablesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("association.main"),
Values: []*string{aws.String("true")},
},
{
Name: aws.String("vpc-id"),
Values: []*string{vpcID},
},
},
}
tablesResp, err = t.ec2.DescribeRouteTables(tablesParams)
if err != nil {
return nil, fmt.Errorf("DescribeRouteTables failed: %s", err)
}
if len(tablesResp.RouteTables) != 0 {
return tablesResp.RouteTables[0].RouteTableId, nil
}
return nil, fmt.Errorf("cannot find routetable for %s instance", t.instanceID)
}
func (t *AWSVPCTracker) debugf(fmt string, args ...interface{}) {
common.Log.Debugf("[tracker] "+fmt, args...)
}
func (t *AWSVPCTracker) infof(fmt string, args ...interface{}) {
common.Log.Infof("[tracker] "+fmt, args...)
}
// Helpers
// merge merges adjacent range entries.
// The given slice has to be sorted in increasing order.
func merge(r []address.Range) []address.Range {
var merged []address.Range
for i := range r {
if prev := len(merged) - 1; prev >= 0 && merged[prev].End == r[i].Start {
merged[prev].End = r[i].End
} else {
merged = append(merged, r[i])
}
}
return merged
}
// removeCommon filters out CIDR ranges which are contained in both a and b slices.
// Both slices have to be sorted in increasing order.
func removeCommon(a, b []address.CIDR) (newA, newB []address.CIDR) {
i, j := 0, 0
for i < len(a) && j < len(b) {
switch {
case a[i].Start() < b[j].Start() || a[i].End() < b[j].End():
newA = append(newA, a[i])
i++
case a[i].Start() > b[j].Start() || a[i].End() > b[j].End():
newB = append(newB, b[j])
j++
default:
i++
j++
}
}
newA = append(newA, a[i:]...)
newB = append(newB, b[j:]...)
return
}
func parseCIDR(cidr string) (*net.IPNet, error) {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}
ipnet.IP = ip
return ipnet, nil
}
+52
View File
@@ -0,0 +1,52 @@
package tracker
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/weaveworks/weave/net/address"
)
var (
r0to127 = cidr("10.0.0.0", "10.0.0.127")
r128to255 = cidr("10.0.0.128", "10.0.0.255")
r0to255 = cidr("10.0.0.0", "10.0.0.255")
r1dot0to255 = cidr("10.0.1.0", "10.0.1.255")
r2dot0to255 = cidr("10.0.2.0", "10.0.2.255")
)
func TestRemoveCommon(t *testing.T) {
a := []address.CIDR{r0to127, r1dot0to255}
b := []address.CIDR{r1dot0to255, r2dot0to255}
newA, newB := removeCommon(a, b)
require.Equal(t, []address.CIDR{r0to127}, newA)
require.Equal(t, []address.CIDR{r2dot0to255}, newB)
}
func TestMerge(t *testing.T) {
ranges := []address.Range{
r0to127.Range(),
r128to255.Range(),
r2dot0to255.Range(),
}
require.Equal(t, []address.Range{r0to255.Range(), r2dot0to255.Range()}, merge(ranges))
}
// Helper
// TODO(mp) DRY with helpers of other tests.
func ip(s string) address.Address {
addr, _ := address.ParseIP(s)
return addr
}
// [start; end]
func cidr(start, end string) address.CIDR {
c := address.Range{Start: ip(start), End: ip(end) + 1}.CIDRs()
if len(c) != 1 {
panic("invalid cidr")
}
return c[0]
}
+20
View File
@@ -0,0 +1,20 @@
package tracker
import (
"github.com/weaveworks/weave/net/address"
)
// LocalRangeTracker is an interface for tracking changes in the IPAM ring.
type LocalRangeTracker interface {
// HandleUpdate is called whenever an address ring gets updated.
//
// prevRanges corresponds to ranges which were owned by a peer before
// a change in the ring, while currRanges to the ones which are currently
// owned by the peer.
// Both slices have to be sorted in increasing order.
// Adjacent ranges within each slice might appear as separate ranges.
//
// The local parameter indicates whether the ranges belong to the peer
// by which the method is called.
HandleUpdate(prevRanges, currRanges []address.Range, local bool) error
}
-437
View File
@@ -1,437 +0,0 @@
package mesh
import (
"fmt"
"net"
"strconv"
"sync"
"time"
)
type Connection interface {
Local() *Peer
Remote() *Peer
RemoteTCPAddr() string
Outbound() bool
Established() bool
BreakTie(Connection) ConnectionTieBreak
Shutdown(error)
Log(args ...interface{})
}
type ConnectionTieBreak int
const (
TieBreakWon ConnectionTieBreak = iota
TieBreakLost
TieBreakTied
)
var ErrConnectToSelf = fmt.Errorf("Cannot connect to ourself")
type RemoteConnection struct {
local *Peer
remote *Peer
remoteTCPAddr string
outbound bool
established bool
}
type LocalConnection struct {
sync.RWMutex
RemoteConnection
TCPConn *net.TCPConn
version byte
tcpSender TCPSender
SessionKey *[32]byte
heartbeatTCP *time.Ticker
Router *Router
uid uint64
actionChan chan<- ConnectionAction
finished <-chan struct{} // closed to signal that actorLoop has finished
OverlayConn OverlayConnection
}
type ConnectionAction func() error
func NewRemoteConnection(from, to *Peer, tcpAddr string, outbound bool, established bool) *RemoteConnection {
return &RemoteConnection{
local: from,
remote: to,
remoteTCPAddr: tcpAddr,
outbound: outbound,
established: established,
}
}
func (conn *RemoteConnection) Local() *Peer { return conn.local }
func (conn *RemoteConnection) Remote() *Peer { return conn.remote }
func (conn *RemoteConnection) RemoteTCPAddr() string { return conn.remoteTCPAddr }
func (conn *RemoteConnection) Outbound() bool { return conn.outbound }
func (conn *RemoteConnection) Established() bool { return conn.established }
func (conn *RemoteConnection) BreakTie(Connection) ConnectionTieBreak { return TieBreakTied }
func (conn *RemoteConnection) Shutdown(error) {}
func (conn *RemoteConnection) Log(args ...interface{}) {
log.Println(append(append([]interface{}{}, fmt.Sprintf("->[%s|%s]:", conn.remoteTCPAddr, conn.remote)), args...)...)
}
func (conn *RemoteConnection) ErrorLog(args ...interface{}) {
log.Errorln(append(append([]interface{}{}, fmt.Sprintf("->[%s|%s]:", conn.remoteTCPAddr, conn.remote)), args...)...)
}
// Does not return anything. If the connection is successful, it will
// end up in the local peer's connections map.
func StartLocalConnection(connRemote *RemoteConnection, tcpConn *net.TCPConn, router *Router, acceptNewPeer bool) {
if connRemote.local != router.Ourself.Peer {
log.Fatal("Attempt to create local connection from a peer which is not ourself")
}
// NB, we're taking a copy of connRemote here.
actionChan := make(chan ConnectionAction, ChannelSize)
finished := make(chan struct{})
conn := &LocalConnection{
RemoteConnection: *connRemote,
Router: router,
TCPConn: tcpConn,
uid: randUint64(),
actionChan: actionChan,
finished: finished}
go conn.run(actionChan, finished, acceptNewPeer)
}
func (conn *LocalConnection) BreakTie(dupConn Connection) ConnectionTieBreak {
dupConnLocal := dupConn.(*LocalConnection)
// conn.uid is used as the tie breaker here, in the knowledge that
// both sides will make the same decision.
if conn.uid < dupConnLocal.uid {
return TieBreakWon
} else if dupConnLocal.uid < conn.uid {
return TieBreakLost
} else {
return TieBreakTied
}
}
func (conn *LocalConnection) Established() bool {
return conn.established
}
// Send directly, not via the Actor. If it goes via the Actor we can
// get a deadlock where LocalConnection is blocked talking to
// LocalPeer and LocalPeer is blocked trying send a ProtocolMsg via
// LocalConnection, and the channels are full in both directions so
// nothing can proceed.
func (conn *LocalConnection) SendProtocolMsg(m ProtocolMsg) {
if err := conn.sendProtocolMsg(m); err != nil {
conn.Shutdown(err)
}
}
// ACTOR methods
// NB: The conn.* fields are only written by the connection actor
// process, which is the caller of the ConnectionAction funs. Hence we
// do not need locks for reading, and only need write locks for fields
// read by other processes.
// Async
func (conn *LocalConnection) Shutdown(err error) {
// err should always be a real error, even if only io.EOF
if err == nil {
panic("nil error")
}
// Run on its own goroutine in case the channel is backed up
go func() { conn.sendAction(func() error { return err }) }()
}
// Send an actor request to the actorLoop, but don't block if
// actorLoop has exited - see http://blog.golang.org/pipelines for
// pattern
func (conn *LocalConnection) sendAction(action ConnectionAction) {
select {
case conn.actionChan <- action:
case <-conn.finished:
}
}
// ACTOR server
func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished chan<- struct{}, acceptNewPeer bool) {
var err error // important to use this var and not create another one with 'err :='
defer func() { conn.shutdown(err) }()
defer close(finished)
conn.TCPConn.SetLinger(0)
intro, err := ProtocolIntroParams{
MinVersion: conn.Router.ProtocolMinVersion,
MaxVersion: ProtocolMaxVersion,
Features: conn.makeFeatures(),
Conn: conn.TCPConn,
Password: conn.Router.Password,
Outbound: conn.outbound,
}.DoIntro()
if err != nil {
return
}
conn.SessionKey = intro.SessionKey
conn.tcpSender = intro.Sender
conn.version = intro.Version
remote, err := conn.parseFeatures(intro.Features)
if err != nil {
return
}
if err = conn.registerRemote(remote, acceptNewPeer); err != nil {
return
}
conn.Log("connection ready; using protocol version", conn.version)
params := OverlayConnectionParams{
RemotePeer: conn.remote,
LocalAddr: conn.TCPConn.LocalAddr().(*net.TCPAddr),
RemoteAddr: conn.TCPConn.RemoteAddr().(*net.TCPAddr),
Outbound: conn.outbound,
ConnUID: conn.uid,
SessionKey: conn.SessionKey,
SendControlMessage: conn.sendOverlayControlMessage,
Features: intro.Features,
}
if conn.OverlayConn, err = conn.Router.Overlay.PrepareConnection(params); err != nil {
return
}
// As soon as we do AddConnection, the new connection becomes
// visible to the packet routing logic. So AddConnection must
// come after PrepareConnection
if err = conn.Router.Ourself.AddConnection(conn); err != nil {
return
}
conn.Router.ConnectionMaker.ConnectionCreated(conn)
// OverlayConnection confirmation comes after AddConnection,
// because only after that completes do we know the connection is
// valid: in particular that it is not a duplicate connection to
// the same peer. Overlay communication on a duplicate connection
// can cause problems such as tripping up overlay crypto at the
// other end due to data being decoded by the other connection. It
// is also generally wasteful to engage in any interaction with
// the remote on a connection that turns out to be invalid.
conn.OverlayConn.Confirm()
// receiveTCP must follow also AddConnection. In the absence
// of any indirect connectivity to the remote peer, the first
// we hear about it (and any peers reachable from it) is
// through topology gossip it sends us on the connection. We
// must ensure that the connection has been added to Ourself
// prior to processing any such gossip, otherwise we risk
// immediately gc'ing part of that newly received portion of
// the topology (though not the remote peer itself, since that
// will have a positive ref count), leaving behind dangling
// references to peers. Hence we must invoke AddConnection,
// which is *synchronous*, first.
conn.heartbeatTCP = time.NewTicker(TCPHeartbeat)
go conn.receiveTCP(intro.Receiver)
// AddConnection must precede actorLoop. More precisely, it
// must precede shutdown, since that invokes DeleteConnection
// and is invoked on termination of this entire
// function. Essentially this boils down to a prohibition on
// running AddConnection in a separate goroutine, at least not
// without some synchronisation. Which in turn requires the
// launching of the receiveTCP goroutine to precede actorLoop.
err = conn.actorLoop(actionChan)
}
func (conn *LocalConnection) makeFeatures() map[string]string {
features := map[string]string{
"PeerNameFlavour": PeerNameFlavour,
"Name": conn.local.Name.String(),
"NickName": conn.local.NickName,
"ShortID": fmt.Sprint(conn.local.ShortID),
"UID": fmt.Sprint(conn.local.UID),
"ConnID": fmt.Sprint(conn.uid),
}
conn.Router.Overlay.AddFeaturesTo(features)
return features
}
type features map[string]string
func (features features) MustHave(keys []string) error {
for _, key := range keys {
if _, ok := features[key]; !ok {
return fmt.Errorf("Field %s is missing", key)
}
}
return nil
}
func (features features) Get(key string) string {
return features[key]
}
func (conn *LocalConnection) parseFeatures(features features) (*Peer, error) {
if err := features.MustHave([]string{"PeerNameFlavour", "Name", "NickName", "UID", "ConnID"}); err != nil {
return nil, err
}
remotePeerNameFlavour := features.Get("PeerNameFlavour")
if remotePeerNameFlavour != PeerNameFlavour {
return nil, fmt.Errorf("Peer name flavour mismatch (ours: '%s', theirs: '%s')", PeerNameFlavour, remotePeerNameFlavour)
}
name, err := PeerNameFromString(features.Get("Name"))
if err != nil {
return nil, err
}
nickName := features.Get("NickName")
var shortID uint64
var hasShortID bool
if shortIDStr, present := features["ShortID"]; present {
hasShortID = true
shortID, err = strconv.ParseUint(shortIDStr, 10,
PeerShortIDBits)
if err != nil {
return nil, err
}
}
uid, err := ParsePeerUID(features.Get("UID"))
if err != nil {
return nil, err
}
remoteConnID, err := strconv.ParseUint(features.Get("ConnID"), 10, 64)
if err != nil {
return nil, err
}
conn.uid ^= remoteConnID
peer := NewPeer(name, nickName, uid, 0, PeerShortID(shortID))
peer.HasShortID = hasShortID
return peer, nil
}
func (conn *LocalConnection) registerRemote(remote *Peer, acceptNewPeer bool) error {
if acceptNewPeer {
conn.remote = conn.Router.Peers.FetchWithDefault(remote)
} else {
conn.remote = conn.Router.Peers.FetchAndAddRef(remote.Name)
if conn.remote == nil {
return fmt.Errorf("Found unknown remote name: %s at %s", remote.Name, conn.remoteTCPAddr)
}
}
if conn.remote == conn.local {
return ErrConnectToSelf
}
return nil
}
func (conn *LocalConnection) actorLoop(actionChan <-chan ConnectionAction) (err error) {
fwdErrorChan := conn.OverlayConn.ErrorChannel()
fwdEstablishedChan := conn.OverlayConn.EstablishedChannel()
for err == nil {
select {
case action := <-actionChan:
err = action()
case <-conn.heartbeatTCP.C:
err = conn.sendSimpleProtocolMsg(ProtocolHeartbeat)
case <-fwdEstablishedChan:
conn.established = true
fwdEstablishedChan = nil
conn.Router.Ourself.ConnectionEstablished(conn)
case err = <-fwdErrorChan:
}
}
return
}
func (conn *LocalConnection) shutdown(err error) {
if conn.remote == nil {
log.Errorf("->[%s] connection shutting down due to error during handshake: %v", conn.remoteTCPAddr, err)
} else {
conn.ErrorLog("connection shutting down due to error:", err)
}
if conn.TCPConn != nil {
checkWarn(conn.TCPConn.Close())
}
if conn.remote != nil {
conn.Router.Peers.Dereference(conn.remote)
conn.Router.Ourself.DeleteConnection(conn)
}
if conn.heartbeatTCP != nil {
conn.heartbeatTCP.Stop()
}
if conn.OverlayConn != nil {
conn.OverlayConn.Stop()
}
conn.Router.ConnectionMaker.ConnectionTerminated(conn, err)
}
func (conn *LocalConnection) sendOverlayControlMessage(tag byte, msg []byte) error {
return conn.sendProtocolMsg(ProtocolMsg{ProtocolTag(tag), msg})
}
// Helpers
func (conn *LocalConnection) sendSimpleProtocolMsg(tag ProtocolTag) error {
return conn.sendProtocolMsg(ProtocolMsg{tag: tag})
}
func (conn *LocalConnection) sendProtocolMsg(m ProtocolMsg) error {
return conn.tcpSender.Send(append([]byte{byte(m.tag)}, m.msg...))
}
func (conn *LocalConnection) receiveTCP(receiver TCPReceiver) {
var err error
for {
conn.extendReadDeadline()
var msg []byte
if msg, err = receiver.Receive(); err != nil {
break
}
if len(msg) < 1 {
conn.Log("ignoring blank msg")
continue
}
if err = conn.handleProtocolMsg(ProtocolTag(msg[0]), msg[1:]); err != nil {
break
}
}
conn.Shutdown(err)
}
func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte) error {
switch tag {
case ProtocolHeartbeat:
case ProtocolReserved1, ProtocolReserved2, ProtocolReserved3, ProtocolOverlayControlMsg:
conn.OverlayConn.ControlMessage(byte(tag), payload)
case ProtocolGossipUnicast, ProtocolGossipBroadcast, ProtocolGossip:
return conn.Router.handleGossip(tag, payload)
default:
conn.Log("ignoring unknown protocol tag:", tag)
}
return nil
}
func (conn *LocalConnection) extendReadDeadline() {
conn.TCPConn.SetReadDeadline(time.Now().Add(TCPHeartbeat * 2))
}
-312
View File
@@ -1,312 +0,0 @@
package mesh
import (
"fmt"
"math/rand"
"net"
"time"
)
const (
InitialInterval = 2 * time.Second
MaxInterval = 6 * time.Minute
ResetAfter = 1 * time.Minute
)
type peerAddrs map[string]*net.TCPAddr
type ConnectionMaker struct {
ourself *LocalPeer
peers *Peers
port int
discovery bool
targets map[string]*Target
connections map[Connection]struct{}
directPeers peerAddrs
actionChan chan<- ConnectionMakerAction
}
type TargetState int
const (
TargetWaiting TargetState = iota // we are waiting to connect there
TargetAttempting // we are attempting to connect there
TargetConnected // we are connected to there
)
// Information about an address where we may find a peer
type Target struct {
state TargetState
lastError error // reason for disconnection last time
tryAfter time.Time // next time to try this address
tryInterval time.Duration // retry delay on next failure
}
type ConnectionMakerAction func() bool
func NewConnectionMaker(ourself *LocalPeer, peers *Peers, port int, discovery bool) *ConnectionMaker {
actionChan := make(chan ConnectionMakerAction, ChannelSize)
cm := &ConnectionMaker{
ourself: ourself,
peers: peers,
port: port,
discovery: discovery,
directPeers: peerAddrs{},
targets: make(map[string]*Target),
connections: make(map[Connection]struct{}),
actionChan: actionChan}
go cm.queryLoop(actionChan)
return cm
}
func (cm *ConnectionMaker) InitiateConnections(peers []string, replace bool) []error {
errors := []error{}
addrs := peerAddrs{}
for _, peer := range peers {
host, port, err := net.SplitHostPort(peer)
if err != nil {
host = peer
port = "0" // we use that as an indication that "no port was supplied"
}
if addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%s", host, port)); err != nil {
errors = append(errors, err)
} else {
addrs[peer] = addr
}
}
cm.actionChan <- func() bool {
if replace {
cm.directPeers = peerAddrs{}
}
for peer, addr := range addrs {
cm.directPeers[peer] = addr
// curtail any existing reconnect interval
if target, found := cm.targets[addr.String()]; found {
target.nextTryNow()
}
}
return true
}
return errors
}
func (cm *ConnectionMaker) ForgetConnections(peers []string) {
cm.actionChan <- func() bool {
for _, peer := range peers {
delete(cm.directPeers, peer)
}
return false
}
}
func (cm *ConnectionMaker) ConnectionAborted(address string, err error) {
cm.actionChan <- func() bool {
target := cm.targets[address]
target.state = TargetWaiting
target.lastError = err
target.nextTryLater()
return true
}
}
func (cm *ConnectionMaker) ConnectionCreated(conn Connection) {
cm.actionChan <- func() bool {
cm.connections[conn] = void
if conn.Outbound() {
target := cm.targets[conn.RemoteTCPAddr()]
target.state = TargetConnected
}
return false
}
}
func (cm *ConnectionMaker) ConnectionTerminated(conn Connection, err error) {
cm.actionChan <- func() bool {
delete(cm.connections, conn)
if conn.Outbound() {
target := cm.targets[conn.RemoteTCPAddr()]
target.state = TargetWaiting
target.lastError = err
switch {
case err == ErrConnectToSelf:
target.nextTryNever()
case time.Now().After(target.tryAfter.Add(ResetAfter)):
target.nextTryNow()
default:
target.nextTryLater()
}
}
return true
}
}
func (cm *ConnectionMaker) Refresh() {
cm.actionChan <- func() bool { return true }
}
func (cm *ConnectionMaker) queryLoop(actionChan <-chan ConnectionMakerAction) {
timer := time.NewTimer(MaxDuration)
run := func() { timer.Reset(cm.checkStateAndAttemptConnections()) }
for {
select {
case action := <-actionChan:
if action() {
run()
}
case <-timer.C:
run()
}
}
}
func (cm *ConnectionMaker) checkStateAndAttemptConnections() time.Duration {
var (
validTarget = make(map[string]struct{})
directTarget = make(map[string]struct{})
)
ourConnectedPeers, ourConnectedTargets, ourInboundIPs := cm.ourConnections()
addTarget := func(address string) {
if _, connected := ourConnectedTargets[address]; connected {
return
}
validTarget[address] = void
if _, found := cm.targets[address]; found {
return
}
target := &Target{state: TargetWaiting}
target.nextTryNow()
cm.targets[address] = target
}
// Add direct targets that are not connected
for _, addr := range cm.directPeers {
completeAddr := *addr
attempt := true
if completeAddr.Port == 0 {
completeAddr.Port = cm.port
// If a peer was specified w/o a port, then we do not
// attempt to connect to it if we have any inbound
// connections from that IP.
if _, connected := ourInboundIPs[completeAddr.IP.String()]; connected {
attempt = false
}
}
address := completeAddr.String()
directTarget[address] = void
if attempt {
addTarget(address)
}
}
// Add targets for peers that someone else is connected to, but we
// aren't
if cm.discovery {
cm.addPeerTargets(ourConnectedPeers, addTarget)
}
return cm.connectToTargets(validTarget, directTarget)
}
func (cm *ConnectionMaker) ourConnections() (PeerNameSet, map[string]struct{}, map[string]struct{}) {
var (
ourConnectedPeers = make(PeerNameSet)
ourConnectedTargets = make(map[string]struct{})
ourInboundIPs = make(map[string]struct{})
)
for conn := range cm.connections {
address := conn.RemoteTCPAddr()
ourConnectedPeers[conn.Remote().Name] = void
ourConnectedTargets[address] = void
if conn.Outbound() {
continue
}
if ip, _, err := net.SplitHostPort(address); err == nil { // should always succeed
ourInboundIPs[ip] = void
}
}
return ourConnectedPeers, ourConnectedTargets, ourInboundIPs
}
func (cm *ConnectionMaker) addPeerTargets(ourConnectedPeers PeerNameSet, addTarget func(string)) {
cm.peers.ForEach(func(peer *Peer) {
if peer == cm.ourself.Peer {
return
}
// Modifying peer.connections requires a write lock on Peers,
// and since we are holding a read lock (due to the ForEach),
// access without locking the peer is safe.
for otherPeer, conn := range peer.connections {
if otherPeer == cm.ourself.Name {
continue
}
if _, connected := ourConnectedPeers[otherPeer]; connected {
continue
}
address := conn.RemoteTCPAddr()
if conn.Outbound() {
addTarget(address)
} else if ip, _, err := net.SplitHostPort(address); err == nil {
// There is no point connecting to the (likely
// ephemeral) remote port of an inbound connection
// that some peer has. Let's try to connect on the
// weave port instead.
addTarget(fmt.Sprintf("%s:%d", ip, cm.port))
}
}
})
}
func (cm *ConnectionMaker) connectToTargets(validTarget map[string]struct{}, directTarget map[string]struct{}) time.Duration {
now := time.Now() // make sure we catch items just added
after := MaxDuration
for address, target := range cm.targets {
if target.state != TargetWaiting {
continue
}
if _, valid := validTarget[address]; !valid {
delete(cm.targets, address)
continue
}
if target.tryAfter.IsZero() {
continue
}
switch duration := target.tryAfter.Sub(now); {
case duration <= 0:
target.state = TargetAttempting
_, isCmdLineTarget := directTarget[address]
go cm.attemptConnection(address, isCmdLineTarget)
case duration < after:
after = duration
}
}
return after
}
func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
log.Printf("->[%s] attempting connection", address)
if err := cm.ourself.CreateConnection(address, acceptNewPeer); err != nil {
log.Errorf("->[%s] error during connection attempt: %v", address, err)
cm.ConnectionAborted(address, err)
}
}
func (t *Target) nextTryNever() {
t.tryAfter = time.Time{}
t.tryInterval = MaxInterval
}
func (t *Target) nextTryNow() {
t.tryAfter = time.Now()
t.tryInterval = InitialInterval
}
// The delay at the nth retry is a random value in the range
// [i-i/2,i+i/2], where i = InitialInterval * 1.5^(n-1).
func (t *Target) nextTryLater() {
t.tryAfter = time.Now().Add(t.tryInterval/2 + time.Duration(rand.Int63n(int64(t.tryInterval))))
t.tryInterval = t.tryInterval * 3 / 2
if t.tryInterval > MaxInterval {
t.tryInterval = MaxInterval
}
}
-171
View File
@@ -1,171 +0,0 @@
package mesh
import (
"fmt"
)
type GossipData interface {
Encode() [][]byte
Merge(GossipData)
}
type Gossip interface {
// specific message from one peer to another
// intermediate peers relay it using unicast topology.
GossipUnicast(dstPeerName PeerName, msg []byte) error
// send gossip to every peer, relayed using broadcast topology.
GossipBroadcast(update GossipData) error
}
type Gossiper interface {
OnGossipUnicast(sender PeerName, msg []byte) error
// merge received data into state and return a representation of
// the received data, for further propagation
OnGossipBroadcast(sender PeerName, update []byte) (GossipData, error)
// return state of everything we know; gets called periodically
Gossip() GossipData
// merge received data into state and return "everything new I've
// just learnt", or nil if nothing in the received data was new
OnGossip(update []byte) (GossipData, error)
}
// Accumulates GossipData that needs to be sent to one destination,
// and sends it when possible.
type GossipSender struct {
send func(GossipData)
cell chan GossipData
// for testing
sent bool
flushch chan chan bool
}
func NewGossipSender(send func(GossipData)) *GossipSender {
cell := make(chan GossipData, 1)
flushch := make(chan chan bool)
sender := &GossipSender{
send: send,
cell: cell,
flushch: flushch,
}
go sender.run()
return sender
}
func (sender *GossipSender) run() {
for {
select {
case pending := <-sender.cell:
if pending == nil { // receive zero value when chan is closed
return
}
sender.send(pending)
sender.sent = true
case ch := <-sender.flushch:
// send anything pending, then reply back whether we sent
// anything since previous flush
select {
case pending := <-sender.cell:
sender.send(pending)
sender.sent = true
default:
}
ch <- sender.sent
sender.sent = false
}
}
}
func (sender *GossipSender) Send(data GossipData) {
// NB: this must not be invoked concurrently
select {
case pending := <-sender.cell:
pending.Merge(data)
sender.cell <- pending
default:
sender.cell <- data
}
}
func (sender *GossipSender) Stop() {
close(sender.cell)
}
type GossipChannels map[string]*GossipChannel
func (router *Router) NewGossip(channelName string, g Gossiper) Gossip {
channel := NewGossipChannel(channelName, router.Ourself, router.Routes, g)
router.gossipLock.Lock()
defer router.gossipLock.Unlock()
if _, found := router.gossipChannels[channelName]; found {
checkFatal(fmt.Errorf("[gossip] duplicate channel %s", channelName))
}
router.gossipChannels[channelName] = channel
return channel
}
func (router *Router) gossipChannel(channelName string) *GossipChannel {
router.gossipLock.RLock()
channel, found := router.gossipChannels[channelName]
router.gossipLock.RUnlock()
if found {
return channel
}
router.gossipLock.Lock()
defer router.gossipLock.Unlock()
if channel, found = router.gossipChannels[channelName]; found {
return channel
}
channel = NewGossipChannel(channelName, router.Ourself, router.Routes, &surrogateGossiper)
channel.log("created surrogate channel")
router.gossipChannels[channelName] = channel
return channel
}
func (router *Router) gossipChannelSet() map[*GossipChannel]struct{} {
channels := make(map[*GossipChannel]struct{})
router.gossipLock.RLock()
defer router.gossipLock.RUnlock()
for _, channel := range router.gossipChannels {
channels[channel] = void
}
return channels
}
func (router *Router) SendAllGossip() {
for channel := range router.gossipChannelSet() {
if gossip := channel.gossiper.Gossip(); gossip != nil {
channel.Send(router.Ourself.Name, gossip)
}
}
}
func (router *Router) SendAllGossipDown(conn Connection) {
for channel := range router.gossipChannelSet() {
if gossip := channel.gossiper.Gossip(); gossip != nil {
channel.SendDown(conn, channel.gossiper.Gossip())
}
}
}
// for testing
func (router *Router) sendPendingGossip() bool {
sentSomething := false
for channel := range router.gossipChannelSet() {
channel.Lock()
for _, sender := range channel.senders {
sentSomething = sender.flush() || sentSomething
}
for _, sender := range channel.broadcasters {
sentSomething = sender.flush() || sentSomething
}
channel.Unlock()
}
return sentSomething
}
func (sender *GossipSender) flush() bool {
ch := make(chan bool)
sender.flushch <- ch
return <-ch
}
-250
View File
@@ -1,250 +0,0 @@
package mesh
import (
"bytes"
"encoding/gob"
"fmt"
"sync"
)
type GossipChannel struct {
sync.Mutex
name string
ourself *LocalPeer
routes *Routes
gossiper Gossiper
senders connectionSenders
broadcasters peerSenders
}
type connectionSenders map[Connection]*GossipSender
type peerSenders map[PeerName]*GossipSender
func NewGossipChannel(channelName string, ourself *LocalPeer, routes *Routes, g Gossiper) *GossipChannel {
return &GossipChannel{
name: channelName,
ourself: ourself,
routes: routes,
gossiper: g,
senders: make(connectionSenders),
broadcasters: make(peerSenders)}
}
func (router *Router) handleGossip(tag ProtocolTag, payload []byte) error {
decoder := gob.NewDecoder(bytes.NewReader(payload))
var channelName string
if err := decoder.Decode(&channelName); err != nil {
return err
}
channel := router.gossipChannel(channelName)
var srcName PeerName
if err := decoder.Decode(&srcName); err != nil {
return err
}
switch tag {
case ProtocolGossipUnicast:
return channel.deliverUnicast(srcName, payload, decoder)
case ProtocolGossipBroadcast:
return channel.deliverBroadcast(srcName, payload, decoder)
case ProtocolGossip:
return channel.deliver(srcName, payload, decoder)
}
return nil
}
func (c *GossipChannel) deliverUnicast(srcName PeerName, origPayload []byte, dec *gob.Decoder) error {
var destName PeerName
if err := dec.Decode(&destName); err != nil {
return err
}
if c.ourself.Name != destName {
if err := c.relayUnicast(destName, origPayload); err != nil {
// just log errors from relayUnicast; a problem between us and destination
// is not enough reason to break the connection from the source
c.log(err)
}
return nil
}
var payload []byte
if err := dec.Decode(&payload); err != nil {
return err
}
return c.gossiper.OnGossipUnicast(srcName, payload)
}
func (c *GossipChannel) deliverBroadcast(srcName PeerName, _ []byte, dec *gob.Decoder) error {
var payload []byte
if err := dec.Decode(&payload); err != nil {
return err
}
data, err := c.gossiper.OnGossipBroadcast(srcName, payload)
if err != nil || data == nil {
return err
}
return c.relayBroadcast(srcName, data)
}
func (c *GossipChannel) deliver(srcName PeerName, _ []byte, dec *gob.Decoder) error {
var payload []byte
if err := dec.Decode(&payload); err != nil {
return err
}
if data, err := c.gossiper.OnGossip(payload); err != nil {
return err
} else if data != nil {
c.Send(srcName, data)
}
return nil
}
func (c *GossipChannel) Send(srcName PeerName, data GossipData) {
// do this outside the lock below so we avoid lock nesting
c.routes.EnsureRecalculated()
selectedConnections := make(ConnectionSet)
for name := range c.routes.RandomNeighbours(srcName) {
if conn, found := c.ourself.ConnectionTo(name); found {
selectedConnections[conn] = void
}
}
if len(selectedConnections) == 0 {
return
}
connections := c.ourself.Connections()
c.Lock()
defer c.Unlock()
c.gcSenders(connections)
for conn := range selectedConnections {
c.sendDown(conn, data)
}
}
func (c *GossipChannel) SendDown(conn Connection, data GossipData) {
connections := c.ourself.Connections()
c.Lock()
defer c.Unlock()
c.gcSenders(connections)
c.sendDown(conn, data)
}
// GC - randomly (courtesy of go's map iterator) pick some existing
// senders and stop&remove them if the associated connection is no
// longer active. We stop as soon as we encounter a valid entry; the
// idea being that when there is little or no garbage then this
// executes close to O(1)[1], whereas when there is lots of garbage we
// remove it quickly.
//
// [1] TODO Unfortunately, due to the desire to avoid nested locks,
// instead of simply invoking LocalPeer.ConnectionTo(name), we pass in
// the result of LocalPeer.Connections(). That is O(n_our_connections)
// at best.
func (c *GossipChannel) gcSenders(connections ConnectionSet) {
for conn, sender := range c.senders {
if _, found := connections[conn]; !found {
delete(c.senders, conn)
sender.Stop()
} else {
break
}
}
}
// We have seen a couple of failures which suggest a >128GB slice was encountered.
// 100MB should be enough for anyone.
const maxFeasibleMessageLen = 100 * 1024 * 1024
func (c *GossipChannel) sendDown(conn Connection, data GossipData) {
sender, found := c.senders[conn]
if !found {
sender = NewGossipSender(func(pending GossipData) {
for _, msg := range pending.Encode() {
if len(msg) > maxFeasibleMessageLen {
panic(fmt.Sprintf("Gossip message too large: len=%d bytes; on channel '%s' from %+v", len(msg), c.name, pending))
}
protocolMsg := ProtocolMsg{ProtocolGossip, GobEncode(c.name, c.ourself.Name, msg)}
conn.(ProtocolSender).SendProtocolMsg(protocolMsg)
}
})
c.senders[conn] = sender
}
sender.Send(data)
}
func (c *GossipChannel) GossipUnicast(dstPeerName PeerName, msg []byte) error {
return c.relayUnicast(dstPeerName, GobEncode(c.name, c.ourself.Name, dstPeerName, msg))
}
func (c *GossipChannel) GossipBroadcast(update GossipData) error {
return c.relayBroadcast(c.ourself.Name, update)
}
func (c *GossipChannel) relayUnicast(dstPeerName PeerName, buf []byte) (err error) {
if relayPeerName, found := c.routes.UnicastAll(dstPeerName); !found {
err = fmt.Errorf("unknown relay destination: %s", dstPeerName)
} else if conn, found := c.ourself.ConnectionTo(relayPeerName); !found {
err = fmt.Errorf("unable to find connection to relay peer %s", relayPeerName)
} else {
conn.(ProtocolSender).SendProtocolMsg(ProtocolMsg{ProtocolGossipUnicast, buf})
}
return err
}
func (c *GossipChannel) relayBroadcast(srcName PeerName, update GossipData) error {
names := c.routes.PeerNames() // do this outside the lock so they don't nest
c.Lock()
defer c.Unlock()
// GC - randomly (courtesy of go's map iterator) pick some
// existing broadcasters and stop&remove them if their source peer
// is unknown. We stop as soon as we encounter a valid entry; the
// idea being that when there is little or no garbage then this
// executes close to O(1)[1], whereas when there is lots of
// garbage we remove it quickly.
//
// [1] TODO Unfortunately, due to the desire to avoid nested
// locks, instead of simply invoking Peers.Fetch(name) below, we
// have that Peers.Names() invocation above. That is O(n_peers) at
// best.
for name, broadcaster := range c.broadcasters {
if _, found := names[name]; !found {
delete(c.broadcasters, name)
broadcaster.Stop()
} else {
break
}
}
broadcaster, found := c.broadcasters[srcName]
if !found {
broadcaster = NewGossipSender(func(pending GossipData) { c.sendBroadcast(srcName, pending) })
c.broadcasters[srcName] = broadcaster
}
broadcaster.Send(update)
return nil
}
func (c *GossipChannel) sendBroadcast(srcName PeerName, update GossipData) {
c.routes.EnsureRecalculated()
nextHops := c.routes.BroadcastAll(srcName)
if len(nextHops) == 0 {
return
}
connections := c.ourself.ConnectionsTo(nextHops)
for _, msg := range update.Encode() {
protocolMsg := ProtocolMsg{ProtocolGossipBroadcast, GobEncode(c.name, srcName, msg)}
// FIXME a single blocked connection can stall us
for _, conn := range connections {
conn.(ProtocolSender).SendProtocolMsg(protocolMsg)
}
}
}
func (c *GossipChannel) log(args ...interface{}) {
log.Println(append(append([]interface{}{}, "[gossip "+c.name+"]:"), args...)...)
}
func GobEncode(items ...interface{}) []byte {
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
for _, i := range items {
checkFatal(enc.Encode(i))
}
return buf.Bytes()
}
-259
View File
@@ -1,259 +0,0 @@
package mesh
import (
"fmt"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
wt "github.com/weaveworks/weave/testing"
)
// TODO test gossip unicast; atm we only test topology gossip and
// surrogates, neither of which employ unicast.
type mockChannelConnection struct {
RemoteConnection
dest *Router
}
func NewTestRouter(name string) *Router {
peerName, _ := PeerNameFromString(name)
router := NewRouter(Config{}, peerName, "nick", nil)
router.Start()
return router
}
func (conn *mockChannelConnection) SendProtocolMsg(protocolMsg ProtocolMsg) {
if err := conn.dest.handleGossip(protocolMsg.tag, protocolMsg.msg); err != nil {
panic(err)
}
}
func sendPendingGossip(routers ...*Router) {
// Loop until all routers report they didn't send anything
for sentSomething := true; sentSomething; {
sentSomething = false
for _, router := range routers {
sentSomething = router.sendPendingGossip() || sentSomething
}
}
}
func (router *Router) AddTestChannelConnection(r *Router) {
fromPeer := NewPeerFrom(router.Ourself.Peer)
toPeer := NewPeerFrom(r.Ourself.Peer)
r.Peers.FetchWithDefault(fromPeer) // Has side-effect of incrementing refcount
router.Peers.FetchWithDefault(toPeer) //
conn := &mockChannelConnection{RemoteConnection{router.Ourself.Peer, toPeer, "", false, true}, r}
router.Ourself.handleAddConnection(conn)
router.Ourself.handleConnectionEstablished(conn)
}
func (router *Router) DeleteTestChannelConnection(r *Router) {
fromName := router.Ourself.Peer.Name
toName := r.Ourself.Peer.Name
fromPeer := r.Peers.Fetch(fromName)
toPeer := router.Peers.Fetch(toName)
r.Peers.Dereference(fromPeer)
router.Peers.Dereference(toPeer)
conn, _ := router.Ourself.ConnectionTo(toName)
router.Ourself.handleDeleteConnection(conn)
}
func TestGossipTopology(t *testing.T) {
wt.RunWithTimeout(t, 5*time.Second, func() {
implTestGossipTopology(t)
})
}
// Create a Peer representing the receiver router, with connections to
// the routers supplied as arguments, carrying across all UID and
// version information.
func (router *Router) tp(routers ...*Router) *Peer {
peer := NewPeerFrom(router.Ourself.Peer)
connections := make(map[PeerName]Connection)
for _, r := range routers {
p := NewPeerFrom(r.Ourself.Peer)
connections[r.Ourself.Peer.Name] = newMockConnection(peer, p)
}
peer.Version = router.Ourself.Peer.Version
peer.connections = connections
return peer
}
// Check that the topology of router matches the peers and all of their connections
func checkTopology(t *testing.T, router *Router, wantedPeers ...*Peer) {
router.Peers.RLock()
checkTopologyPeers(t, true, router.Peers.allPeers(), wantedPeers...)
router.Peers.RUnlock()
}
func implTestGossipTopology(t *testing.T) {
// Create some peers that will talk to each other
r1 := NewTestRouter("01:00:00:01:00:00")
r2 := NewTestRouter("02:00:00:02:00:00")
r3 := NewTestRouter("03:00:00:03:00:00")
// Check state when they have no connections
checkTopology(t, r1, r1.tp())
checkTopology(t, r2, r2.tp())
// Now try adding some connections
r1.AddTestChannelConnection(r2)
sendPendingGossip(r1, r2)
checkTopology(t, r1, r1.tp(r2), r2.tp())
checkTopology(t, r2, r1.tp(r2), r2.tp())
r2.AddTestChannelConnection(r1)
sendPendingGossip(r1, r2)
checkTopology(t, r1, r1.tp(r2), r2.tp(r1))
checkTopology(t, r2, r1.tp(r2), r2.tp(r1))
// Currently, the connection from 2 to 3 is one-way only
r2.AddTestChannelConnection(r3)
sendPendingGossip(r1, r2, r3)
checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp())
checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp())
// When r2 gossiped to r3, 1 was unreachable from r3 so it got removed from the
// list of peers, but remains referenced in the connection from 1 to 3.
checkTopology(t, r3, r2.tp(r1, r3), r3.tp())
// Add a connection from 3 to 1 and now r1 is reachable.
r3.AddTestChannelConnection(r1)
sendPendingGossip(r1, r2, r3)
checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r1))
checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r1))
checkTopology(t, r3, r1.tp(), r2.tp(r1, r3), r3.tp(r1))
r1.AddTestChannelConnection(r3)
sendPendingGossip(r1, r2, r3)
checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
// Drop the connection from 2 to 3
r2.DeleteTestChannelConnection(r3)
sendPendingGossip(r1, r2, r3)
checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1))
checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
// Drop the connection from 1 to 3
r1.DeleteTestChannelConnection(r3)
sendPendingGossip(r1, r2, r3)
checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1))
checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1))
checkTopology(t, r2, r1.tp(r2), r2.tp(r1))
// r3 still thinks r1 has a connection to it
checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
// On a timer, r3 will gossip to r1
r3.SendAllGossip()
sendPendingGossip(r1, r2, r3)
checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1))
}
func TestGossipSurrogate(t *testing.T) {
// create the topology r1 <-> r2 <-> r3
r1 := NewTestRouter("01:00:00:01:00:00")
r2 := NewTestRouter("02:00:00:02:00:00")
r3 := NewTestRouter("03:00:00:03:00:00")
r1.AddTestChannelConnection(r2)
r2.AddTestChannelConnection(r1)
r3.AddTestChannelConnection(r2)
r2.AddTestChannelConnection(r3)
sendPendingGossip(r1, r2, r3)
checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
checkTopology(t, r3, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
// create a gossiper at either end, but not the middle
g1 := newTestGossiper()
g3 := newTestGossiper()
s1 := r1.NewGossip("Test", g1)
s3 := r3.NewGossip("Test", g3)
// broadcast a message from each end, check it reaches the other
broadcast(s1, 1)
broadcast(s3, 2)
sendPendingGossip(r1, r2, r3)
g1.checkHas(t, 2)
g3.checkHas(t, 1)
// check that each end gets their message back through periodic
// gossip
r1.SendAllGossip()
r3.SendAllGossip()
sendPendingGossip(r1, r2, r3)
g1.checkHas(t, 1, 2)
g3.checkHas(t, 1, 2)
}
type testGossiper struct {
sync.RWMutex
state map[byte]struct{}
}
func newTestGossiper() *testGossiper {
return &testGossiper{state: make(map[byte]struct{})}
}
func (g *testGossiper) OnGossipUnicast(sender PeerName, msg []byte) error {
return nil
}
func (g *testGossiper) OnGossipBroadcast(_ PeerName, update []byte) (GossipData, error) {
g.Lock()
defer g.Unlock()
for _, v := range update {
g.state[v] = void
}
return NewSurrogateGossipData(update), nil
}
func (g *testGossiper) Gossip() GossipData {
g.RLock()
defer g.RUnlock()
state := make([]byte, len(g.state))
for v := range g.state {
state = append(state, v)
}
return NewSurrogateGossipData(state)
}
func (g *testGossiper) OnGossip(update []byte) (GossipData, error) {
g.Lock()
defer g.Unlock()
var delta []byte
for _, v := range update {
if _, found := g.state[v]; !found {
delta = append(delta, v)
g.state[v] = void
}
}
if len(delta) > 0 {
return NewSurrogateGossipData(delta), nil
}
return nil, nil
}
func (g *testGossiper) checkHas(t *testing.T, vs ...byte) {
g.RLock()
defer g.RUnlock()
for _, v := range vs {
if _, found := g.state[v]; !found {
require.FailNow(t, fmt.Sprintf("%d is missing", v))
}
}
}
func broadcast(s Gossip, v byte) {
s.GossipBroadcast(NewSurrogateGossipData([]byte{v}))
}
-261
View File
@@ -1,261 +0,0 @@
package mesh
import (
"fmt"
"net"
"sync"
"time"
)
type LocalPeer struct {
sync.RWMutex
*Peer
router *Router
actionChan chan<- LocalPeerAction
}
type LocalPeerAction func()
func NewLocalPeer(name PeerName, nickName string, router *Router) *LocalPeer {
actionChan := make(chan LocalPeerAction, ChannelSize)
peer := &LocalPeer{
Peer: NewPeer(name, nickName, randomPeerUID(), 0, randomPeerShortID()),
router: router,
actionChan: actionChan,
}
go peer.actorLoop(actionChan)
return peer
}
func (peer *LocalPeer) Connections() ConnectionSet {
connections := make(ConnectionSet)
peer.RLock()
defer peer.RUnlock()
for _, conn := range peer.connections {
connections[conn] = void
}
return connections
}
func (peer *LocalPeer) ConnectionTo(name PeerName) (Connection, bool) {
peer.RLock()
defer peer.RUnlock()
conn, found := peer.connections[name]
return conn, found // yes, you really can't inline that. FFS.
}
func (peer *LocalPeer) ConnectionsTo(names []PeerName) []Connection {
conns := make([]Connection, 0, len(names))
peer.RLock()
defer peer.RUnlock()
for _, name := range names {
conn, found := peer.connections[name]
// Again, !found could just be due to a race.
if found {
conns = append(conns, conn)
}
}
return conns
}
func (peer *LocalPeer) CreateConnection(peerAddr string, acceptNewPeer bool) error {
if err := peer.checkConnectionLimit(); err != nil {
return err
}
tcpAddr, err := net.ResolveTCPAddr("tcp4", peerAddr)
if err != nil {
return err
}
tcpConn, err := net.DialTCP("tcp4", nil, tcpAddr)
if err != nil {
return err
}
connRemote := NewRemoteConnection(peer.Peer, nil, tcpConn.RemoteAddr().String(), true, false)
StartLocalConnection(connRemote, tcpConn, peer.router, acceptNewPeer)
return nil
}
// ACTOR client API
// Sync.
func (peer *LocalPeer) AddConnection(conn *LocalConnection) error {
resultChan := make(chan error)
peer.actionChan <- func() {
resultChan <- peer.handleAddConnection(conn)
}
return <-resultChan
}
// Async.
func (peer *LocalPeer) ConnectionEstablished(conn *LocalConnection) {
peer.actionChan <- func() {
peer.handleConnectionEstablished(conn)
}
}
// Sync.
func (peer *LocalPeer) DeleteConnection(conn *LocalConnection) {
resultChan := make(chan interface{})
peer.actionChan <- func() {
peer.handleDeleteConnection(conn)
resultChan <- nil
}
<-resultChan
}
// ACTOR server
func (peer *LocalPeer) actorLoop(actionChan <-chan LocalPeerAction) {
gossipTimer := time.Tick(GossipInterval)
for {
select {
case action := <-actionChan:
action()
case <-gossipTimer:
peer.router.SendAllGossip()
}
}
}
func (peer *LocalPeer) handleAddConnection(conn Connection) error {
if peer.Peer != conn.Local() {
log.Fatal("Attempt made to add connection to peer where peer is not the source of connection")
}
if conn.Remote() == nil {
log.Fatal("Attempt made to add connection to peer with unknown remote peer")
}
toName := conn.Remote().Name
dupErr := fmt.Errorf("Multiple connections to %s added to %s", conn.Remote(), peer.String())
// deliberately non symmetrical
if dupConn, found := peer.connections[toName]; found {
if dupConn == conn {
return nil
}
switch conn.BreakTie(dupConn) {
case TieBreakWon:
dupConn.Shutdown(dupErr)
peer.handleDeleteConnection(dupConn)
case TieBreakLost:
return dupErr
case TieBreakTied:
// oh good grief. Sod it, just kill both of them.
dupConn.Shutdown(dupErr)
peer.handleDeleteConnection(dupConn)
return dupErr
}
}
if err := peer.checkConnectionLimit(); err != nil {
return err
}
_, isConnectedPeer := peer.router.Routes.Unicast(toName)
peer.addConnection(conn)
if isConnectedPeer {
conn.Log("connection added")
} else {
conn.Log("connection added (new peer)")
peer.router.SendAllGossipDown(conn)
}
peer.router.Routes.Recalculate()
peer.broadcastPeerUpdate(conn.Remote())
return nil
}
func (peer *LocalPeer) handleConnectionEstablished(conn Connection) {
if peer.Peer != conn.Local() {
log.Fatal("Peer informed of active connection where peer is not the source of connection")
}
if dupConn, found := peer.connections[conn.Remote().Name]; !found || conn != dupConn {
conn.Shutdown(fmt.Errorf("Cannot set unknown connection active"))
return
}
peer.connectionEstablished(conn)
conn.Log("connection fully established")
peer.router.Routes.Recalculate()
peer.broadcastPeerUpdate()
}
func (peer *LocalPeer) handleDeleteConnection(conn Connection) {
if peer.Peer != conn.Local() {
log.Fatal("Attempt made to delete connection from peer where peer is not the source of connection")
}
if conn.Remote() == nil {
log.Fatal("Attempt made to delete connection to peer with unknown remote peer")
}
toName := conn.Remote().Name
if connFound, found := peer.connections[toName]; !found || connFound != conn {
return
}
peer.deleteConnection(conn)
conn.Log("connection deleted")
// Must do garbage collection first to ensure we don't send out an
// update with unreachable peers (can cause looping)
peer.router.Peers.GarbageCollect()
peer.router.Routes.Recalculate()
peer.broadcastPeerUpdate()
}
// helpers
func (peer *LocalPeer) broadcastPeerUpdate(peers ...*Peer) {
// Some tests run without a router. This should be fixed so
// that the relevant part of Router can be easily run in the
// context of a test, but that will involve significant
// reworking of tests.
if peer.router != nil {
peer.router.BroadcastTopologyUpdate(append(peers, peer.Peer))
}
}
func (peer *LocalPeer) checkConnectionLimit() error {
limit := peer.router.ConnLimit
if 0 != limit && peer.connectionCount() >= limit {
return fmt.Errorf("Connection limit reached (%v)", limit)
}
return nil
}
func (peer *LocalPeer) addConnection(conn Connection) {
peer.Lock()
defer peer.Unlock()
peer.connections[conn.Remote().Name] = conn
peer.Version++
}
func (peer *LocalPeer) deleteConnection(conn Connection) {
peer.Lock()
defer peer.Unlock()
delete(peer.connections, conn.Remote().Name)
peer.Version++
}
func (peer *LocalPeer) connectionEstablished(conn Connection) {
peer.Lock()
defer peer.Unlock()
peer.Version++
}
func (peer *LocalPeer) connectionCount() int {
peer.RLock()
defer peer.RUnlock()
return len(peer.connections)
}
func (peer *LocalPeer) setShortID(shortID PeerShortID) {
peer.Lock()
defer peer.Unlock()
peer.ShortID = shortID
peer.Version++
}
func (peer *LocalPeer) setVersionBeyond(version uint64) bool {
peer.Lock()
defer peer.Unlock()
if version >= peer.Version {
peer.Version = version + 1
return true
}
return false
}
-115
View File
@@ -1,115 +0,0 @@
// No mocks are tested by this file.
//
// It supplies some mock implementations to other unit tests, and is
// named "...test.go" so it is only compiled under `go test`.
package mesh
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
// Add to peers a connection from peers.ourself to p
func (peers *Peers) AddTestConnection(p *Peer) {
summary := p.PeerSummary
summary.Version = 0
toPeer := NewPeerFromSummary(summary)
peers.FetchWithDefault(toPeer) // Has side-effect of incrementing refcount
conn := newMockConnection(peers.ourself.Peer, toPeer)
peers.ourself.addConnection(conn)
peers.ourself.connectionEstablished(conn)
}
// Add to peers a connection from p1 to p2
func (peers *Peers) AddTestRemoteConnection(p1, p2 *Peer) {
fromPeer := NewPeerFrom(p1)
fromPeer = peers.FetchWithDefault(fromPeer)
toPeer := NewPeerFrom(p2)
toPeer = peers.FetchWithDefault(toPeer)
peers.ourself.addConnection(&RemoteConnection{fromPeer, toPeer, "", false, false})
}
func (peers *Peers) DeleteTestConnection(p *Peer) {
toName := p.Name
toPeer := peers.Fetch(toName)
peers.Dereference(toPeer)
conn, _ := peers.ourself.ConnectionTo(toName)
peers.ourself.deleteConnection(conn)
}
// mockConnection used in testing is very similar to a
// RemoteConnection, without the RemoteTCPAddr(). We are making it a
// separate type in order to distinguish what is created by the test
// from what is created by the real code.
func newMockConnection(from, to *Peer) Connection {
type mockConnection struct{ RemoteConnection }
return &mockConnection{RemoteConnection{from, to, "", false, false}}
}
func checkEqualConns(t *testing.T, ourName PeerName, got, wanted map[PeerName]Connection) {
checkConns := make(PeerNameSet)
for _, conn := range wanted {
checkConns[conn.Remote().Name] = void
}
for _, conn := range got {
remoteName := conn.Remote().Name
if _, found := checkConns[remoteName]; found {
delete(checkConns, remoteName)
} else {
require.FailNow(t, fmt.Sprintf("Unexpected connection from %s to %s", ourName, remoteName))
}
}
if len(checkConns) > 0 {
require.FailNow(t, fmt.Sprintf("Expected connections not found: from %s to %v", ourName, checkConns))
}
}
// Get all the peers from a Peers in a slice
func (peers *Peers) allPeers() []*Peer {
var res []*Peer
for _, peer := range peers.byName {
res = append(res, peer)
}
return res
}
func (peers *Peers) allPeersExcept(excludeName PeerName) []*Peer {
res := peers.allPeers()
for i, peer := range res {
if peer.Name == excludeName {
return append(res[:i], res[i+1:]...)
}
}
return res
}
// Check that the peers slice matches the wanted peers
func checkPeerArray(t *testing.T, peers []*Peer, wantedPeers ...*Peer) {
checkTopologyPeers(t, false, peers, wantedPeers...)
}
// Check that the peers slice matches the wanted peers and optionally
// all of their connections
func checkTopologyPeers(t *testing.T, checkConns bool, peers []*Peer, wantedPeers ...*Peer) {
check := make(map[PeerName]*Peer)
for _, peer := range wantedPeers {
check[peer.Name] = peer
}
for _, peer := range peers {
name := peer.Name
if wantedPeer, found := check[name]; found {
if checkConns {
checkEqualConns(t, name, peer.connections, wantedPeer.connections)
}
delete(check, name)
} else {
require.FailNow(t, fmt.Sprintf("Unexpected peer: %s", name))
}
}
if len(check) > 0 {
require.FailNow(t, fmt.Sprintf("Expected peers not found: %v", check))
}
}
-116
View File
@@ -1,116 +0,0 @@
package mesh
import (
"net"
)
type Overlay interface {
// Enhance a features map with overlay-related features
AddFeaturesTo(map[string]string)
// Prepare on overlay connection. The connection should remain
// passive until it has been Confirm()ed.
PrepareConnection(OverlayConnectionParams) (OverlayConnection, error)
// Obtain diagnostic information specific to the overlay
Diagnostics() interface{}
}
type OverlayConnectionParams struct {
RemotePeer *Peer
// The local address of the corresponding TCP connection. Used to
// derive the local IP address for sending. May differ for
// different overlay connections.
LocalAddr *net.TCPAddr
// The remote address of the corresponding TCP connection. Used to
// determine the address to send to, but only if the TCP
// connection is outbound. Otherwise the Overlay needs to discover
// it (e.g. from incoming datagrams).
RemoteAddr *net.TCPAddr
// Is the corresponding TCP connection outbound?
Outbound bool
// Unique identifier for this connection
ConnUID uint64
// Session key, if connection is encrypted; nil otherwise.
//
// NB: overlay connections must take care not to use nonces which
// may collide with those of the main connection. These nonces are
// 192 bits, with the top most bit unspecified, the next bit set
// to 1, followed by 126 zero bits, and a message sequence number
// in the lowest 64 bits.
SessionKey *[32]byte
// Function to send a control message to the counterpart
// overlay connection.
SendControlMessage func(tag byte, msg []byte) error
// Features passed at connection initiation
Features map[string]string
}
// All of the machinery to manage overlay connectivity to a particular
// peer
type OverlayConnection interface {
// Confirm that the connection is really wanted, and so the
// Overlay should begin heartbeats etc. to verify the operation of
// the overlay connection.
Confirm()
// A channel indicating that the overlay connection is
// established, i.e. its operation has been confirmed.
EstablishedChannel() <-chan struct{}
// A channel indicating an error from the overlay connection. The
// overlay connection is not expected to be operational after the
// first error, so the channel only needs to buffer a single
// error.
ErrorChannel() <-chan error
Stop()
// Handle a message from the peer. 'tag' exists for
// compatibility, and should always be
// ProtocolOverlayControlMessage for non-sleeve overlays.
ControlMessage(tag byte, msg []byte)
// User facing overlay name
DisplayName() string
}
type NullOverlay struct{}
func (NullOverlay) AddFeaturesTo(map[string]string) {
}
func (NullOverlay) PrepareConnection(OverlayConnectionParams) (OverlayConnection, error) {
return NullOverlay{}, nil
}
func (NullOverlay) Diagnostics() interface{} {
return nil
}
func (NullOverlay) Confirm() {
}
func (NullOverlay) EstablishedChannel() <-chan struct{} {
return nil
}
func (NullOverlay) ErrorChannel() <-chan error {
return nil
}
func (NullOverlay) Stop() {
}
func (NullOverlay) ControlMessage(byte, []byte) {
}
func (NullOverlay) DisplayName() string {
return "null"
}
-173
View File
@@ -1,173 +0,0 @@
package mesh
import (
"crypto/rand"
"encoding/binary"
"fmt"
"sort"
"strconv"
)
func randBytes(n int) []byte {
buf := make([]byte, n)
_, err := rand.Read(buf)
checkFatal(err)
return buf
}
func randUint64() (r uint64) {
return binary.LittleEndian.Uint64(randBytes(8))
}
func randUint16() (r uint16) {
return binary.LittleEndian.Uint16(randBytes(2))
}
type PeerUID uint64
func randomPeerUID() PeerUID {
return PeerUID(randUint64())
}
func ParsePeerUID(s string) (PeerUID, error) {
uid, err := strconv.ParseUint(s, 10, 64)
return PeerUID(uid), err
}
// Short IDs exist for the sake of fast datapath. They are 12 bits,
// randomly assigned, but we detect and recover from collisions. This
// does limit us to 4096 peers, but that should be sufficient for a
// while.
type PeerShortID uint16
const PeerShortIDBits = 12
func randomPeerShortID() PeerShortID {
return PeerShortID(randUint16() & (1<<PeerShortIDBits - 1))
}
type PeerSummary struct {
NameByte []byte
NickName string
UID PeerUID
Version uint64
ShortID PeerShortID
HasShortID bool
}
type Peer struct {
Name PeerName
PeerSummary
localRefCount uint64 // maintained by Peers
connections map[PeerName]Connection
}
type ListOfPeers []*Peer
func (lop ListOfPeers) Len() int {
return len(lop)
}
func (lop ListOfPeers) Swap(i, j int) {
lop[i], lop[j] = lop[j], lop[i]
}
func (lop ListOfPeers) Less(i, j int) bool {
return lop[i].Name < lop[j].Name
}
type ConnectionSet map[Connection]struct{}
func NewPeerFromSummary(summary PeerSummary) *Peer {
return &Peer{
Name: PeerNameFromBin(summary.NameByte),
PeerSummary: summary,
connections: make(map[PeerName]Connection),
}
}
func NewPeer(name PeerName, nickName string, uid PeerUID, version uint64, shortID PeerShortID) *Peer {
return NewPeerFromSummary(PeerSummary{
NameByte: name.Bin(),
NickName: nickName,
UID: uid,
Version: version,
ShortID: shortID,
HasShortID: true,
})
}
func NewPeerFrom(peer *Peer) *Peer {
return NewPeerFromSummary(peer.PeerSummary)
}
func (peer *Peer) String() string {
return fmt.Sprint(peer.Name, "(", peer.NickName, ")")
}
// Calculate the routing table from this peer to all peers reachable
// from it, returning a "next hop" map of PeerNameX -> PeerNameY,
// which says "in order to send a message to X, the peer should send
// the message to its neighbour Y".
//
// Because currently we do not have weightings on the connections
// between peers, there is no need to use a minimum spanning tree
// algorithm. Instead we employ the simpler and cheaper breadth-first
// widening. The computation is deterministic, which ensures that when
// it is performed on the same data by different peers, they get the
// same result. This is important since otherwise we risk message loss
// or routing cycles.
//
// When the 'establishedAndSymmetric' flag is set, only connections
// that are marked as 'established' and are symmetric (i.e. where both
// sides indicate they have a connection to the other) are considered.
//
// When a non-nil stopAt peer is supplied, the widening stops when it
// reaches that peer. The boolean return indicates whether that has
// happened.
//
// NB: This function should generally be invoked while holding a read
// lock on Peers and LocalPeer.
func (peer *Peer) Routes(stopAt *Peer, establishedAndSymmetric bool) (bool, map[PeerName]PeerName) {
routes := make(unicastRoutes)
routes[peer.Name] = UnknownPeerName
nextWorklist := []*Peer{peer}
for len(nextWorklist) > 0 {
worklist := nextWorklist
sort.Sort(ListOfPeers(worklist))
nextWorklist = []*Peer{}
for _, curPeer := range worklist {
if curPeer == stopAt {
return true, routes
}
curPeer.ForEachConnectedPeer(establishedAndSymmetric, routes,
func(remotePeer *Peer) {
nextWorklist = append(nextWorklist, remotePeer)
remoteName := remotePeer.Name
// We now know how to get to remoteName: the same
// way we get to curPeer. Except, if curPeer is
// the starting peer in which case we know we can
// reach remoteName directly.
if curPeer == peer {
routes[remoteName] = remoteName
} else {
routes[remoteName] = routes[curPeer.Name]
}
})
}
}
return false, routes
}
func (peer *Peer) ForEachConnectedPeer(establishedAndSymmetric bool, exclude map[PeerName]PeerName, f func(*Peer)) {
for remoteName, conn := range peer.connections {
if establishedAndSymmetric && !conn.Established() {
continue
}
if _, found := exclude[remoteName]; found {
continue
}
remotePeer := conn.Remote()
if remoteConn, found := remotePeer.connections[peer.Name]; !establishedAndSymmetric || (found && remoteConn.Established()) {
f(remotePeer)
}
}
}
-46
View File
@@ -1,46 +0,0 @@
// +build peer_name_hash
// Let peer names be sha256 hashes...of anything (as long as it's
// unique).
package mesh
import (
"crypto/sha256"
"encoding/hex"
)
type PeerName string
const (
PeerNameFlavour = "hash"
NameSize = sha256.Size >> 1
UnknownPeerName = PeerName("")
)
func PeerNameFromUserInput(userInput string) (PeerName, error) {
// fixed-length identity
nameByteAry := sha256.Sum256([]byte(userInput))
return PeerNameFromBin(nameByteAry[:NameSize]), nil
}
func PeerNameFromString(nameStr string) (PeerName, error) {
if _, err := hex.DecodeString(nameStr); err != nil {
return UnknownPeerName, err
}
return PeerName(nameStr), nil
}
func PeerNameFromBin(nameByte []byte) PeerName {
return PeerName(hex.EncodeToString(nameByte))
}
func (name PeerName) Bin() []byte {
res, err := hex.DecodeString(string(name))
checkFatal(err)
return res
}
func (name PeerName) String() string {
return string(name)
}
-75
View File
@@ -1,75 +0,0 @@
// The !peer_name_alternative effectively makes this the default,
// i.e. to choose an alternative, run "go build -tags
// 'peer_name_alternative peer_name_hash'"
// +build peer_name_mac !peer_name_alternative
// Let peer names be MACs...
//
// MACs need to be unique across our network, or bad things will
// happen anyway. So they make pretty good candidates for peer
// names. And doing so is pretty efficient both computationally and
// network overhead wise.
//
// Note that we do not mandate *what* MAC should be used as the peer
// name. In particular it doesn't actually have to be the MAC of, say,
// the network interface the peer is sniffing on.
package mesh
import (
"net"
)
// PeerName is used as a map key. Since net.HardwareAddr isn't
// suitable for that - it's a slice, and slices can't be map keys - we
// convert that to/from uint64.
type PeerName uint64
const (
PeerNameFlavour = "mac"
NameSize = 6
UnknownPeerName = PeerName(0)
)
func PeerNameFromUserInput(userInput string) (PeerName, error) {
res, err := PeerNameFromString(userInput)
return res, err
}
func PeerNameFromString(nameStr string) (PeerName, error) {
mac, err := net.ParseMAC(nameStr)
if err != nil {
return UnknownPeerName, err
}
return PeerName(macint(mac)), nil
}
func PeerNameFromBin(nameByte []byte) PeerName {
return PeerName(macint(net.HardwareAddr(nameByte)))
}
func (name PeerName) Bin() []byte {
return intmac(uint64(name))
}
func (name PeerName) String() string {
return intmac(uint64(name)).String()
}
func macint(mac net.HardwareAddr) (r uint64) {
for _, b := range mac {
r <<= 8
r |= uint64(b)
}
return
}
func intmac(key uint64) (r net.HardwareAddr) {
r = make([]byte, 6)
for i := 5; i >= 0; i-- {
r[i] = byte(key)
key >>= 8
}
return
}
-538
View File
@@ -1,538 +0,0 @@
package mesh
import (
"bytes"
"encoding/gob"
"fmt"
"io"
"math/rand"
"sync"
)
var void = struct{}{}
type Peers struct {
sync.RWMutex
ourself *LocalPeer
byName map[PeerName]*Peer
byShortID map[PeerShortID]ShortIDPeers
onGC []func(*Peer)
// Called when the mapping from short ids to peers changes
onInvalidateShortIDs []func()
}
type ShortIDPeers struct {
// If we know about a single peer with the short id, this is
// that peer. If there is a collision, this is the peer with
// the lowest Name.
peer *Peer
// In case of a collision, this holds the other peers.
others []*Peer
}
type UnknownPeerError struct {
Name PeerName
}
func (upe UnknownPeerError) Error() string {
return fmt.Sprint("Reference to unknown peer ", upe.Name)
}
type PeerNameSet map[PeerName]struct{}
type ConnectionSummary struct {
NameByte []byte
RemoteTCPAddr string
Outbound bool
Established bool
}
// Pending notifications due to changes to Peers that need to be sent
// out once the Peers is unlocked.
type PeersPendingNotifications struct {
// Peers that have been GCed
removed []*Peer
// The mapping from shorts ids to peers changed
invalidateShortIDs bool
// The local short ID needs reassigning due to a collision
reassignLocalShortID bool
// The local peer was modified
localPeerModified bool
}
func NewPeers(ourself *LocalPeer) *Peers {
peers := &Peers{
ourself: ourself,
byName: make(map[PeerName]*Peer),
byShortID: make(map[PeerShortID]ShortIDPeers),
}
peers.FetchWithDefault(ourself.Peer)
return peers
}
func (peers *Peers) OnGC(callback func(*Peer)) {
peers.Lock()
defer peers.Unlock()
// Although the array underlying peers.onGC might be accessed
// without holding the lock in unlockAndNotify, we don't
// support removing callbacks, so a simple append here is
// safe.
peers.onGC = append(peers.onGC, callback)
}
func (peers *Peers) OnInvalidateShortIDs(callback func()) {
peers.Lock()
defer peers.Unlock()
// Safe, as in OnGC
peers.onInvalidateShortIDs = append(peers.onInvalidateShortIDs, callback)
}
func (peers *Peers) unlockAndNotify(pending *PeersPendingNotifications) {
broadcastLocalPeer := (pending.reassignLocalShortID && peers.reassignLocalShortID(pending)) ||
pending.localPeerModified
onGC := peers.onGC
onInvalidateShortIDs := peers.onInvalidateShortIDs
peers.Unlock()
if pending.removed != nil {
for _, callback := range onGC {
for _, peer := range pending.removed {
callback(peer)
}
}
}
if pending.invalidateShortIDs {
for _, callback := range onInvalidateShortIDs {
callback()
}
}
if broadcastLocalPeer {
peers.ourself.broadcastPeerUpdate()
}
}
func (peers *Peers) addByShortID(peer *Peer, pending *PeersPendingNotifications) {
if !peer.HasShortID {
return
}
entry, ok := peers.byShortID[peer.ShortID]
if !ok {
entry = ShortIDPeers{peer: peer}
} else if entry.peer == nil {
// This short ID is free, but was used in the past.
// Because we are reusing it, it's an invalidation
// event.
entry.peer = peer
pending.invalidateShortIDs = true
} else if peer.Name < entry.peer.Name {
// Short ID collision, this peer becomes the principal
// peer for the short ID, bumping the previous one
// into others.
if entry.peer == peers.ourself.Peer {
// The bumped peer is peers.ourself, so we
// need to look for a new short id
pending.reassignLocalShortID = true
}
entry.others = append(entry.others, entry.peer)
entry.peer = peer
pending.invalidateShortIDs = true
} else {
// Short ID collision, this peer is secondary
entry.others = append(entry.others, peer)
}
peers.byShortID[peer.ShortID] = entry
}
func (peers *Peers) deleteByShortID(peer *Peer, pending *PeersPendingNotifications) {
if !peer.HasShortID {
return
}
entry := peers.byShortID[peer.ShortID]
var otherIndex int
if peer != entry.peer {
// peer is secondary, find its index in others
otherIndex = -1
for i, other := range entry.others {
if peer == other {
otherIndex = i
break
}
}
if otherIndex < 0 {
return
}
} else if len(entry.others) != 0 {
// need to find the peer with the lowest name to
// become the new principal one
otherIndex = 0
minName := entry.others[0].Name
for i := 1; i < len(entry.others); i++ {
otherName := entry.others[i].Name
if otherName < minName {
minName = otherName
otherIndex = i
}
}
entry.peer = entry.others[otherIndex]
pending.invalidateShortIDs = true
} else {
// This is the last peer with the short id. We clear
// the entry, don't delete it, in order to detect when
// it gets re-used.
peers.byShortID[peer.ShortID] = ShortIDPeers{}
return
}
entry.others[otherIndex] = entry.others[len(entry.others)-1]
entry.others = entry.others[:len(entry.others)-1]
peers.byShortID[peer.ShortID] = entry
}
func (peers *Peers) reassignLocalShortID(pending *PeersPendingNotifications) bool {
newShortID, ok := peers.chooseShortID()
if ok {
peers.setLocalShortID(newShortID, pending)
return true
}
// Otherwise we'll try again later on in garbageColleect
return false
}
func (peers *Peers) setLocalShortID(newShortID PeerShortID, pending *PeersPendingNotifications) {
peers.deleteByShortID(peers.ourself.Peer, pending)
peers.ourself.setShortID(newShortID)
peers.addByShortID(peers.ourself.Peer, pending)
}
// Choose an available short id at random
func (peers *Peers) chooseShortID() (PeerShortID, bool) {
rng := rand.New(rand.NewSource(int64(randUint64())))
// First, just try picking some short ids at random, and
// seeing if they are available:
for i := 0; i < 10; i++ {
shortID := PeerShortID(rng.Intn(1 << PeerShortIDBits))
if peers.byShortID[shortID].peer == nil {
return shortID, true
}
}
// Looks like most short ids are used. So count the number of
// unused ones, and pick one at random.
available := int(1 << PeerShortIDBits)
for _, entry := range peers.byShortID {
if entry.peer != nil {
available--
}
}
if available == 0 {
// All short ids are used.
return 0, false
}
n := rng.Intn(available)
var i PeerShortID
for {
if peers.byShortID[i].peer == nil {
if n == 0 {
return PeerShortID(i), true
}
n--
}
i++
}
}
func (peers *Peers) FetchWithDefault(peer *Peer) *Peer {
peers.Lock()
var pending PeersPendingNotifications
defer peers.unlockAndNotify(&pending)
if existingPeer, found := peers.byName[peer.Name]; found {
existingPeer.localRefCount++
return existingPeer
}
peers.byName[peer.Name] = peer
peers.addByShortID(peer, &pending)
peer.localRefCount++
return peer
}
func (peers *Peers) Fetch(name PeerName) *Peer {
peers.RLock()
defer peers.RUnlock()
return peers.byName[name]
}
func (peers *Peers) FetchAndAddRef(name PeerName) *Peer {
peers.Lock()
defer peers.Unlock()
peer := peers.byName[name]
if peer != nil {
peer.localRefCount++
}
return peer
}
func (peers *Peers) FetchByShortID(shortID PeerShortID) *Peer {
peers.RLock()
defer peers.RUnlock()
return peers.byShortID[shortID].peer
}
func (peers *Peers) Dereference(peer *Peer) {
peers.Lock()
defer peers.Unlock()
peer.localRefCount--
}
func (peers *Peers) ForEach(fun func(*Peer)) {
peers.RLock()
defer peers.RUnlock()
for _, peer := range peers.byName {
fun(peer)
}
}
// Merge an incoming update with our own topology.
//
// We add peers hitherto unknown to us, and update peers for which the
// update contains a more recent version than known to us. The return
// value is a) a representation of the received update, and b) an
// "improved" update containing just these new/updated elements.
func (peers *Peers) ApplyUpdate(update []byte) (PeerNameSet, PeerNameSet, error) {
peers.Lock()
var pending PeersPendingNotifications
defer peers.unlockAndNotify(&pending)
newPeers, decodedUpdate, decodedConns, err := peers.decodeUpdate(update)
if err != nil {
return nil, nil, err
}
// By this point, we know the update doesn't refer to any peers we
// have no knowledge of. We can now apply the update. Start by
// adding in any new peers.
for name, newPeer := range newPeers {
peers.byName[name] = newPeer
peers.addByShortID(newPeer, &pending)
}
// Now apply the updates
newUpdate := peers.applyUpdate(decodedUpdate, decodedConns, &pending)
peers.garbageCollect(&pending)
for _, peerRemoved := range pending.removed {
delete(newUpdate, peerRemoved.Name)
}
updateNames := make(PeerNameSet)
for _, peer := range decodedUpdate {
updateNames[peer.Name] = void
}
return updateNames, newUpdate, nil
}
func (peers *Peers) Names() PeerNameSet {
peers.RLock()
defer peers.RUnlock()
names := make(PeerNameSet)
for name := range peers.byName {
names[name] = void
}
return names
}
func (peers *Peers) EncodePeers(names PeerNameSet) []byte {
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
peers.RLock()
defer peers.RUnlock()
for name := range names {
if peer, found := peers.byName[name]; found {
if peer == peers.ourself.Peer {
peers.ourself.Encode(enc)
} else {
peer.Encode(enc)
}
}
}
return buf.Bytes()
}
func (peers *Peers) GarbageCollect() {
peers.Lock()
var pending PeersPendingNotifications
defer peers.unlockAndNotify(&pending)
peers.garbageCollect(&pending)
}
func (peers *Peers) garbageCollect(pending *PeersPendingNotifications) {
peers.ourself.RLock()
_, reached := peers.ourself.Routes(nil, false)
peers.ourself.RUnlock()
for name, peer := range peers.byName {
if _, found := reached[peer.Name]; !found && peer.localRefCount == 0 {
delete(peers.byName, name)
peers.deleteByShortID(peer, pending)
pending.removed = append(pending.removed, peer)
}
}
if peers.byShortID[peers.ourself.ShortID].peer != peers.ourself.Peer {
// The local peer doesn't own its short id. Garbage
// collection might have freed some up, so try to
// reassign.
pending.reassignLocalShortID = true
}
}
func (peers *Peers) decodeUpdate(update []byte) (newPeers map[PeerName]*Peer, decodedUpdate []*Peer, decodedConns [][]ConnectionSummary, err error) {
newPeers = make(map[PeerName]*Peer)
decodedUpdate = []*Peer{}
decodedConns = [][]ConnectionSummary{}
decoder := gob.NewDecoder(bytes.NewReader(update))
for {
peerSummary, connSummaries, decErr := decodePeer(decoder)
if decErr == io.EOF {
break
} else if decErr != nil {
err = decErr
return
}
newPeer := NewPeerFromSummary(peerSummary)
decodedUpdate = append(decodedUpdate, newPeer)
decodedConns = append(decodedConns, connSummaries)
if _, found := peers.byName[newPeer.Name]; !found {
newPeers[newPeer.Name] = newPeer
}
}
for _, connSummaries := range decodedConns {
for _, connSummary := range connSummaries {
remoteName := PeerNameFromBin(connSummary.NameByte)
if _, found := newPeers[remoteName]; found {
continue
}
if _, found := peers.byName[remoteName]; found {
continue
}
// Update refers to a peer which we have no knowledge
// of. Thus we can't apply the update. Abort.
err = UnknownPeerError{remoteName}
return
}
}
return
}
func (peers *Peers) applyUpdate(decodedUpdate []*Peer, decodedConns [][]ConnectionSummary, pending *PeersPendingNotifications) PeerNameSet {
newUpdate := make(PeerNameSet)
for idx, newPeer := range decodedUpdate {
connSummaries := decodedConns[idx]
name := newPeer.Name
// guaranteed to find peer in the peers.byName
switch peer := peers.byName[name]; peer {
case peers.ourself.Peer:
if newPeer.UID != peer.UID {
// The update contains information about an old
// incarnation of ourselves. We increase our version
// number beyond that which we received, so our
// information supersedes the old one when it is
// received by other peers.
pending.localPeerModified = peers.ourself.setVersionBeyond(newPeer.Version)
}
case newPeer:
peer.connections = makeConnsMap(peer, connSummaries, peers.byName)
newUpdate[name] = void
default: // existing peer
if newPeer.Version < peer.Version ||
(newPeer.Version == peer.Version && newPeer.UID <= peer.UID) {
continue
}
peer.Version = newPeer.Version
peer.UID = newPeer.UID
peer.connections = makeConnsMap(peer, connSummaries, peers.byName)
if newPeer.ShortID != peer.ShortID {
peers.deleteByShortID(peer, pending)
peer.ShortID = newPeer.ShortID
peers.addByShortID(peer, pending)
}
newUpdate[name] = void
}
}
return newUpdate
}
func (peer *Peer) Encode(enc *gob.Encoder) {
checkFatal(enc.Encode(peer.PeerSummary))
connSummaries := []ConnectionSummary{}
for _, conn := range peer.connections {
connSummaries = append(connSummaries, ConnectionSummary{
conn.Remote().NameByte,
conn.RemoteTCPAddr(),
conn.Outbound(),
conn.Established(),
})
}
checkFatal(enc.Encode(connSummaries))
}
func (peer *LocalPeer) Encode(enc *gob.Encoder) {
peer.RLock()
defer peer.RUnlock()
peer.Peer.Encode(enc)
}
func decodePeer(dec *gob.Decoder) (peerSummary PeerSummary, connSummaries []ConnectionSummary, err error) {
if err = dec.Decode(&peerSummary); err != nil {
return
}
if err = dec.Decode(&connSummaries); err != nil {
return
}
return
}
func makeConnsMap(peer *Peer, connSummaries []ConnectionSummary, byName map[PeerName]*Peer) map[PeerName]Connection {
conns := make(map[PeerName]Connection)
for _, connSummary := range connSummaries {
name := PeerNameFromBin(connSummary.NameByte)
remotePeer := byName[name]
conn := NewRemoteConnection(peer, remotePeer, connSummary.RemoteTCPAddr, connSummary.Outbound, connSummary.Established)
conns[name] = conn
}
return conns
}
-376
View File
@@ -1,376 +0,0 @@
package mesh
import (
"fmt"
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// TODO we should also test:
//
// - applying an incremental update, including the case where that
// leads to an UnknownPeerError
//
// - the "improved update" calculation
//
// - non-gc of peers that are only referenced locally
func newNode(name PeerName) (*Peer, *Peers) {
peer := NewLocalPeer(name, "", nil)
peers := NewPeers(peer)
return peer.Peer, peers
}
// Check that ApplyUpdate copies the whole topology from peers
func checkApplyUpdate(t *testing.T, peers *Peers) {
dummyName, _ := PeerNameFromString("99:00:00:01:00:00")
// We need a new node outside of the network, with a connection
// into it.
_, testBedPeers := newNode(dummyName)
testBedPeers.AddTestConnection(peers.ourself.Peer)
testBedPeers.ApplyUpdate(peers.EncodePeers(peers.Names()))
checkTopologyPeers(t, true, testBedPeers.allPeersExcept(dummyName), peers.allPeers()...)
}
func TestPeersEncoding(t *testing.T) {
const numNodes = 20
const numIters = 1000
var peer [numNodes]*Peer
var ps [numNodes]*Peers
for i := 0; i < numNodes; i++ {
name, _ := PeerNameFromString(fmt.Sprintf("%02d:00:00:01:00:00", i))
peer[i], ps[i] = newNode(name)
}
var conns []struct{ from, to int }
for i := 0; i < numIters; i++ {
oper := rand.Intn(2)
switch oper {
case 0:
from, to := rand.Intn(numNodes), rand.Intn(numNodes)
if from != to {
if _, found := peer[from].connections[peer[to].Name]; !found {
ps[from].AddTestConnection(peer[to])
conns = append(conns, struct{ from, to int }{from, to})
checkApplyUpdate(t, ps[from])
}
}
case 1:
if len(conns) > 0 {
n := rand.Intn(len(conns))
c := conns[n]
ps[c.from].DeleteTestConnection(peer[c.to])
ps[c.from].GarbageCollect()
checkApplyUpdate(t, ps[c.from])
conns = append(conns[:n], conns[n+1:]...)
}
}
}
}
func garbageCollect(peers *Peers) []*Peer {
var removed []*Peer
peers.OnGC(func(peer *Peer) { removed = append(removed, peer) })
peers.GarbageCollect()
return removed
}
func TestPeersGarbageCollection(t *testing.T) {
const (
peer1NameString = "01:00:00:01:00:00"
peer2NameString = "02:00:00:02:00:00"
peer3NameString = "03:00:00:03:00:00"
)
var (
peer1Name, _ = PeerNameFromString(peer1NameString)
peer2Name, _ = PeerNameFromString(peer2NameString)
peer3Name, _ = PeerNameFromString(peer3NameString)
)
// Create some peers with some connections to each other
p1, ps1 := newNode(peer1Name)
p2, ps2 := newNode(peer2Name)
p3, ps3 := newNode(peer3Name)
ps1.AddTestConnection(p2)
ps2.AddTestRemoteConnection(p1, p2)
ps2.AddTestConnection(p1)
ps2.AddTestConnection(p3)
ps3.AddTestConnection(p1)
ps1.AddTestConnection(p3)
ps2.AddTestRemoteConnection(p1, p3)
ps2.AddTestRemoteConnection(p3, p1)
// Every peer is referenced, so nothing should be dropped
require.Empty(t, garbageCollect(ps1), "peers removed")
require.Empty(t, garbageCollect(ps2), "peers removed")
require.Empty(t, garbageCollect(ps3), "peers removed")
// Drop the connection from 2 to 3, and 3 isn't garbage-collected
// because 1 has a connection to 3
ps2.DeleteTestConnection(p3)
require.Empty(t, garbageCollect(ps2), "peers removed")
// Drop the connection from 1 to 3, and 3 will get removed by
// garbage-collection
ps1.DeleteTestConnection(p3)
checkPeerArray(t, garbageCollect(ps1), p3)
}
func TestShortIDCollisions(t *testing.T) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
_, peers := newNode(PeerName(1 << PeerShortIDBits))
// Make enough peers that short id collisions are
// overwhelmingly likely
ps := make([]*Peer, 1<<PeerShortIDBits)
for i := 0; i < 1<<PeerShortIDBits; i++ {
ps[i] = NewPeer(PeerName(i), "", PeerUID(i), 0,
PeerShortID(rng.Intn(1<<PeerShortIDBits)))
}
shuffle := func() {
for i := range ps {
j := rng.Intn(i + 1)
ps[i], ps[j] = ps[j], ps[i]
}
}
// Fill peers
shuffle()
var pending PeersPendingNotifications
for _, p := range ps {
peers.addByShortID(p, &pending)
}
// Check invariants
counts := make([]int, 1<<PeerShortIDBits)
saw := func(p *Peer) {
if p != peers.ourself.Peer {
counts[p.UID]++
}
}
for shortID, entry := range peers.byShortID {
if entry.peer == nil {
// no principal peer for this short id, so
// others must be empty
require.Empty(t, entry.others)
continue
}
require.Equal(t, shortID, entry.peer.ShortID)
saw(entry.peer)
for _, p := range entry.others {
saw(p)
require.Equal(t, shortID, p.ShortID)
// the principal peer should have the lowest name
require.True(t, p.Name > entry.peer.Name)
}
}
// Check that every peer was seen
for _, n := range counts {
require.Equal(t, 1, n)
}
// Delete all the peers
shuffle()
for _, p := range ps {
peers.deleteByShortID(p, &pending)
}
for _, entry := range peers.byShortID {
if entry.peer != peers.ourself.Peer {
require.Nil(t, entry.peer)
}
require.Empty(t, entry.others)
}
}
// Test the easy case of short id reassignment, when few short ids are taken
func TestShortIDReassignmentEasy(t *testing.T) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
_, peers := newNode(PeerName(0))
for i := 1; i <= 10; i++ {
peers.FetchWithDefault(NewPeer(PeerName(i), "", PeerUID(i), 0,
PeerShortID(rng.Intn(1<<PeerShortIDBits))))
}
checkShortIDReassignment(t, peers)
}
// Test the hard case of short id reassignment, when most short ids are taken
func TestShortIDReassignmentHard(t *testing.T) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
_, peers := newNode(PeerName(1 << PeerShortIDBits))
// Take all short ids
ps := make([]*Peer, 1<<PeerShortIDBits)
var pending PeersPendingNotifications
for i := 0; i < 1<<PeerShortIDBits; i++ {
ps[i] = NewPeer(PeerName(i), "", PeerUID(i), 0,
PeerShortID(i))
peers.addByShortID(ps[i], &pending)
}
// As all short ids are taken, an attempted reassigment won't
// do anything
oldShortID := peers.ourself.ShortID
require.False(t, peers.reassignLocalShortID(&pending))
require.Equal(t, oldShortID, peers.ourself.ShortID)
// Free up a few ids
for i := 0; i < 10; i++ {
x := rng.Intn(len(ps))
if ps[x] != nil {
peers.deleteByShortID(ps[x], &pending)
ps[x] = nil
}
}
checkShortIDReassignment(t, peers)
}
func checkShortIDReassignment(t *testing.T, peers *Peers) {
oldShortID := peers.ourself.ShortID
peers.reassignLocalShortID(&PeersPendingNotifications{})
require.NotEqual(t, oldShortID, peers.ourself.ShortID)
require.Equal(t, peers.ourself.Peer, peers.byShortID[peers.ourself.ShortID].peer)
}
func TestShortIDInvalidation(t *testing.T) {
_, peers := newNode(PeerName(1 << PeerShortIDBits))
// need to use a short id that is not the local peer's
shortID := peers.ourself.ShortID + 1
var pending PeersPendingNotifications
requireInvalidateShortIDs := func(expect bool) {
require.Equal(t, expect, pending.invalidateShortIDs)
pending.invalidateShortIDs = false
}
// The use of a fresh short id does not cause invalidation
a := NewPeer(PeerName(1), "", PeerUID(1), 0, shortID)
peers.addByShortID(a, &pending)
requireInvalidateShortIDs(false)
// An addition which does not change the mapping
b := NewPeer(PeerName(2), "", PeerUID(2), 0, shortID)
peers.addByShortID(b, &pending)
requireInvalidateShortIDs(false)
// An addition which does change the mapping
c := NewPeer(PeerName(0), "", PeerUID(0), 0, shortID)
peers.addByShortID(c, &pending)
requireInvalidateShortIDs(true)
// A deletion which does not change the mapping
peers.deleteByShortID(b, &pending)
requireInvalidateShortIDs(false)
// A deletion which does change the mapping
peers.deleteByShortID(c, &pending)
requireInvalidateShortIDs(true)
// Deleting the last peer with a short id does not cause invalidation
peers.deleteByShortID(a, &pending)
requireInvalidateShortIDs(false)
// .. but subsequent reuse of that short id does cause invalidation
peers.addByShortID(a, &pending)
requireInvalidateShortIDs(true)
}
func TestShortIDPropagation(t *testing.T) {
_, peers1 := newNode(PeerName(1))
_, peers2 := newNode(PeerName(2))
peers1.AddTestConnection(peers2.ourself.Peer)
peers1.ApplyUpdate(peers2.EncodePeers(peers2.Names()))
peers12 := peers1.Fetch(PeerName(2))
old := peers12.PeerSummary
require.True(t,
peers2.reassignLocalShortID(&PeersPendingNotifications{}))
peers1.ApplyUpdate(peers2.EncodePeers(peers2.Names()))
require.NotEqual(t, old.Version, peers12.Version)
require.NotEqual(t, old.ShortID, peers12.ShortID)
}
func TestShortIDCollision(t *testing.T) {
// Create 3 peers
_, peers1 := newNode(PeerName(1))
_, peers2 := newNode(PeerName(2))
_, peers3 := newNode(PeerName(3))
var pending PeersPendingNotifications
peers1.setLocalShortID(1, &pending)
peers2.setLocalShortID(2, &pending)
peers3.setLocalShortID(3, &pending)
peers2.AddTestConnection(peers1.ourself.Peer)
peers3.AddTestConnection(peers2.ourself.Peer)
// Propogate from 1 to 2 to 3
peers2.ApplyUpdate(peers1.EncodePeers(peers1.Names()))
peers3.ApplyUpdate(peers2.EncodePeers(peers2.Names()))
// Force the short id of peer 1 to collide with peer 2. Peer
// 1 has the lowest name, so it gets to keep the short id
peers1.setLocalShortID(2, &pending)
oldShortID := peers2.ourself.ShortID
_, updated, _ := peers2.ApplyUpdate(peers1.EncodePeers(peers1.Names()))
// peer 2 should have noticed the collision and resolved it
require.NotEqual(t, oldShortID, peers2.ourself.ShortID)
// The Peers do not have a Router, so broadcastPeerUpdate does
// nothing in the context of this test. So we fake what it
// would do.
updated[PeerName(2)] = void
// the update from peer 2 should include its short id change
peers3.ApplyUpdate(peers2.EncodePeers(updated))
require.Equal(t, peers2.ourself.ShortID,
peers3.Fetch(PeerName(2)).ShortID)
}
// Test the case where all short ids are taken, but then some peers go
// away, so the local peer reassigns
func TestDeferredShortIDReassignment(t *testing.T) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
_, us := newNode(PeerName(1 << PeerShortIDBits))
// Connect us to other peers occupying all short ids
others := make([]*Peers, 1<<PeerShortIDBits)
var pending PeersPendingNotifications
for i := range others {
_, others[i] = newNode(PeerName(i))
others[i].setLocalShortID(PeerShortID(i), &pending)
us.AddTestConnection(others[i].ourself.Peer)
}
// Check that, as expected, the local peer does not own its
// short id
require.NotEqual(t, us.ourself.Peer,
us.byShortID[us.ourself.ShortID].peer)
// Disconnect one peer, and we should now be able to claim its
// short id
other := others[rng.Intn(1<<PeerShortIDBits)]
us.DeleteTestConnection(other.ourself.Peer)
us.GarbageCollect()
require.Equal(t, us.ourself.Peer, us.byShortID[us.ourself.ShortID].peer)
}
-348
View File
@@ -1,348 +0,0 @@
package mesh
import (
"bytes"
"encoding/gob"
"encoding/hex"
"fmt"
"io"
"time"
)
const (
Protocol = "weave"
ProtocolMinVersion = 1
ProtocolMaxVersion = 2
)
var (
ProtocolBytes = []byte(Protocol)
HeaderTimeout = 10 * time.Second
ProtocolV1Features = []string{
"ConnID",
"Name",
"NickName",
"PeerNameFlavour",
"UID",
}
ErrExpectedCrypto = fmt.Errorf("Password specified, but peer requested an unencrypted connection")
ErrExpectedNoCrypto = fmt.Errorf("No password specificed, but peer requested an encrypted connection")
)
// We don't need the full net.TCPConn to do the protocol intro. This
// interface contains just the parts we do need, to support testing
type ProtocolIntroConn interface {
// io.Reader
Read(b []byte) (n int, err error)
// io.Writer
Write(b []byte) (n int, err error)
// net.Conn's deadline methods
SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
}
type ProtocolIntroParams struct {
MinVersion byte
MaxVersion byte
Features map[string]string
Conn ProtocolIntroConn
Password []byte
Outbound bool
}
type ProtocolIntroResults struct {
Features map[string]string
Receiver TCPReceiver
Sender TCPSender
SessionKey *[32]byte
Version byte
}
func (params ProtocolIntroParams) DoIntro() (res ProtocolIntroResults, err error) {
if err = params.Conn.SetDeadline(time.Now().Add(HeaderTimeout)); err != nil {
return
}
if res.Version, err = params.exchangeProtocolHeader(); err != nil {
return
}
var pubKey, privKey *[32]byte
if params.Password != nil {
if pubKey, privKey, err = GenerateKeyPair(); err != nil {
return
}
}
if err = params.Conn.SetWriteDeadline(time.Time{}); err != nil {
return
}
if err = params.Conn.SetReadDeadline(time.Now().Add(TCPHeartbeat * 2)); err != nil {
return
}
switch res.Version {
case 1:
err = res.doIntroV1(params, pubKey, privKey)
case 2:
err = res.doIntroV2(params, pubKey, privKey)
default:
panic("unhandled protocol version")
}
return
}
func (params ProtocolIntroParams) exchangeProtocolHeader() (byte, error) {
// Write in a separate goroutine to avoid the possibility of
// deadlock. The result channel is of size 1 so that the
// goroutine does not linger even if we encounter an error on
// the read side.
sendHeader := append(ProtocolBytes, params.MinVersion, params.MaxVersion)
writeDone := make(chan error, 1)
go func() {
_, err := params.Conn.Write(sendHeader)
writeDone <- err
}()
header := make([]byte, len(ProtocolBytes)+2)
if n, err := io.ReadFull(params.Conn, header); err != nil && n == 0 {
return 0, fmt.Errorf("failed to receive remote protocol header: %s", err)
} else if err != nil {
return 0, fmt.Errorf("received incomplete remote protocol header (%d octets instead of %d): %v; error: %s",
n, len(header), header[:n], err)
}
if !bytes.Equal(ProtocolBytes, header[:len(ProtocolBytes)]) {
return 0, fmt.Errorf("remote protocol header not recognised: %v", header[:len(ProtocolBytes)])
}
theirMinVersion := header[len(ProtocolBytes)]
minVersion := theirMinVersion
if params.MinVersion > minVersion {
minVersion = params.MinVersion
}
theirMaxVersion := header[len(ProtocolBytes)+1]
maxVersion := theirMaxVersion
if maxVersion > params.MaxVersion {
maxVersion = params.MaxVersion
}
if minVersion > maxVersion {
return 0, fmt.Errorf("remote version range [%d,%d] is incompatible with ours [%d,%d]",
theirMinVersion, theirMaxVersion,
params.MinVersion, params.MaxVersion)
}
if err := <-writeDone; err != nil {
return 0, err
}
return maxVersion, nil
}
// The V1 procotol consists of the protocol identification/version
// header, followed by a stream of gobified values. The first value
// is the encoded features map (never encrypted). The subsequent
// values are the messages on the connection (encrypted for an
// encrypted connection). For an encrypted connection, the public key
// is passed in the "PublicKey" feature as a string of hex digits.
func (res *ProtocolIntroResults) doIntroV1(params ProtocolIntroParams, pubKey, privKey *[32]byte) error {
features := filterV1Features(params.Features)
if pubKey != nil {
features["PublicKey"] = hex.EncodeToString(pubKey[:])
}
enc := gob.NewEncoder(params.Conn)
dec := gob.NewDecoder(params.Conn)
// Encode in a separate goroutine to avoid the possibility of
// deadlock. The result channel is of size 1 so that the
// goroutine does not linger even if we encounter an error on
// the read side.
encodeDone := make(chan error, 1)
go func() {
encodeDone <- enc.Encode(features)
}()
if err := dec.Decode(&res.Features); err != nil {
return err
}
if err := <-encodeDone; err != nil {
return err
}
res.Sender = NewGobTCPSender(enc)
res.Receiver = NewGobTCPReceiver(dec)
if pubKey == nil {
if _, present := res.Features["PublicKey"]; present {
return ErrExpectedNoCrypto
}
} else {
remotePubKeyStr, ok := res.Features["PublicKey"]
if !ok {
return ErrExpectedCrypto
}
remotePubKey, err := hex.DecodeString(remotePubKeyStr)
if err != nil {
return err
}
res.setupCrypto(params, remotePubKey, privKey)
}
res.Features = filterV1Features(res.Features)
return nil
}
// In the V1 protocol, the intro fields are sent unencrypted. So we
// restrict them to an established subset of fields that are assumed
// to be safe.
func filterV1Features(intro map[string]string) map[string]string {
safe := make(map[string]string)
for _, k := range ProtocolV1Features {
if val, ok := intro[k]; ok {
safe[k] = val
}
}
return safe
}
// The V2 procotol consists of the protocol identification/version
// header, followed by:
//
// - A single "encryption flag" byte: 0 for no encryption, 1 for
// encryption.
//
// - When the connection is encrypted, 32 bytes follow containing the
// public key.
//
// - Then a stream of length-prefixed messages, which are encrypted
// for an encrypted connection.
//
// The first message contains the encoded features map (so in contrast
// to V1, it will be encrypted on an encrypted connection).
func (res *ProtocolIntroResults) doIntroV2(params ProtocolIntroParams, pubKey, privKey *[32]byte) error {
// Public key exchange
var wbuf []byte
if pubKey == nil {
wbuf = []byte{0}
} else {
wbuf = make([]byte, 1+len(*pubKey))
wbuf[0] = 1
copy(wbuf[1:], (*pubKey)[:])
}
// Write in a separate goroutine to avoid the possibility of
// deadlock. The result channel is of size 1 so that the
// goroutine does not linger even if we encounter an error on
// the read side.
writeDone := make(chan error, 1)
go func() {
_, err := params.Conn.Write(wbuf)
writeDone <- err
}()
rbuf := make([]byte, 1)
if _, err := io.ReadFull(params.Conn, rbuf); err != nil {
return err
}
switch rbuf[0] {
case 0:
if pubKey != nil {
return ErrExpectedCrypto
}
res.Sender = NewLengthPrefixTCPSender(params.Conn)
res.Receiver = NewLengthPrefixTCPReceiver(params.Conn)
case 1:
if pubKey == nil {
return ErrExpectedNoCrypto
}
rbuf = make([]byte, len(pubKey))
if _, err := io.ReadFull(params.Conn, rbuf); err != nil {
return err
}
res.Sender = NewLengthPrefixTCPSender(params.Conn)
res.Receiver = NewLengthPrefixTCPReceiver(params.Conn)
res.setupCrypto(params, rbuf, privKey)
default:
return fmt.Errorf("Bad encryption flag %d", rbuf[0])
}
if err := <-writeDone; err != nil {
return err
}
// Features exchange
go func() {
buf := new(bytes.Buffer)
if err := gob.NewEncoder(buf).Encode(&params.Features); err != nil {
writeDone <- err
return
}
writeDone <- res.Sender.Send(buf.Bytes())
}()
rbuf, err := res.Receiver.Receive()
if err != nil {
return err
}
if err := gob.NewDecoder(bytes.NewReader(rbuf)).Decode(&res.Features); err != nil {
return err
}
if err := <-writeDone; err != nil {
return err
}
return nil
}
func (res *ProtocolIntroResults) setupCrypto(params ProtocolIntroParams, remotePubKey []byte, privKey *[32]byte) {
var remotePubKeyArr [32]byte
copy(remotePubKeyArr[:], remotePubKey)
res.SessionKey = FormSessionKey(&remotePubKeyArr, privKey, params.Password)
res.Sender = NewEncryptedTCPSender(res.Sender, res.SessionKey, params.Outbound)
res.Receiver = NewEncryptedTCPReceiver(res.Receiver, res.SessionKey, params.Outbound)
}
type ProtocolTag byte
const (
ProtocolHeartbeat = iota
ProtocolReserved1 // legacy overlay control messages
ProtocolReserved2 //
ProtocolReserved3 //
ProtocolGossip
ProtocolGossipUnicast
ProtocolGossipBroadcast
ProtocolOverlayControlMsg
)
type ProtocolMsg struct {
tag ProtocolTag
msg []byte
}
type ProtocolSender interface {
SendProtocolMsg(m ProtocolMsg)
}
-180
View File
@@ -1,180 +0,0 @@
package mesh
import (
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"encoding/gob"
"fmt"
"io"
"sync"
"golang.org/x/crypto/nacl/box"
"golang.org/x/crypto/nacl/secretbox"
)
const MaxTCPMsgSize = 10 * 1024 * 1024
func GenerateKeyPair() (publicKey, privateKey *[32]byte, err error) {
return box.GenerateKey(rand.Reader)
}
func FormSessionKey(remotePublicKey, localPrivateKey *[32]byte, secretKey []byte) *[32]byte {
var sharedKey [32]byte
box.Precompute(&sharedKey, remotePublicKey, localPrivateKey)
sharedKeySlice := sharedKey[:]
sharedKeySlice = append(sharedKeySlice, secretKey...)
sessionKey := sha256.Sum256(sharedKeySlice)
return &sessionKey
}
// TCP Senders/Receivers
// The lowest 64 bits of the nonce contain the message sequence
// number. The top most bit indicates the connection polarity at the
// sender - '1' for outbound; the next indicates protocol type - '1'
// for TCP. The remaining 126 bits are zero. The polarity is needed so
// that the two ends of a connection do not use the same nonces; the
// protocol type so that the TCP connection nonces are distinct from
// nonces used by overlay connections, if they share the session key.
// This is a requirement of the NaCl Security Model; see
// http://nacl.cr.yp.to/box.html.
type TCPCryptoState struct {
sessionKey *[32]byte
nonce [24]byte
seqNo uint64
}
func NewTCPCryptoState(sessionKey *[32]byte, outbound bool) *TCPCryptoState {
s := &TCPCryptoState{sessionKey: sessionKey}
if outbound {
s.nonce[0] |= (1 << 7)
}
s.nonce[0] |= (1 << 6)
return s
}
func (s *TCPCryptoState) advance() {
s.seqNo++
binary.BigEndian.PutUint64(s.nonce[16:24], s.seqNo)
}
type TCPSender interface {
Send([]byte) error
}
type GobTCPSender struct {
encoder *gob.Encoder
}
type LengthPrefixTCPSender struct {
writer io.Writer
}
type EncryptedTCPSender struct {
sync.RWMutex
sender TCPSender
state *TCPCryptoState
}
func NewGobTCPSender(encoder *gob.Encoder) *GobTCPSender {
return &GobTCPSender{encoder: encoder}
}
func (sender *GobTCPSender) Send(msg []byte) error {
return sender.encoder.Encode(msg)
}
func NewLengthPrefixTCPSender(writer io.Writer) *LengthPrefixTCPSender {
return &LengthPrefixTCPSender{writer: writer}
}
func (sender *LengthPrefixTCPSender) Send(msg []byte) error {
l := len(msg)
if l > MaxTCPMsgSize {
return fmt.Errorf("outgoing message exceeds maximum size: %d > %d", l, MaxTCPMsgSize)
}
// We copy the message so we can send it in a single Write
// operation, thus making this thread-safe without locking.
prefixedMsg := make([]byte, 4+l)
binary.BigEndian.PutUint32(prefixedMsg, uint32(l))
copy(prefixedMsg[4:], msg)
_, err := sender.writer.Write(prefixedMsg)
return err
}
func NewEncryptedTCPSender(sender TCPSender, sessionKey *[32]byte, outbound bool) *EncryptedTCPSender {
return &EncryptedTCPSender{sender: sender, state: NewTCPCryptoState(sessionKey, outbound)}
}
func (sender *EncryptedTCPSender) Send(msg []byte) error {
sender.Lock()
defer sender.Unlock()
encodedMsg := secretbox.Seal(nil, msg, &sender.state.nonce, sender.state.sessionKey)
sender.state.advance()
return sender.sender.Send(encodedMsg)
}
type TCPReceiver interface {
Receive() ([]byte, error)
}
type GobTCPReceiver struct {
decoder *gob.Decoder
}
type LengthPrefixTCPReceiver struct {
reader io.Reader
}
type EncryptedTCPReceiver struct {
receiver TCPReceiver
state *TCPCryptoState
}
func NewGobTCPReceiver(decoder *gob.Decoder) *GobTCPReceiver {
return &GobTCPReceiver{decoder: decoder}
}
func (receiver *GobTCPReceiver) Receive() ([]byte, error) {
var msg []byte
err := receiver.decoder.Decode(&msg)
return msg, err
}
func NewLengthPrefixTCPReceiver(reader io.Reader) *LengthPrefixTCPReceiver {
return &LengthPrefixTCPReceiver{reader: reader}
}
func (receiver *LengthPrefixTCPReceiver) Receive() ([]byte, error) {
lenPrefix := make([]byte, 4)
if _, err := io.ReadFull(receiver.reader, lenPrefix); err != nil {
return nil, err
}
l := binary.BigEndian.Uint32(lenPrefix)
if l > MaxTCPMsgSize {
return nil, fmt.Errorf("incoming message exceeds maximum size: %d > %d", l, MaxTCPMsgSize)
}
msg := make([]byte, l)
_, err := io.ReadFull(receiver.reader, msg)
return msg, err
}
func NewEncryptedTCPReceiver(receiver TCPReceiver, sessionKey *[32]byte, outbound bool) *EncryptedTCPReceiver {
return &EncryptedTCPReceiver{receiver: receiver, state: NewTCPCryptoState(sessionKey, !outbound)}
}
func (receiver *EncryptedTCPReceiver) Receive() ([]byte, error) {
msg, err := receiver.receiver.Receive()
if err != nil {
return nil, err
}
decodedMsg, success := secretbox.Open(nil, msg, &receiver.state.nonce, receiver.state.sessionKey)
if !success {
return nil, fmt.Errorf("Unable to decrypt TCP msg")
}
receiver.state.advance()
return decodedMsg, nil
}
-96
View File
@@ -1,96 +0,0 @@
package mesh
import (
"io"
"testing"
"time"
"github.com/stretchr/testify/require"
)
type testConn struct {
io.Writer
io.Reader
}
func (testConn) SetDeadline(t time.Time) error {
return nil
}
func (testConn) SetReadDeadline(t time.Time) error {
return nil
}
func (testConn) SetWriteDeadline(t time.Time) error {
return nil
}
func connPair() (ProtocolIntroConn, ProtocolIntroConn) {
a := testConn{}
b := testConn{}
a.Reader, b.Writer = io.Pipe()
b.Reader, a.Writer = io.Pipe()
return &a, &b
}
func doIntro(t *testing.T, params ProtocolIntroParams) <-chan ProtocolIntroResults {
ch := make(chan ProtocolIntroResults, 1)
go func() {
res, err := params.DoIntro()
require.Nil(t, err)
ch <- res
}()
return ch
}
func doProtocolIntro(t *testing.T, aver, bver byte, password []byte) byte {
aconn, bconn := connPair()
aresch := doIntro(t, ProtocolIntroParams{
MinVersion: ProtocolMinVersion,
MaxVersion: aver,
Features: map[string]string{"Name": "A"},
Conn: aconn,
Outbound: true,
Password: password,
})
bresch := doIntro(t, ProtocolIntroParams{
MinVersion: ProtocolMinVersion,
MaxVersion: bver,
Features: map[string]string{"Name": "B"},
Conn: bconn,
Outbound: false,
Password: password,
})
ares := <-aresch
bres := <-bresch
// Check that features were conveyed
require.Equal(t, "B", ares.Features["Name"])
require.Equal(t, "A", bres.Features["Name"])
// Check that Senders and Receivers work
go func() {
require.Nil(t, ares.Sender.Send([]byte("Hello from A")))
require.Nil(t, bres.Sender.Send([]byte("Hello from B")))
}()
data, err := bres.Receiver.Receive()
require.Nil(t, err)
require.Equal(t, "Hello from A", string(data))
data, err = ares.Receiver.Receive()
require.Nil(t, err)
require.Equal(t, "Hello from B", string(data))
require.Equal(t, ares.Version, bres.Version)
return ares.Version
}
func TestProtocolIntro(t *testing.T) {
require.Equal(t, 2, int(doProtocolIntro(t, 2, 2, nil)))
require.Equal(t, 2, int(doProtocolIntro(t, 2, 2, []byte("sekr1t"))))
require.Equal(t, 1, int(doProtocolIntro(t, 1, 2, nil)))
require.Equal(t, 1, int(doProtocolIntro(t, 1, 2, []byte("pa55"))))
require.Equal(t, 1, int(doProtocolIntro(t, 2, 1, nil)))
require.Equal(t, 1, int(doProtocolIntro(t, 2, 1, []byte("w0rd"))))
}
-189
View File
@@ -1,189 +0,0 @@
package mesh
import (
"fmt"
"math"
"net"
"sync"
"time"
"github.com/weaveworks/weave/common"
)
const (
Port = 6783
ChannelSize = 16
TCPHeartbeat = 30 * time.Second
GossipInterval = 30 * time.Second
MaxDuration = time.Duration(math.MaxInt64)
acceptMaxTokens = 100 // [1]
acceptTokenDelay = 100 * time.Millisecond // [2]
)
// [1] capacity of token bucket for rate limiting accepts
// [2] control rate at which new tokens are added to the bucket
var (
log = common.Log
checkFatal = common.CheckFatal
checkWarn = common.CheckWarn
)
type Config struct {
Port int
ProtocolMinVersion byte
Password []byte
ConnLimit int
PeerDiscovery bool
}
type Router struct {
Config
Overlay Overlay
Ourself *LocalPeer
Peers *Peers
Routes *Routes
ConnectionMaker *ConnectionMaker
gossipLock sync.RWMutex
gossipChannels GossipChannels
TopologyGossip Gossip
acceptLimiter *TokenBucket
}
func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) *Router {
router := &Router{Config: config, gossipChannels: make(GossipChannels)}
if overlay == nil {
overlay = NullOverlay{}
}
router.Overlay = overlay
router.Ourself = NewLocalPeer(name, nickName, router)
router.Peers = NewPeers(router.Ourself)
router.Peers.OnGC(func(peer *Peer) {
log.Println("Removed unreachable peer", peer)
})
router.Routes = NewRoutes(router.Ourself, router.Peers)
router.ConnectionMaker = NewConnectionMaker(router.Ourself, router.Peers, router.Port, router.PeerDiscovery)
router.TopologyGossip = router.NewGossip("topology", router)
router.acceptLimiter = NewTokenBucket(acceptMaxTokens, acceptTokenDelay)
return router
}
// Start listening for TCP connections. This is separate from
// NewRouter so that gossipers can register before we start forming
// connections.
func (router *Router) Start() {
router.listenTCP(router.Port)
}
func (router *Router) Stop() error {
// TODO: perform graceful shutdown...
return nil
}
func (router *Router) UsingPassword() bool {
return router.Password != nil
}
func (router *Router) listenTCP(localPort int) {
localAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprint(":", localPort))
checkFatal(err)
ln, err := net.ListenTCP("tcp4", localAddr)
checkFatal(err)
go func() {
defer ln.Close()
for {
tcpConn, err := ln.AcceptTCP()
if err != nil {
log.Errorln(err)
continue
}
router.acceptTCP(tcpConn)
router.acceptLimiter.Wait()
}
}()
}
func (router *Router) acceptTCP(tcpConn *net.TCPConn) {
remoteAddrStr := tcpConn.RemoteAddr().String()
log.Printf("->[%s] connection accepted", remoteAddrStr)
connRemote := NewRemoteConnection(router.Ourself.Peer, nil, remoteAddrStr, false, false)
StartLocalConnection(connRemote, tcpConn, router, true)
}
// Gossiper methods - the Router is the topology Gossiper
type TopologyGossipData struct {
peers *Peers
update PeerNameSet
}
func (router *Router) BroadcastTopologyUpdate(update []*Peer) {
names := make(PeerNameSet)
for _, p := range update {
names[p.Name] = void
}
router.TopologyGossip.GossipBroadcast(&TopologyGossipData{
peers: router.Peers,
update: names,
})
}
func (d *TopologyGossipData) Merge(other GossipData) {
for name := range other.(*TopologyGossipData).update {
d.update[name] = void
}
}
func (d *TopologyGossipData) Encode() [][]byte {
return [][]byte{d.peers.EncodePeers(d.update)}
}
func (router *Router) OnGossipUnicast(sender PeerName, msg []byte) error {
return fmt.Errorf("unexpected topology gossip unicast: %v", msg)
}
func (router *Router) OnGossipBroadcast(_ PeerName, update []byte) (GossipData, error) {
origUpdate, _, err := router.applyTopologyUpdate(update)
if err != nil || len(origUpdate) == 0 {
return nil, err
}
return &TopologyGossipData{peers: router.Peers, update: origUpdate}, nil
}
func (router *Router) Gossip() GossipData {
return &TopologyGossipData{peers: router.Peers, update: router.Peers.Names()}
}
func (router *Router) OnGossip(update []byte) (GossipData, error) {
_, newUpdate, err := router.applyTopologyUpdate(update)
if err != nil || len(newUpdate) == 0 {
return nil, err
}
return &TopologyGossipData{peers: router.Peers, update: newUpdate}, nil
}
func (router *Router) applyTopologyUpdate(update []byte) (PeerNameSet, PeerNameSet, error) {
origUpdate, newUpdate, err := router.Peers.ApplyUpdate(update)
if _, ok := err.(UnknownPeerError); err != nil && ok {
// That update contained a reference to a peer which wasn't
// itself included in the update, and we didn't know about
// already. We ignore this; eventually we should receive an
// update containing a complete topology.
log.Println("Topology gossip:", err)
return nil, nil, nil
}
if err != nil {
return nil, nil, err
}
if len(newUpdate) > 0 {
router.ConnectionMaker.Refresh()
router.Routes.Recalculate()
}
return origUpdate, newUpdate, nil
}
-272
View File
@@ -1,272 +0,0 @@
package mesh
import (
"math"
"sync"
)
type unicastRoutes map[PeerName]PeerName
type broadcastRoutes map[PeerName][]PeerName
type Routes struct {
sync.RWMutex
ourself *LocalPeer
peers *Peers
onChange []func()
unicast unicastRoutes
unicastAll unicastRoutes // [1]
broadcast broadcastRoutes
broadcastAll broadcastRoutes // [1]
recalculate chan<- *struct{}
wait chan<- chan struct{}
// [1] based on *all* connections, not just established &
// symmetric ones
}
func NewRoutes(ourself *LocalPeer, peers *Peers) *Routes {
recalculate := make(chan *struct{}, 1)
wait := make(chan chan struct{})
routes := &Routes{
ourself: ourself,
peers: peers,
unicast: make(unicastRoutes),
unicastAll: make(unicastRoutes),
broadcast: make(broadcastRoutes),
broadcastAll: make(broadcastRoutes),
recalculate: recalculate,
wait: wait}
routes.unicast[ourself.Name] = UnknownPeerName
routes.unicastAll[ourself.Name] = UnknownPeerName
routes.broadcast[ourself.Name] = []PeerName{}
routes.broadcastAll[ourself.Name] = []PeerName{}
go routes.run(recalculate, wait)
return routes
}
func (routes *Routes) OnChange(callback func()) {
routes.Lock()
defer routes.Unlock()
routes.onChange = append(routes.onChange, callback)
}
func (routes *Routes) PeerNames() PeerNameSet {
return routes.peers.Names()
}
func (routes *Routes) Unicast(name PeerName) (PeerName, bool) {
routes.RLock()
defer routes.RUnlock()
hop, found := routes.unicast[name]
return hop, found
}
func (routes *Routes) UnicastAll(name PeerName) (PeerName, bool) {
routes.RLock()
defer routes.RUnlock()
hop, found := routes.unicastAll[name]
return hop, found
}
func (routes *Routes) Broadcast(name PeerName) []PeerName {
routes.RLock()
defer routes.RUnlock()
return routes.broadcast[name]
}
func (routes *Routes) BroadcastAll(name PeerName) []PeerName {
routes.RLock()
defer routes.RUnlock()
return routes.broadcastAll[name]
}
// Choose min(log2(n_peers), n_neighbouring_peers) neighbours, with a
// random distribution that is topology-sensitive, favouring
// neighbours at the end of "bottleneck links". We determine the
// latter based on the unicast routing table. If a neighbour appears
// as the value more frequently than others - meaning that we reach a
// higher proportion of peers via that neighbour than other neighbours
// - then it is chosen with a higher probability.
//
// Note that we choose log2(n_peers) *neighbours*, not
// peers. Consequently, on sparsely connected peers this function
// returns a higher proportion of neighbours than elsewhere. In
// extremis, on peers with fewer than log2(n_peers) neighbours, all
// neighbours are returned.
func (routes *Routes) RandomNeighbours(except PeerName) PeerNameSet {
res := make(PeerNameSet)
routes.RLock()
defer routes.RUnlock()
count := int(math.Log2(float64(len(routes.unicastAll))))
// depends on go's random map iteration
for _, dst := range routes.unicastAll {
if dst != UnknownPeerName && dst != except {
res[dst] = void
if len(res) >= count {
break
}
}
}
return res
}
// Request recalculation of the routing table. This is async but can
// effectively be made synchronous with a subsequent call to
// EnsureRecalculated.
func (routes *Routes) Recalculate() {
// The use of a 1-capacity channel in combination with the
// non-blocking send is an optimisation that results in multiple
// requests being coalesced.
select {
case routes.recalculate <- nil:
default:
}
}
// Wait for any preceding Recalculate requests to be processed.
func (routes *Routes) EnsureRecalculated() {
done := make(chan struct{})
routes.wait <- done
<-done
}
func (routes *Routes) run(recalculate <-chan *struct{}, wait <-chan chan struct{}) {
for {
select {
case <-recalculate:
routes.calculate()
case done := <-wait:
select {
case <-recalculate:
routes.calculate()
default:
}
close(done)
}
}
}
func (routes *Routes) calculate() {
routes.peers.RLock()
routes.ourself.RLock()
var (
oldUnicast = routes.unicast
oldBroadcast = routes.broadcast
unicast = routes.calculateUnicast(true)
unicastAll = routes.calculateUnicast(false)
broadcast = routes.calculateBroadcast(true)
broadcastAll = routes.calculateBroadcast(false)
)
routes.ourself.RUnlock()
routes.peers.RUnlock()
routes.Lock()
routes.unicast = unicast
routes.unicastAll = unicastAll
routes.broadcast = broadcast
routes.broadcastAll = broadcastAll
onChange := routes.onChange
routes.Unlock()
if !unicast.equals(oldUnicast) || !broadcast.equals(oldBroadcast) {
for _, callback := range onChange {
callback()
}
}
}
// Calculate all the routes for the question: if *we* want to send a
// packet to Peer X, what is the next hop?
//
// When we sniff a packet, we determine the destination peer
// ourself. Consequently, we can relay the packet via any
// arbitrary peers - the intermediate peers do not have to have
// any knowledge of the MAC address at all. Thus there's no need
// to exchange knowledge of MAC addresses, nor any constraints on
// the routes that we construct.
func (routes *Routes) calculateUnicast(establishedAndSymmetric bool) unicastRoutes {
_, unicast := routes.ourself.Routes(nil, establishedAndSymmetric)
return unicast
}
// Calculate all the routes for the question: if we receive a
// broadcast originally from Peer X, which peers should we pass the
// frames on to?
//
// When the topology is stable, and thus all peers perform route
// calculations based on the same data, the algorithm ensures that
// broadcasts reach every peer exactly once.
//
// This is largely due to properties of the Peer.Routes algorithm. In
// particular:
//
// ForAll X,Y,Z in Peers.
// X.Routes(Y) <= X.Routes(Z) \/
// X.Routes(Z) <= X.Routes(Y)
// ForAll X,Y,Z in Peers.
// Y =/= Z /\ X.Routes(Y) <= X.Routes(Z) =>
// X.Routes(Y) u [P | Y.HasSymmetricConnectionTo(P)] <= X.Routes(Z)
// where <= is the subset relationship on keys of the returned map.
func (routes *Routes) calculateBroadcast(establishedAndSymmetric bool) broadcastRoutes {
broadcast := make(broadcastRoutes)
for _, peer := range routes.peers.byName {
hops := []PeerName{}
if found, reached := peer.Routes(routes.ourself.Peer, establishedAndSymmetric); found {
routes.ourself.ForEachConnectedPeer(establishedAndSymmetric, reached,
func(remotePeer *Peer) { hops = append(hops, remotePeer.Name) })
}
broadcast[peer.Name] = hops
}
return broadcast
}
func (a unicastRoutes) equals(b unicastRoutes) bool {
for key, aval := range a {
if bval, ok := b[key]; !ok || bval != aval {
return false
}
}
for key := range b {
if _, ok := a[key]; !ok {
return false
}
}
return true
}
func (a broadcastRoutes) equals(b broadcastRoutes) bool {
set := make(map[PeerName]struct{})
for key, aval := range a {
bval, ok := b[key]
if !ok {
return false
}
for _, peer := range aval {
set[peer] = struct{}{}
}
for _, peer := range bval {
if _, ok := set[peer]; !ok {
return false
}
delete(set, peer)
}
if len(set) != 0 {
return false
}
}
for key := range b {
if _, ok := a[key]; !ok {
return false
}
}
return true
}
-193
View File
@@ -1,193 +0,0 @@
package mesh
import (
"fmt"
)
type Status struct {
Protocol string
ProtocolMinVersion int
ProtocolMaxVersion int
Encryption bool
PeerDiscovery bool
Name string
NickName string
Port int
Peers []PeerStatus
UnicastRoutes []UnicastRouteStatus
BroadcastRoutes []BroadcastRouteStatus
Connections []LocalConnectionStatus
Targets []string
OverlayDiagnostics interface{}
}
type PeerStatus struct {
Name string
NickName string
UID PeerUID
ShortID PeerShortID
Version uint64
Connections []ConnectionStatus
}
type ConnectionStatus struct {
Name string
NickName string
Address string
Outbound bool
Established bool
}
type UnicastRouteStatus struct {
Dest, Via string
}
type BroadcastRouteStatus struct {
Source string
Via []string
}
type LocalConnectionStatus struct {
Address string
Outbound bool
State string
Info string
}
func NewStatus(router *Router) *Status {
return &Status{
Protocol,
ProtocolMinVersion,
ProtocolMaxVersion,
router.UsingPassword(),
router.PeerDiscovery,
router.Ourself.Name.String(),
router.Ourself.NickName,
router.Port,
NewPeerStatusSlice(router.Peers),
NewUnicastRouteStatusSlice(router.Routes),
NewBroadcastRouteStatusSlice(router.Routes),
NewLocalConnectionStatusSlice(router.ConnectionMaker),
NewTargetSlice(router.ConnectionMaker),
router.Overlay.Diagnostics()}
}
func NewPeerStatusSlice(peers *Peers) []PeerStatus {
var slice []PeerStatus
peers.ForEach(func(peer *Peer) {
var connections []ConnectionStatus
if peer == peers.ourself.Peer {
for conn := range peers.ourself.Connections() {
connections = append(connections, newConnectionStatus(conn))
}
} else {
// Modifying peer.connections requires a write lock on
// Peers, and since we are holding a read lock (due to the
// ForEach), access without locking the peer is safe.
for _, conn := range peer.connections {
connections = append(connections, newConnectionStatus(conn))
}
}
slice = append(slice, PeerStatus{
peer.Name.String(),
peer.NickName,
peer.UID,
peer.ShortID,
peer.Version,
connections})
})
return slice
}
func newConnectionStatus(c Connection) ConnectionStatus {
return ConnectionStatus{
c.Remote().Name.String(),
c.Remote().NickName,
c.RemoteTCPAddr(),
c.Outbound(),
c.Established()}
}
func NewUnicastRouteStatusSlice(routes *Routes) []UnicastRouteStatus {
routes.RLock()
defer routes.RUnlock()
var slice []UnicastRouteStatus
for dest, via := range routes.unicast {
slice = append(slice, UnicastRouteStatus{dest.String(), via.String()})
}
return slice
}
func NewBroadcastRouteStatusSlice(routes *Routes) []BroadcastRouteStatus {
routes.RLock()
defer routes.RUnlock()
var slice []BroadcastRouteStatus
for source, via := range routes.broadcast {
var hops []string
for _, hop := range via {
hops = append(hops, hop.String())
}
slice = append(slice, BroadcastRouteStatus{source.String(), hops})
}
return slice
}
func NewLocalConnectionStatusSlice(cm *ConnectionMaker) []LocalConnectionStatus {
resultChan := make(chan []LocalConnectionStatus, 0)
cm.actionChan <- func() bool {
var slice []LocalConnectionStatus
for conn := range cm.connections {
state := "pending"
if conn.Established() {
state = "established"
}
lc, _ := conn.(*LocalConnection)
info := fmt.Sprintf("%-6v %v", lc.OverlayConn.DisplayName(), conn.Remote())
slice = append(slice, LocalConnectionStatus{conn.RemoteTCPAddr(), conn.Outbound(), state, info})
}
for address, target := range cm.targets {
add := func(state, info string) {
slice = append(slice, LocalConnectionStatus{address, true, state, info})
}
switch target.state {
case TargetWaiting:
until := "never"
if !target.tryAfter.IsZero() {
until = target.tryAfter.String()
}
if target.lastError == nil { // shouldn't happen
add("waiting", "until: "+until)
} else {
add("failed", target.lastError.Error()+", retry: "+until)
}
case TargetAttempting:
if target.lastError == nil {
add("connecting", "")
} else {
add("retrying", target.lastError.Error())
}
case TargetConnected:
}
}
resultChan <- slice
return false
}
return <-resultChan
}
func NewTargetSlice(cm *ConnectionMaker) []string {
resultChan := make(chan []string, 0)
cm.actionChan <- func() bool {
var slice []string
for peer := range cm.directPeers {
slice = append(slice, peer)
}
resultChan <- slice
return false
}
return <-resultChan
}
-41
View File
@@ -1,41 +0,0 @@
package mesh
type SurrogateGossipData struct {
messages [][]byte
}
func NewSurrogateGossipData(msg []byte) *SurrogateGossipData {
return &SurrogateGossipData{messages: [][]byte{msg}}
}
func (d *SurrogateGossipData) Encode() [][]byte {
return d.messages
}
func (d *SurrogateGossipData) Merge(other GossipData) {
d.messages = append(d.messages, other.(*SurrogateGossipData).messages...)
}
// SurrogateGossiper ignores unicasts and relays broadcasts and gossips.
type SurrogateGossiper struct{}
func (*SurrogateGossiper) OnGossipUnicast(sender PeerName, msg []byte) error {
return nil
}
func (*SurrogateGossiper) OnGossipBroadcast(_ PeerName, update []byte) (GossipData, error) {
return NewSurrogateGossipData(update), nil
}
func (*SurrogateGossiper) Gossip() GossipData {
return nil
}
func (*SurrogateGossiper) OnGossip(update []byte) (GossipData, error) {
return NewSurrogateGossipData(update), nil
}
var (
surrogateGossiper SurrogateGossiper
)
-42
View File
@@ -1,42 +0,0 @@
package mesh
import (
"time"
)
type TokenBucket struct {
capacity int64 // Maximum capacity of bucket
tokenInterval time.Duration // Token replenishment rate
refillDuration time.Duration // Time to refill from empty
earliestUnspentToken time.Time
}
func NewTokenBucket(capacity int64, tokenInterval time.Duration) *TokenBucket {
tb := TokenBucket{
capacity: capacity,
tokenInterval: tokenInterval,
refillDuration: tokenInterval * time.Duration(capacity)}
tb.earliestUnspentToken = tb.capacityToken()
return &tb
}
func (tb *TokenBucket) Wait() {
// If earliest unspent token is in the future, sleep until then
time.Sleep(tb.earliestUnspentToken.Sub(time.Now()))
// Alternatively, enforce bucket capacity if necessary
capacityToken := tb.capacityToken()
if tb.earliestUnspentToken.Before(capacityToken) {
tb.earliestUnspentToken = capacityToken
}
// 'Remove' a token from the bucket
tb.earliestUnspentToken = tb.earliestUnspentToken.Add(tb.tokenInterval)
}
// Determine the historic token timestamp representing a full bucket
func (tb *TokenBucket) capacityToken() time.Time {
return time.Now().Add(-tb.refillDuration).Truncate(tb.tokenInterval)
}
+76 -23
View File
@@ -5,8 +5,10 @@ import (
"fmt"
"math/rand"
"net"
"os"
"sort"
"strings"
"sync"
"time"
"github.com/miekg/dns"
@@ -17,7 +19,6 @@ import (
const (
topDomain = "."
reverseDNSdomain = "in-addr.arpa."
etcResolvConf = "/etc/resolv.conf"
udpBuffSize = uint16(4096)
minUDPSize = 512
@@ -26,16 +27,52 @@ const (
DefaultClientTimeout = 5 * time.Second
)
type DNSServer struct {
ns *Nameserver
domain string
ttl uint32
address string
type Upstream interface {
Config() (*dns.ClientConfig, error)
}
servers []*dns.Server
upstream *dns.ClientConfig
tcpClient *dns.Client
udpClient *dns.Client
func NewUpstream(resolvConf, filterAddress string) Upstream {
return &upstream{
resolvConf: resolvConf,
filterAddress: filterAddress,
cachedConfig: &dns.ClientConfig{}}
}
type upstream struct {
sync.Mutex
resolvConf string
filterAddress string
cachedConfig *dns.ClientConfig
lastStat time.Time
lastModified time.Time
}
func (u *upstream) Config() (*dns.ClientConfig, error) {
u.Lock()
defer u.Unlock()
// If we checked less than five seconds ago return what we already have
now := time.Now()
if now.Sub(u.lastStat) < 5*time.Second {
return u.cachedConfig, nil
}
u.lastStat = now
// Reread file if it has changed
if fi, err := os.Stat(u.resolvConf); err != nil {
return u.cachedConfig, err
} else if fi.ModTime() != u.lastModified {
if config, err := dns.ClientConfigFromFile(u.resolvConf); err == nil {
config.Servers = filter(config.Servers, u.filterAddress)
u.lastModified = fi.ModTime()
u.cachedConfig = config
} else {
return u.cachedConfig, err
}
}
return u.cachedConfig, nil
}
func filter(ss []string, s string) []string {
@@ -49,24 +86,30 @@ func filter(ss []string, s string) []string {
return ss
}
func NewDNSServer(ns *Nameserver, domain, address, effectiveAddress string, ttl uint32, clientTimeout time.Duration) (*DNSServer, error) {
type DNSServer struct {
ns *Nameserver
domain string
ttl uint32
address string
servers []*dns.Server
upstream Upstream
tcpClient *dns.Client
udpClient *dns.Client
}
func NewDNSServer(ns *Nameserver, domain, address string, upstream Upstream, ttl uint32, clientTimeout time.Duration) (*DNSServer, error) {
s := &DNSServer{
ns: ns,
domain: dns.Fqdn(domain),
ttl: ttl,
address: address,
upstream: upstream,
tcpClient: &dns.Client{Net: "tcp", ReadTimeout: clientTimeout},
udpClient: &dns.Client{Net: "udp", ReadTimeout: clientTimeout, UDPSize: udpBuffSize},
}
var err error
if s.upstream, err = dns.ClientConfigFromFile(etcResolvConf); err != nil {
return nil, err
}
if s.upstream != nil {
s.upstream.Servers = filter(s.upstream.Servers, effectiveAddress)
}
err = s.listen(address)
err := s.listen(address)
return s, err
}
@@ -134,7 +177,7 @@ func (d *DNSServer) createMux(client *dns.Client, defaultMaxResponseSize int) *d
func (h *handler) handleLocal(w dns.ResponseWriter, req *dns.Msg) {
h.ns.debugf("local request: %+v", *req)
if len(req.Question) != 1 || req.Question[0].Qtype != dns.TypeA {
if len(req.Question) != 1 {
h.nameError(w, req)
return
}
@@ -149,6 +192,12 @@ func (h *handler) handleLocal(w dns.ResponseWriter, req *dns.Msg) {
h.nameError(w, req)
return
}
// Per RFC4074, if we have an A but another type was requested,
// return 'no error' with empty answer section
if req.Question[0].Qtype != dns.TypeA {
h.respond(w, h.makeResponse(req, nil))
return
}
header := dns.RR_Header{
Name: req.Question[0].Name,
@@ -204,7 +253,7 @@ func (h *handler) handleRecursive(w dns.ResponseWriter, req *dns.Msg) {
h.ns.debugf("recursive request: %+v", *req)
// Resolve unqualified names locally
if len(req.Question) == 1 && req.Question[0].Qtype == dns.TypeA {
if len(req.Question) == 1 {
hostname := dns.Fqdn(req.Question[0].Name)
if strings.Count(hostname, ".") == 1 {
h.handleLocal(w, req)
@@ -212,10 +261,14 @@ func (h *handler) handleRecursive(w dns.ResponseWriter, req *dns.Msg) {
}
}
for _, server := range h.upstream.Servers {
upstreamConfig, err := h.upstream.Config()
if err != nil {
h.ns.errorf("unable to read upstream config: %s", err)
}
for _, server := range upstreamConfig.Servers {
reqCopy := req.Copy()
reqCopy.Id = dns.Id()
response, _, err := h.client.Exchange(reqCopy, fmt.Sprintf("%s:%s", server, h.upstream.Port))
response, _, err := h.client.Exchange(reqCopy, fmt.Sprintf("%s:%s", server, upstreamConfig.Port))
if (err != nil && err != dns.ErrTruncated) || response == nil {
h.ns.debugf("error trying %s: %v", server, err)
continue
+10 -5
View File
@@ -11,21 +11,26 @@ import (
"github.com/miekg/dns"
"github.com/stretchr/testify/require"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/net/address"
)
type mockUpstream struct {
config *dns.ClientConfig
}
func (mu *mockUpstream) Config() (*dns.ClientConfig, error) {
return mu.config, nil
}
func startServer(t *testing.T, upstream *dns.ClientConfig) (*DNSServer, *Nameserver, int, int) {
peername, err := mesh.PeerNameFromString("00:00:00:02:00:00")
require.Nil(t, err)
nameserver := New(peername, "", func(mesh.PeerName) bool { return true })
dnsserver, err := NewDNSServer(nameserver, "weave.local.", "0.0.0.0:0", "", 30, 5*time.Second)
dnsserver, err := NewDNSServer(nameserver, "weave.local.", "0.0.0.0:0", &mockUpstream{upstream}, 30, 5*time.Second)
require.Nil(t, err)
udpPort := dnsserver.servers[0].PacketConn.LocalAddr().(*net.UDPAddr).Port
tcpPort := dnsserver.servers[1].Listener.Addr().(*net.TCPAddr).Port
if upstream != nil {
dnsserver.upstream = upstream
}
go dnsserver.ActivateAndServe()
return dnsserver, nameserver, udpPort, tcpPort
}
+40 -12
View File
@@ -8,7 +8,8 @@ import (
"strings"
"time"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/net/address"
)
@@ -93,6 +94,9 @@ func (e1 *Entry) merge(e2 *Entry) bool {
e1.Version = e2.Version
e1.Tombstone = e2.Tombstone
return true
} else if e2.Version == e1.Version && e2.Tombstone > e1.Tombstone {
e1.Tombstone = e2.Tombstone
return true
}
return false
}
@@ -105,9 +109,18 @@ func (e1 *Entry) addLowercase() {
e1.lHostname = strings.ToLower(e1.Hostname)
}
func (e1 *Entry) tombstone() bool {
if e1.Tombstone > 0 {
return false
}
e1.Tombstone = now()
e1.Version++
return true
}
func check(es SortableEntries) error {
if !sort.IsSorted(es) {
return fmt.Errorf("Not sorted!")
return fmt.Errorf("Not sorted")
}
for i := 1; i < es.Len(); i++ {
if es.Get(i).equal(es.Get(i - 1)) {
@@ -181,9 +194,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries
tombstoned := Entries{}
for i, e := range *es {
if f(&e) && e.Origin == ourname {
e.Version++
e.Tombstone = now()
if f(&e) && e.Origin == ourname && e.tombstone() {
(*es)[i] = e
tombstoned = append(tombstoned, e)
}
@@ -191,6 +202,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries
return tombstoned
}
// note f() may only modify entries such that they remain in order defined by less()
func (es *Entries) filter(f func(*Entry) bool) {
defer es.checkAndPanic().checkAndPanic()
@@ -205,6 +217,16 @@ func (es *Entries) filter(f func(*Entry) bool) {
*es = (*es)[:i]
}
func (es Entries) findEqual(e *Entry) (*Entry, bool) {
i := sort.Search(len(es), func(i int) bool {
return !es[i].insensitiveLess(e)
})
if i < len(es) && es[i].equal(*e) {
return &es[i], true
}
return nil, false
}
func (es Entries) lookup(hostname string) Entries {
es.checkAndPanic()
@@ -245,12 +267,14 @@ type GossipData struct {
Entries
}
func (g *GossipData) Merge(o mesh.GossipData) {
func (g *GossipData) Merge(o mesh.GossipData) mesh.GossipData {
other := o.(*GossipData)
g.Entries.merge(other.Entries)
if g.Timestamp < other.Timestamp {
g.Timestamp = other.Timestamp
gossip := g.copy()
gossip.Entries.merge(other.Entries)
if gossip.Timestamp < other.Timestamp {
gossip.Timestamp = other.Timestamp
}
return gossip
}
func (g *GossipData) Decode(msg []byte) error {
@@ -264,9 +288,7 @@ func (g *GossipData) Decode(msg []byte) error {
}
func (g *GossipData) Encode() [][]byte {
// Make a copy so we can sort: all outgoing data is sent in case-sensitive order
g2 := GossipData{Timestamp: g.Timestamp, Entries: make(Entries, len(g.Entries))}
copy(g2.Entries, g.Entries)
g2 := g.copy()
sort.Sort(CaseSensitive(g2.Entries))
buf := &bytes.Buffer{}
if err := gob.NewEncoder(buf).Encode(g2); err != nil {
@@ -274,3 +296,9 @@ func (g *GossipData) Encode() [][]byte {
}
return [][]byte{buf.Bytes()}
}
func (g *GossipData) copy() *GossipData {
g2 := &GossipData{Timestamp: g.Timestamp, Entries: make(Entries, len(g.Entries))}
copy(g2.Entries, g.Entries)
return g2
}
+18 -3
View File
@@ -4,8 +4,8 @@ import (
"testing"
"github.com/stretchr/testify/require"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/net/address"
)
@@ -86,6 +86,21 @@ func TestTombstone(t *testing.T) {
Entry{Hostname: "B", Version: 1, Tombstone: 1234},
})
require.Equal(t, expected, es)
// Now try a merge including two entries which differ only in tombstone
e2 := make(Entries, len(es))
copy(e2, es)
e2[1].Tombstone = 5555
diff := es.merge(e2)
expected2 := l(Entries{
Entry{Hostname: "A"},
Entry{Hostname: "B", Version: 1, Tombstone: 5555},
})
require.Equal(t, expected2, es)
expectedDiff := l(Entries{Entry{Hostname: "B", Version: 1, Tombstone: 5555}})
require.Equal(t, expectedDiff, diff)
}
func TestDelete(t *testing.T) {
@@ -117,7 +132,7 @@ func TestGossipDataMerge(t *testing.T) {
g1 := GossipData{Entries: makeEntries("AcDf")}
g2 := GossipData{Entries: makeEntries("BEf")}
g1.Merge(&g2)
g3 := g1.Merge(&g2).(*GossipData)
require.Equal(t, GossipData{Entries: makeEntries("ABcDEf")}, g1)
require.Equal(t, GossipData{Entries: makeEntries("ABcDEf")}, *g3)
}
+3 -11
View File
@@ -40,16 +40,11 @@ func (n *Nameserver) HandleHTTP(router *mux.Router, dockerCli *docker.Client) {
return
}
if err := n.AddEntry(hostname, container, n.ourName, ip); err != nil {
n.badRequest(w, fmt.Errorf("Unable to add entry: %v", err))
return
}
n.AddEntry(hostname, container, n.ourName, ip)
if r.FormValue("check-alive") == "true" && dockerCli != nil && dockerCli.IsContainerNotRunning(container) {
n.infof("container '%s' is not running: removing", container)
if err := n.Delete(hostname, container, ipStr, ip); err != nil {
n.infof("failed to remove: %v", err)
}
n.Delete(hostname, container, ipStr, ip)
}
w.WriteHeader(204)
@@ -79,10 +74,7 @@ func (n *Nameserver) HandleHTTP(router *mux.Router, dockerCli *docker.Client) {
ipStr = "*"
}
if err := n.Delete(hostname, container, ipStr, ip); err != nil {
n.badRequest(w, fmt.Errorf("Unable to delete entries: %v", err))
return
}
n.Delete(hostname, container, ipStr, ip)
w.WriteHeader(204)
}
router.Methods("DELETE").Path("/name/{container}/{ip}").HandlerFunc(deleteHandler)
+58 -27
View File
@@ -6,9 +6,9 @@ import (
"time"
"github.com/miekg/dns"
"github.com/weaveworks/mesh"
. "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/net/address"
)
@@ -73,22 +73,22 @@ func (n *Nameserver) Stop() {
n.quit <- struct{}{}
}
func (n *Nameserver) broadcastEntries(es ...Entry) error {
if n.gossip != nil {
return n.gossip.GossipBroadcast(&GossipData{
Entries: Entries(es),
Timestamp: now(),
})
func (n *Nameserver) broadcastEntries(es ...Entry) {
if n.gossip == nil || len(es) == 0 {
return
}
return nil
n.gossip.GossipBroadcast(&GossipData{
Entries: Entries(es),
Timestamp: now(),
})
}
func (n *Nameserver) AddEntry(hostname, containerid string, origin mesh.PeerName, addr address.Address) error {
n.infof("adding entry %s -> %s", hostname, addr.String())
func (n *Nameserver) AddEntry(hostname, containerid string, origin mesh.PeerName, addr address.Address) {
n.Lock()
n.infof("adding entry for %s: %s -> %s", containerid, hostname, addr.String())
entry := n.entries.add(hostname, containerid, origin, addr)
n.Unlock()
return n.broadcastEntries(entry)
n.broadcastEntries(entry)
}
func (n *Nameserver) Lookup(hostname string) []address.Address {
@@ -121,7 +121,8 @@ func (n *Nameserver) ReverseLookup(ip address.Address) (string, error) {
return match.Hostname, nil
}
func (n *Nameserver) ContainerStarted(ident string) {}
func (n *Nameserver) ContainerStarted(ident string) {}
func (n *Nameserver) ContainerDestroyed(ident string) {}
func (n *Nameserver) ContainerDied(ident string) {
n.Lock()
@@ -133,11 +134,7 @@ func (n *Nameserver) ContainerDied(ident string) {
return false
})
n.Unlock()
if len(entries) > 0 {
if err := n.broadcastEntries(entries...); err != nil {
n.errorf("failed to broadcast container %s death: %v", ident, err)
}
}
n.broadcastEntries(entries...)
}
func (n *Nameserver) PeerGone(peer mesh.PeerName) {
@@ -149,7 +146,7 @@ func (n *Nameserver) PeerGone(peer mesh.PeerName) {
})
}
func (n *Nameserver) Delete(hostname, containerid, ipStr string, ip address.Address) error {
func (n *Nameserver) Delete(hostname, containerid, ipStr string, ip address.Address) {
n.Lock()
n.infof("tombstoning hostname=%s, container=%s, ip=%s", hostname, containerid, ipStr)
entries := n.entries.tombstone(n.ourName, func(e *Entry) bool {
@@ -169,7 +166,7 @@ func (n *Nameserver) Delete(hostname, containerid, ipStr string, ip address.Addr
return true
})
n.Unlock()
return n.broadcastEntries(entries...)
n.broadcastEntries(entries...)
}
func (n *Nameserver) deleteTombstones() {
@@ -202,17 +199,46 @@ func (n *Nameserver) receiveGossip(msg []byte) (mesh.GossipData, mesh.GossipData
return nil, nil, err
}
if delta := gossip.Timestamp - now(); delta > gossipWindow || delta < -gossipWindow {
return nil, nil, fmt.Errorf("clock skew of %d detected", delta)
return nil, nil, fmt.Errorf("host clock skew of %ds exceeds %ds limit", delta, gossipWindow)
}
n.Lock()
defer n.Unlock()
// Filter to remove entries from unknown peers, done before we take
// the nameserver lock, so we don't have to worry what isKnownPeer locks.
gossip.Entries.filter(func(e *Entry) bool {
return n.isKnownPeer(e.Origin)
})
var overriddenEntries []Entry
n.Lock()
// Check entries claiming to originate from us against our current data
gossip.Entries.filter(func(e *Entry) bool {
if e.Origin == n.ourName {
if ourEntry, ok := n.entries.findEqual(e); ok {
if ourEntry.Version < e.Version ||
(ourEntry.Version == e.Version && ourEntry.Tombstone != e.Tombstone) {
// Take our version of the data, but make the version higher than the incoming
nextVersion := e.Version + 1
*e = *ourEntry
e.Version = nextVersion
overriddenEntries = append(overriddenEntries, *e)
}
} else { // We have no entry matching the one that came in with us as Origin
if e.tombstone() {
overriddenEntries = append(overriddenEntries, *e)
}
}
}
return true
})
newEntries := n.entries.merge(gossip.Entries)
n.Unlock() // unlock before attempting to broadcast
// Note that all overriddenEntries have been merged into our entries, either
// because we forced the version higher or because they were missing before.
n.broadcastEntries(overriddenEntries...)
if len(newEntries) > 0 {
return &GossipData{Entries: newEntries, Timestamp: now()}, &gossip, nil
}
@@ -233,12 +259,17 @@ func (n *Nameserver) OnGossipBroadcast(_ mesh.PeerName, msg []byte) (mesh.Gossip
return entries, err
}
// Logging
func (n *Nameserver) infof(fmt string, args ...interface{}) {
Log.Infof("[nameserver %s] "+fmt, append([]interface{}{n.ourName}, args...)...)
n.logf(common.Log.Infof, fmt, args...)
}
func (n *Nameserver) debugf(fmt string, args ...interface{}) {
Log.Debugf("[nameserver %s] "+fmt, append([]interface{}{n.ourName}, args...)...)
n.logf(common.Log.Debugf, fmt, args...)
}
func (n *Nameserver) errorf(fmt string, args ...interface{}) {
Log.Errorf("[nameserver %s] "+fmt, append([]interface{}{n.ourName}, args...)...)
n.logf(common.Log.Errorf, fmt, args...)
}
func (n *Nameserver) logf(f func(string, ...interface{}), fmt string, args ...interface{}) {
f("[nameserver %s] "+fmt, append([]interface{}{n.ourName}, args...)...)
}
+8 -19
View File
@@ -10,10 +10,9 @@ import (
"time"
"github.com/stretchr/testify/require"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/mesh"
"github.com/weaveworks/weave/net/address"
wt "github.com/weaveworks/weave/testing"
"github.com/weaveworks/weave/testing/gossip"
)
@@ -76,12 +75,6 @@ func (m mapping) Addrs() []address.Address {
}
func TestNameservers(t *testing.T) {
wt.RunWithTimeout(t, 2*time.Minute, func() {
testNameservers(t)
})
}
func testNameservers(t *testing.T) {
//common.SetLogLevel("debug")
lookupTimeout := 10 // ms
@@ -124,7 +117,7 @@ func testNameservers(t *testing.T) {
mapping := mapping{hostname, []pair{{nameserver.ourName, addr}}}
mappings = append(mappings, mapping)
require.Nil(t, nameserver.AddEntry(hostname, "", nameserver.ourName, addr))
nameserver.AddEntry(hostname, "", nameserver.ourName, addr)
check(nameserver, mapping)
}
@@ -139,7 +132,7 @@ func testNameservers(t *testing.T) {
mapping.addrs = append(mapping.addrs, pair{nameserver.ourName, addr})
mappings[i] = mapping
require.Nil(t, nameserver.AddEntry(mapping.hostname, "", nameserver.ourName, addr))
nameserver.AddEntry(mapping.hostname, "", nameserver.ourName, addr)
check(nameserver, mapping)
}
@@ -164,7 +157,7 @@ func testNameservers(t *testing.T) {
mappings[i] = mapping
nameserver := nameserversByName[pair.origin]
require.Nil(t, nameserver.Delete(mapping.hostname, "*", pair.addr.String(), pair.addr))
nameserver.Delete(mapping.hostname, "*", pair.addr.String(), pair.addr)
check(nameserver, mapping)
}
@@ -230,15 +223,13 @@ func TestContainerAndPeerDeath(t *testing.T) {
require.Nil(t, err)
nameserver := makeNameserver(peername)
err = nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
require.Nil(t, err)
nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname"))
nameserver.ContainerDied("containerid")
require.Equal(t, []address.Address{}, nameserver.Lookup("hostname"))
err = nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
require.Nil(t, err)
nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname"))
nameserver.PeerGone(peername)
@@ -254,15 +245,13 @@ func TestTombstoneDeletion(t *testing.T) {
require.Nil(t, err)
nameserver := makeNameserver(peername)
err = nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
require.Nil(t, err)
nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname"))
nameserver.deleteTombstones()
require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname"))
err = nameserver.Delete("hostname", "containerid", "", address.Address(0))
require.Nil(t, err)
nameserver.Delete("hostname", "containerid", "", address.Address(0))
require.Equal(t, []address.Address{}, nameserver.Lookup("hostname"))
require.Equal(t, l(Entries{Entry{
ContainerID: "containerid",
Loaded 100 of 403 files, more files were not shown because too many files have changed in this diff. Show more