Compare commits

...
961 Commits
Author SHA1 Message Date
Bryan Boreham 242b8907bf Add release v1.9.1 2017-02-27 16:20:02 +00:00
Bryan Boreham 9db22c3cd6 Merge pull request #2818 from 'tobowers-fix-reverse-dns'
Lowercase the request before comparing it

Fix #2817
2017-02-27 16:15:18 +00:00
Bryan Boreham e57d79bd70 Test reverse DNS using dig
so that we can check it works with upper and lower case IN-ADDR.ARPA
2017-02-27 14:56:25 +00:00
Martynas Pumputis 589ab4f01d Merge pull request #2819 from weaveworks/issues/2726-modprobe
Ensure we have the right modules loaded for weave-npc

Fix #2726
2017-02-27 14:23:12 +00:00
Bryan Boreham 01fe09065c Add weave-npc required kernel modules to docs 2017-02-27 14:25:43 +00:00
Topper Bowers 83958561f7 some DNS clients send reverse lookups with uppercase suffixes. This lowercases the request before trimming the lowercase suffix. Problem discovered and discussed here: https://github.com/weaveworks/weave/issues/2817 2017-02-27 14:19:31 +01:00
Bryan Boreham cb73cf3f51 Ensure we have the kernel modules loaded for weave-npc 2017-02-27 12:32:57 +00:00
Martynas Pumputis 7a3e8e64b7 Merge pull request #2810 from ocadotechnology/add-pending-metrics
Add prometheus metrics for pending Allocates and Claims
2017-02-24 15:55:39 +00:00
Bryan Boreham f7ce16cba8 Move detailed warning about rmpeer from FAQ to docs 2017-02-23 13:22:28 +00:00
Bryan Boreham 6ac1fef01d Fix broken link 2017-02-23 13:22:16 +00:00
Bryan Boreham 5c19efae48 Merge pull request #2811 from weaveworks/issues/2223-faq-anchors
Add anchors to faq questions
2017-02-23 13:19:39 +00:00
Bryan Boreham f7c0da3ae1 Merge pull request #2781 from keontang/luanch-update
Add CONN_LIMIT environment var for running container
2017-02-23 12:40:01 +00:00
Bryan Boreham fe0c833cdf Move FAQ to the bottom of the menu 2017-02-23 12:28:51 +00:00
Bryan Boreham 58342f7509 add anchors to faq questions 2017-02-23 12:26:03 +00:00
Mike Bryant fad537cad7 Add prometheus metrics for pending Allocates and Claims 2017-02-23 11:41:07 +00:00
Bryan Boreham 6d5c2ad0fa Merge pull request #2793 from weaveworks/improve-fastdp-crypto-tests
Improve encryption tests
2017-02-22 14:56:14 +00:00
Martynas Pumputis b585e1f4cb Merge pull request #2795 from weaveworks/issues/2792-refcount-ipset
Reference-count ipset entries

Fix #2792
2017-02-22 14:01:26 +00:00
Bryan Boreham 7102bf6d9d Merge pull request #2803 from weaveworks/update-readme
update slack community and weave user group details
2017-02-21 15:38:34 +00:00
Bryan Boreham 77988012ed Merge pull request #2765 from weaveworks/issues/1644-fastdp-crypto-docs
Add fastdp-crypto docs
2017-02-20 17:56:32 +00:00
Bryan Boreham 2989e3cccd Merge pull request #2790 from weaveworks/update-netlink-dep
Update vishvananda/netlink
2017-02-20 17:51:37 +00:00
Bryan Boreham 5a47d1d13f Merge pull request #2796 from weaveworks/versions-manifest
Add versions manifest file for dependencies.
2017-02-20 11:42:30 +00:00
Martynas Pumputis d3795d4e74 Merge pull request #2774 from weaveworks/update-ipam-doc
Update IPAM documentation.
2017-02-16 12:09:08 +00:00
Marc CARRE bc97daf5c0 Update IPAM documentation. 2017-02-15 16:25:12 +00:00
abuehrle 08e4c98172 open new window punctuation 2017-02-14 14:41:25 -06:00
abuehrle ca254e066a changed to pro link for WUOG 2017-02-14 14:28:22 -06:00
abuehrle aea92a3563 update slack community and wuog 2017-02-14 14:16:37 -06:00
Bryan Boreham e9fa655e0e Merge pull request #2802 from weaveworks/issues/2761-build-chown
Make /usr/local/go writable to anyone
2017-02-14 16:55:37 +00:00
Martynas Pumputis 7d178ecee9 Make /usr/local/go writable to anyone
Previous attempt to chown the dir inside build.sh resulted in
a significant increase in a build time, and build.sh is exec'd
once per each build.
2017-02-14 15:45:25 +00:00
Bryan Boreham 201321f390 Remove refcounts on destroy and flush 2017-02-14 10:50:22 +00:00
Bryan Boreham 3afc528c88 Reference-count ipset entries 2017-02-14 10:26:59 +00:00
Marc CARRE 62c9522bf6 Fix bug in get_go_version_from_build_dockerfile.
Previously, the first line of the Dockerfile would have been selected, regardless of its value.
What we want is to actually select the first line matching the regex, and then extract the group corresponding to the Go version out of it.
2017-02-13 19:54:38 +00:00
Marc CARRE 1b45e8662e Add DEPENDENCIES file and source Vagrant and tests versions from it.
- One unique file to list all dependencies and dependencies' versions (except Go, currently defined in `build/Dockerfile`).
- Custom versions can now be injected into Vagrant VMs.
- Vagrant dev VMs, Vagrant test VMs, and `run-integration-tests.sh` all source from `DEPENDENCIES`, to keep things 'DRY'.
- Vagrant versions can be overriden using environment variables, like it was possible in `run-integration-tests.sh`.
2017-02-13 19:54:38 +00:00
Marc CARRE 3ce8aec039 Removed unecessary trailing whitespaces.
Noise on git diff if/when text editors remove them automatically, so might as well proactively remove them.
2017-02-13 19:54:38 +00:00
Martynas Pumputis 32d44e09a1 Merge pull request #2787 from weaveworks/issues/2784-preclaim-addresses
Claim existing IP addresses at startup with no race condition

Fixes #2784
2017-02-13 17:51:38 +00:00
Bryan Boreham 4e37f5ec42 Add explanations of various claim and allocation fields 2017-02-13 17:31:02 +00:00
Bryan Boreham 39f471e9d3 Merge pull request #2773 from weaveworks/issues/2772-check-type-on-delete
Handle cache.DeleteFinalStateUnknown
2017-02-13 15:49:24 +00:00
Bryan Boreham 293abd953e Fix flaky test 320
The intention, per the comments, is that host1 should claim from host2.
But host2 and host3 can carve up the space either way round.  If host1
claims from host3 then there is a race whether anyone finds out about
it.
Adding a 'prime' on host2 ensures the space is all owned by host2 at that point.
2017-02-13 11:30:34 +00:00
Bryan Boreham fde7dcdde9 Stop collecting addresses in weave script now we do it in Go 2017-02-13 11:30:34 +00:00
Bryan Boreham 7075b5d9fd Extend pre-existing address reclaim to docker containers 2017-02-13 11:30:34 +00:00
Bryan Boreham 50b1aa0c74 Merge pull request #2785 from weaveworks/typo-app-isolation-doc
Fix typo in CIDR.
2017-02-13 11:15:17 +00:00
Martynas Pumputis 7f48cc9239 Replace 110_encryption_2_test.sh by 110_sleeve_encryption_2_test.sh 2017-02-10 17:30:30 +00:00
Martynas Pumputis 8211afe5d5 Improve 111_fastdp_encryption_2_test.sh 2017-02-10 17:20:24 +00:00
Bryan Boreham e26dbf11e9 Stop collecting addresses in launch script now we do it in Go 2017-02-10 15:11:14 +00:00
Bryan Boreham 39ac1a0037 Collect existing weave addresses at start-up, to avoid a race when
doing it from the script

Note we need to run weaver in the host pid namespace, so it can search
for existing container IPs. Also now we are firing off sub-processes
it's better to not be PID 1 so Linux doesn't expect us to reap zombies.
2017-02-10 15:10:02 +00:00
Martynas Pumputis 86f716c38c Add fastdp-crypto docs 2017-02-10 14:49:47 +00:00
Marc CARRE d5c7c4476b Fix typo in CIDR. 2017-02-09 20:58:06 +00:00
Martynas Pumputis 2a02883f07 Update vishvananda/netlink 2017-02-09 15:56:02 +00:00
Martynas Pumputis f592e4b70a Merge pull request #2780 from weaveworks/tf-ansi-macos
Upgrade to latest build-tools.
2017-02-09 14:58:43 +00:00
Marc CARRE 968855e0a4 Upgrade to latest build-tools.
Make tools/provisioning/setup.sh behave consistently regardless of whether under Linux or macOS, and whether sourced or executed.
2017-02-09 14:35:54 +00:00
Jiyuan Tang bee031ad70 Add CONN_LIMIT environment for running container 2017-02-09 19:34:16 +08:00
Martynas Pumputis 3378e09b6a Merge pull request #2775 from weaveworks/num-hosts-via-env-var
Remove hard-coded NUM_HOSTS env. var.
2017-02-08 18:17:35 +00:00
Marc CARRE ab37b4a6c4 Remove hard-coded NUM_HOSTS env. var.
Instead of hardcoding this in the code, this should be passed by CircleCI from Settings > weaveworks > weave > Environment Variables.
2017-02-08 17:56:48 +00:00
Martynas Pumputis dff5b6d3f1 Merge pull request #2694 from weaveworks/2647-testing-mvp
Testing MVP

Fixes #2647
2017-02-08 16:25:56 +00:00
Marc CARRE c026579cec Update make lint to cope with latest changes made in build-tools. 2017-02-08 14:15:59 +00:00
Marc CARRE ef8b576742 Default behaviour now is to create a GCP image if missing.
We previously had 'use image' as a default, but not 'create image', which is inconsistent and leads to unexpected failures.
2017-02-08 14:15:59 +00:00
Marc CARRE 69398a9d7e Source config.sh using relative path to the script, regardless of current directory.
Sourcing failed when running make integration-tests.
2017-02-08 14:15:59 +00:00
Marc CARRE 0a2beedad3 Add flag to skip destruction of test VMS.
This should be useful when we just want to type one make integration-tests / ./run-integration-tests command to make/start VMs/configure them/test, but also investigate potential failures afterwards.
2017-02-08 14:15:59 +00:00
Marc CARRE 29d50bbf09 Globally redirect stdout to stderr, except when echo'ing "export HOSTS=...".
This should make development easier by allowing developers to set HOSTS in their calling shell, and re-use the value for this env. var. when calling individual test scripts, e.g.:
```
cd test
eval $(./run-integration-tests.sh setup)
./200_dns_test.sh
```
2017-02-08 14:15:59 +00:00
Marc CARRE 673fc73cd5 Increase number of test machines for CircleCI to 16.
This should speed the build up, and provide faster feedback to developers.
2017-02-08 14:15:59 +00:00
Marc CARRE 1185bed370 Changed default number of test machines to 3.
CircleCI keeps 10 nodes in order to speed up the build, but the default is 3, as this is the minimum required to run any test. This should make more sense as a default for a developer to quickly start an environment and iterate.
2017-02-08 14:15:59 +00:00
Marc CARRE 1176d44044 Run git submodule update --init as the very first step in CircleCI.
Doing so in circle-dependencies-post arrives too late for background provisioning.
2017-02-08 14:15:59 +00:00
Marc CARRE 77649ab81b Relax .lintignore in order for lint to cover newly added scripts. 2017-02-08 14:15:59 +00:00
Marc CARRE a51bc6164c Signal provisioning failures to fail the build fast.
There may be situations when Terraform/Ansible/etc. fail to provision test machines.
In these cases, we want to fail fast instead of waiting until we time out in circle-test-pre and circle-test-smoke.
2017-02-08 14:15:59 +00:00
Marc CARRE dd935b7e9e Provision and destroy test VMs in the background.
This should help speed-up the build by provisioning test VMs while we run unit tests, and destroying them while we generate coverage reports.
2017-02-08 14:15:59 +00:00
Marc CARRE 67dbdd377c Configure Vagrant VMs using Ansible.
This way, Vagrant VMs and cloud-provided VMs are configured in the exact same way, hence avoiding configuration drift and subtle bugs associated to different versions of software.
2017-02-08 14:15:59 +00:00
Marc CARRE e5185e73ce Refactor Vagrant configuration. 2017-02-08 14:15:59 +00:00
Marc CARRE 17ada094f8 Updated and improved testing documentation. 2017-02-08 14:15:59 +00:00
Marc CARRE 3e5593dc4f Add GCP image creation and usage.
Provisioning and configuration being expensive time-wise, we create Google Cloud Platform images for each Docker/Kubernetes/Kubernetes CNI versions triple, and configure these once (instead of for each build), and then re-use these in subsequent builds, effectively implementing a 'cache' of images.
2017-02-08 14:15:59 +00:00
Marc CARRE e647fe6331 Highlight setup and sanity checks in CircleCI's logs. 2017-02-08 14:15:59 +00:00
Marc CARRE a2679794b3 Install Terraform and Ansible in CircleCI's containers.
Terraform and Ansible are now required to run the smoke tests.
2017-02-08 14:15:59 +00:00
Marc CARRE 30f59953d2 Smoke tests are now run using Terraform, Ansible and run-integration-tests.sh. 2017-02-08 14:15:59 +00:00
Marc CARRE acd16881d9 Add make integration-tests based on Terraform/Ansible. 2017-02-08 14:15:59 +00:00
Marc CARRE 2aaa400d62 Add Terraform and Ansible scripts as part of tools submodule. 2017-02-08 14:15:55 +00:00
Marc CARRE 487ebfb514 Increased timeout for test #840.
Reason: test is periodically failing because of the timeout being too aggressive, especially when using Google Cloud Platform together with Terraform and Ansible.
2017-02-08 14:15:02 +00:00
Marc CARRE fde7e88e66 Allow RUNNER_ARGS to be passed by calling script.
This is required in order to be able to dependency-inject values from layers higher up, e.g.: RUNNER_ARGS="-parallel" from the Makefile.
2017-02-08 14:15:02 +00:00
Marc CARRE 9e4ce8c052 Git-ignore Terraform state files. 2017-02-08 14:15:02 +00:00
Adam Harrison defa5cc3d3 Handle cache.DeleteFinalStateUnknown 2017-02-08 12:48:32 +00:00
Martynas Pumputis dea2755161 Merge pull request #2764 from weaveworks/ports-faq
Expand FAQ info about port usage
2017-02-07 14:23:15 +00:00
Bryan Boreham cc8785fdcf Expand info about port usage 2017-02-07 14:06:24 +00:00
Bryan Boreham 7265c6ea03 Move sed of daemonset up next to weave script
For consistency, also for easier unpicking if the 'draft' stage fails
2017-02-03 12:18:48 +00:00
Bryan Boreham 0792f0717d Revert "Temporarily release weave-daemonset.yaml to weave-kube repo"
This reverts commit 23056cbb45.
Explanation: weave-kube has been moved into the weave repo
2017-02-02 11:56:54 +00:00
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
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
318 changed files with 10913 additions and 3123 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
--ignore-dir=vendor
--ignore-dir=.pkg
+9 -2
View File
@@ -43,12 +43,16 @@ prog/weavewait/weavewait
prog/weavewait/weavewait_noop
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
.*.uptodate
weave.tar.gz
weave*.tar.gz
prog/weaveexec/weave
prog/weaveexec/weavehosts
prog/weaveexec/weaveproxy
@@ -57,9 +61,12 @@ prog/weaveexec/weavewait_noop
prog/weaveexec/weavewait_nomcast
prog/weaveexec/sigproxy
prog/weaveexec/weaveutil
prog/weaveexec/docker*.tgz
prog/weaveexec/docker*
Vagrantfile.local
test/tls/tls
test/tls/*.pem
test/coverage
test/coverage.*
*qemu-*-static
terraform.tfstate
terraform.tfstate.backup
+57 -3
View File
@@ -4,9 +4,6 @@
[submodule "vendor/github.com/vishvananda/netlink"]
path = vendor/github.com/vishvananda/netlink
url = https://github.com/vishvananda/netlink.git
[submodule "vendor/github.com/davecheney/profile"]
path = vendor/github.com/davecheney/profile
url = https://github.com/davecheney/profile.git
[submodule "vendor/github.com/gorilla/mux"]
path = vendor/github.com/gorilla/mux
url = https://github.com/gorilla/mux.git
@@ -70,3 +67,60 @@
[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
+27
View File
@@ -0,0 +1,27 @@
# IMPORTANT: Please only use GLOBs to ignore files and directories.
# Do not lint the below bash scripts in Weave Net, in order to
# avoid breaking the build on make lint:
bin/circle-deploy-issues
bin/circle-deploy-master
bin/circle-teardown-pre
bin/circle-test-teardown
bin/circle-test-unit
bin/install-wordepress
bin/multiweave
bin/publish-site
bin/release
build/build.sh
prog/weave-kube/launch.sh
prog/weaveexec/symlink
test/*_test.sh
test/600_proxy_docker_py.sh
test/assert.sh
test/config.sh
test/gce.sh
test/gen_coverage_reports.sh
test/run_all.sh
test/sanity_check.sh
test/setup.sh
vendor/*.sh
weave
+214
View File
@@ -1,3 +1,217 @@
## Release 1.9.1
# Bug fixes and minor improvements
* Fix a race condition when the Weave Net container is restarted
which could allow a new container to be allocated the same IP
address as an existing one #2784,#2787
* Handle the message type received when a pod has been deleted during
Kubernetes api-server fail-over #2772,#2773
* Make weave-kube work with `dockerd --iptables=false` #2726
* Ensure we have the right kernel modules loaded for Network Policy in weave-kube #2819
* Reference-count addresses in Network Policy Controller, to avoid
errors when updates come in an unexpected order #2792,#2795
* Allow the soft connection limit to be raised in weave-kube, so
larger clusters can be created #2781
* WeaveDNS was incorrectly case-sensitive for reverse DNS lookups #2817,#2818
# Build and Testing
* Scripts to create VMs to run automated tests were rewritten to use
Terraform and Ansible, to make it much easier to test with different
versions of components such as Docker and Kubernetes #2647,#2694,#2775,#2796
* Upgrade to latest Weaveworks common build-tools #2780
* Improve encryption tests #2793
* Update vishvananda/netlink library to bring in changes we had previously forked #2790
* Slight change to the build container to avoid permission errors and slow builds #2761,#2802
## 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
+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
+3
View File
@@ -0,0 +1,3 @@
DOCKER_VERSION=1.11.2
KUBERNETES_VERSION=1.5.2
KUBERNETES_CNI_VERSION=0.3.0.1
+243 -55
View File
@@ -1,52 +1,137 @@
PUBLISH=publish_weave publish_weaveexec publish_plugin
.DEFAULT: all
.PHONY: all exes testrunner update tests lint publish $(PUBLISH) clean clean-bin prerequisites build 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 -E
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
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) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE) $(PLUGIN_EXE) $(TEST_TLS_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)
# 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.uptodate
WEAVEEXEC_UPTODATE=.weaveexec.uptodate
PLUGIN_UPTODATE=.plugin.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) $(PLUGIN_UPTODATE) $(BUILD_UPTODATE) $(WEAVEDB_UPTODATE)
IMAGES_UPTODATE=$(WEAVER_UPTODATE) $(WEAVEEXEC_UPTODATE) $(PLUGIN_UPTODATE) $(WEAVEKUBE_UPTODATE) $(WEAVENPC_UPTODATE)
WEAVER_IMAGE=$(DOCKERHUB_USER)/weave
WEAVEEXEC_IMAGE=$(DOCKERHUB_USER)/weaveexec
PLUGIN_IMAGE=$(DOCKERHUB_USER)/plugin
BUILD_IMAGE=$(DOCKERHUB_USER)/weavebuild
# 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) $(PLUGIN_IMAGE) $(WEAVEDB_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.6.2
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."; \
@@ -55,44 +140,52 @@ NETGO_CHECK=@strings $@ | grep cgo_stub\\\.go >/dev/null || { \
echo " sudo go install -tags netgo std"; \
false; \
}
BUILD_FLAGS=-i -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)
exes: $(EXES)
testrunner: $(RUNNER_EXE) $(TEST_TLS_EXE)
$(EXES): $(BUILD_UPTODATE)
$(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
$(WEAVEUTIL_EXE): prog/weaveutil/*.go net/*.go plugin/net/*.go plugin/ipam/*.go db/*.go
$(SIGPROXY_EXE): prog/sigproxy/*.go
$(PLUGIN_EXE): prog/plugin/*.go plugin/*/*.go api/*.go common/*.go common/docker/*.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: $(BUILD_UPTODATE) tools/.git
lint: $(BUILD_UPTODATE) tools/.git
tests: tools/.git
lint: tools/.git
ifeq ($(BUILD_IN_CONTAINER),true)
$(EXES) tests lint:
# 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 -e GOOS -e CIRCLECI -e CIRCLE_BUILD_NUM -e CIRCLE_NODE_TOTAL -e CIRCLE_NODE_INDEX -e COVERDIR -e SLOW \
$(BUILD_IMAGE) COVERAGE=$(COVERAGE) WEAVE_VERSION=$(WEAVE_VERSION) $@
-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)
go build -v $(BUILD_FLAGS) -o $@ ./$(@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
@@ -100,7 +193,7 @@ else
endif
$(NETGO_CHECK)
$(WEAVEUTIL_EXE):
$(WEAVEUTIL_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE):
go build $(BUILD_FLAGS) -o $@ ./$(@D)
$(NETGO_CHECK)
@@ -114,26 +207,48 @@ $(WEAVEWAIT_NOMCAST_EXE):
# 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) $(TEST_TLS_EXE) $(WEAVEWAIT_NOOP_EXE):
$(SIGPROXY_EXE) $(TEST_TLS_EXE) $(WEAVEWAIT_NOOP_EXE) $(RUNNER_EXE) $(MANIFEST_TOOL_EXE):
go build $(BUILD_FLAGS) -o $@ ./$(@D)
tests:
./tools/test -no-go-get
./tools/test -no-go-get -netgo -timeout 8m
lint:
./tools/lint -nocomment -notestpackage .
./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 $@
$(WEAVER_UPTODATE): prog/weaver/Dockerfile $(WEAVER_EXE)
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -t $(WEAVER_IMAGE) prog/weaver
# 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 prog/weaveexec/symlink $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE)
$(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
@@ -141,45 +256,101 @@ $(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile prog/weaveexec/symlink $(DOCKER
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
cp $(WEAVEWAIT_NOMCAST_EXE) prog/weaveexec/weavewait_nomcast
cp $(WEAVEUTIL_EXE) prog/weaveexec/weaveutil
cp $(DOCKER_DISTRIB) prog/weaveexec/docker.tgz
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -t $(WEAVEEXEC_IMAGE) prog/weaveexec
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 $@
$(PLUGIN_UPTODATE): prog/plugin/Dockerfile $(PLUGIN_EXE) $(WEAVEEXEC_UPTODATE)
$(SUDO) docker build -t $(PLUGIN_IMAGE) prog/plugin
$(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)
$(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
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_HOST=$(DOCKER_HOST) docker tag -f $(DOCKERHUB_USER)/$* $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
$(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
# 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_HOST=$(DOCKER_HOST) docker rmi $(IMAGES) $(BUILD_IMAGE)
rm -rf $(EXES) $(IMAGES_UPTODATE) $(WEAVE_EXPORT) .pkg
-$(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
@@ -188,3 +359,20 @@ build:
run-smoketests: all testrunner
cd test && ./setup.sh && ./run_all.sh
integration-tests: all testrunner
# Usage:
# $ make \
# NAME="<prefix used to name VMs and other resources>" \
# PROVIDER="<provider among {vagrant|gcp|aws|do}>" \
# NUM_HOSTS="<# test machines>" \
# PLAYBOOK="<filename>" \
# RUNNER_ARGS="<...>" \
# TESTS="<...>" \ # Can be set to only run one or a few tests instead of the full test suite.
# DOCKER_VERSION=<...> \
# KUBERNETES_VERSION=<...> \
# KUBERNETES_CNI_VERSION=<...> \
# <...> # See also run-integration-test.sh for all variables and individual functions.
# integration-tests
#
RUNNER_ARGS="-parallel" ./test/run-integration-tests.sh
+26 -165
View File
@@ -1,181 +1,42 @@
# 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 delivers the most productive way for developers to connect, observe and control
Docker containers. The first product developed by Weaveworks, with nearly 5 million downloads to date, is Weave Net, enabling users to get started with Docker clusters and portable apps in a fraction of the time compared to other solutions. In addition, Weaveworks offers Weave Scope, a powerful container monitoring tool that automatically maps Docker containers and their interactions, as well as Weave Flux, a microservice router that automates the access of containers as services.
[Weaveworks](https://www.weave.works) is the company that delivers the most productive way for developers to connect, observe and control
Docker containers.
# Introduction
This document is intended to cover some of the more technical aspects of Weave Net. To learn about our products, including getting
started tutorials, visit our [website](http://weave.works) and
[documentation](http://docs.weave.works).
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.
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 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.
# Weave Net
Weave Net creates a virtual network that connects Docker containers
deployed across multiple hosts and enables their automatic discovery.
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 Virtual Network](/docs/virtual-network.png?raw=true "Weave Virtual 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.
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.
## <a name="help"></a>Getting help
![Weave Net Deployment](/docs/deployment.png?raw=true "Weave Net Deployment")
If you have any questions about, feedback for or a problem with Weave Net:
Weave Net can traverse firewalls and operate in partially connected
networks. Traffic can be encrypted, allowing hosts to be connected
across an untrusted network.
- Read [the Weave Net docs](https://www.weave.works/docs/net/latest/introducing-weave/).
- Invite yourself to the <a href="https://weaveworks.github.io/community-slack/" target="_blank"> #weave-community </a> slack channel.
- Ask a question on the <a href="https://weave-community.slack.com/messages/general/"> #weave-community</a> slack channel.
- Join the <a href="https://www.meetup.com/pro/Weave/"> Weave User Group </a> and get invited to online talks, hands-on training and meetups in your area.
- Send an email to <a href="mailto:weave-users@weave.works">weave-users@weave.works</a>
- <a href="https://github.com/weaveworks/weave/issues/new">File an issue.</a>
With Weave Net you can easily construct applications consisting of
multiple containers, running anywhere.
Your feedback is always welcome!
Weave Net works alongside Docker's existing (single host) networking
capabilities, so these can continue to be used by containers.
##Further Information
## Installation
To get started, you should be running Linux (kernel 3.8 or later) and have Docker
(version 1.6.0 or later) installed. Then install Weave Net 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](https://docs.docker.com/installation/mac/#from-your-shell).
Then you can launch Weave Net directly from the OSX host.
For installing Weave Net on other platforms, follow the [integration guides](http://weave.works/product/integrations/).
Weave Net respects the environment variable `DOCKER_HOST`, so you can run
it locally to control a weave network on a remote host.
Weave Net
[periodically contacts Weaveworks servers for available versions](https://github.com/weaveworks/go-checkpoint).
New versions are announced in the log and in
[the status summary](http://docs.weave.works/weave/latest_release/troubleshooting.html#weave-status).
To disable this check, run:
```
export CHECKPOINT_DISABLE=1
```
before launching Weave Net.
## 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 you would 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 Net. The second line configures your environment
so that containers launched via the docker command line are
automatically attached to the weave network. Finally, you run your
application container.
That's it! If your application consists of more than one container on
this host, you can simply launch them with `docker run` as appropriate.
Next you'll 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 weave is being told 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 you could instead have told the Weave Net instance on `$HOST1` to connect to
`$HOST2`, or told both about each other. Order does not matter here;
Weave Net automatically (re)connects to peers when they become
available. You can instruct Weave Net to connect to multiple peers by
supplying multiple addresses, separated by spaces; you can also
[add peers dynamically](http://docs.weave.works/weave/latest_release/features.html#dynamic-topologies).
Weave Net 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 you've got everything set up, let's confirm that your 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 you 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? Please
[file an issue](https://github.com/weaveworks/weave/issues), or post
to the
[Weave Users Google Group](https://groups.google.com/a/weave.works/forum/#!forum/weave-users),
which you can email at weave-users@weave.works. When reporting a bug, please
include which version of Weave Net you are running, as shown by `weave
version`.
Follow us on Twitter:
[@weaveworks](https://twitter.com/weaveworks).
Check out our blog for the latest product and ecosystem news:
[Weaveworks Blog](https://www.weave.works/blog/).
IRC:
[#weavenetwork](https://botbot.me/freenode/weavenetwork/)
* [Installing Weave Net](https://www.weave.works/docs/net/latest/installing-weave/)
* [Weave Net Product Overview](https://www.weave.works/products/weave-net/)
Vendored
+18 -22
View File
@@ -1,40 +1,36 @@
VAGRANTFILE_API_VERSION = "2"
require './vagrant-common.rb'
require File.expand_path(File.join(File.dirname(__FILE__), 'vagrant-common.rb'))
vm_ip = "172.16.0.3" # arbitrary private IP
pkgs = %w(
docker-engine=1.10.2-0~wily
aufs-tools
build-essential
ethtool
iputils-arping
libpcap-dev
git
mercurial
bc
)
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/wily64"
config.vm.box = VAGRANT_IMAGE
config.vm.network "private_network", ip: vm_ip
config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "off"]
vb.customize ["modifyvm", :id, "--natdnsproxy1", "off"]
vb.memory = 2048
configure_nat_dns(vb)
end
# Disable default Vagrant shared folder, which we don't need:
config.vm.synced_folder ".", "/vagrant", disabled: true
# Keep Weave Net sources' in sync:
config.vm.synced_folder ".", "/home/vagrant/src/github.com/weaveworks/weave"
# Create a convenience symlink to $HOME/src/github.com/weaveworks/weave
config.vm.provision :shell, :inline => 'ln -sf ~vagrant/src/github.com/weaveworks/weave ~vagrant/'
install_build_deps config.vm, pkgs
install_go_toochain config.vm
tweak_user_env config.vm
tweak_docker_daemon config.vm
# 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"
# Grant permissions on sources:
config.vm.provision :shell, :inline => 'sudo chown -R vagrant:vagrant ~vagrant/src', :privileged => false
cleanup config.vm
config.vm.provision 'ansible' do |ansible|
ansible.playbook = 'tools/config_management/setup_weave-net_dev.yml'
ansible.extra_vars = {
go_version: GO_VERSION
}.merge(ansibleize(get_dependencies_version_from_file_and_env()))
end
end
begin
+9
View File
@@ -5,6 +5,15 @@ import (
"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 {
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ]; then
cd "$SRCDIR"
git submodule update --init
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
+36
View File
@@ -0,0 +1,36 @@
#!/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
cd "$SRCDIR"
git submodule update --init
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
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
set -e
# Signal failures in lock file, in order to fail fast:
function signal_failure() {
echo "KO" >"$TEST_VMS_READY_LOCK_FILE"
exit 1
}
trap signal_failure ERR
source "$STATE"
source "$(dirname "$0")/wait_for.sh"
if [ -n "$TEST_AND_PUBLISH" ]; then
[ -n "$SECRET_KEY" ] || {
echo "Cannot run smoke tests: no secret key"
exit 1
}
# Provisioning from image typically take 90 seconds,
# but if we are creating a GCP image, it can take more than 10 minutes:
wait_for 900 "$TEST_VMS_PROV_AND_CONF_LOCK_FILE"
# Upload built binaries to testing VMs:
cd "$SRCDIR/test" # Ensures we generate Terraform state files in the right folder, for later use by integration tests.
./run-integration-tests.sh setup >>"$TEST_VMS_SETUP_OUTPUT_FILE" 2>&1
echo "OK" >"$TEST_VMS_READY_LOCK_FILE"
echo "Test VMs now ready. $(date)." >>"$TEST_VMS_SETUP_OUTPUT_FILE"
fi
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
set -e
source "$STATE"
source "$(dirname "$0")/wait_for.sh"
if [ -n "$TEST_AND_PUBLISH" ]; then
[ -n "$SECRET_KEY" ] || {
echo "Cannot run smoke tests: no secret key"
exit 1
}
# Provisioning from image typically take 90 seconds,
# but if we are creating a GCP image, it can take more than 10 minutes:
wait_for 900 "$TEST_VMS_READY_LOCK_FILE"
# Run integration tests:
export COVERAGE=true
export WEAVE_NET_SANITY_CHECKS_FILES="$CIRCLE_ARTIFACTS/weave_net_sanity_check_*.log"
cd "$SRCDIR/test" # Ensures we generate code coverage files in the right folder, and use the Terraform state of previously provisionned VMs.
./run-integration-tests.sh test
fi
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
set -e
source "$STATE"
if [ -n "$TEST_AND_PUBLISH" ] ; then
cd $SRCDIR/test
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
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
set -e
# Signal failures in lock file, in order to fail fast:
function signal_failure() {
echo "KO" >"$TEST_VMS_PROV_AND_CONF_LOCK_FILE"
exit 1
}
trap signal_failure ERR
source "$STATE"
function install_terraform() {
curl -fsS https://releases.hashicorp.com/terraform/0.8.5/terraform_0.8.5_linux_amd64.zip | gunzip >terraform && chmod +x terraform && sudo mv terraform /usr/bin
}
function install_ansible() {
sudo apt-get update || true
sudo apt-get install -qq -y python-pip python-dev libffi-dev libssl-dev && pip install --user -U cffi && pip install --user ansible
export PATH="$PATH:$HOME/.local/bin"
}
if [ -n "$TEST_AND_PUBLISH" ]; then
[ -n "$SECRET_KEY" ] || {
echo "Cannot run smoke tests: no secret key"
exit 1
}
install_terraform >>"$TEST_VMS_SETUP_OUTPUT_FILE" 2>&1
install_ansible >>"$TEST_VMS_SETUP_OUTPUT_FILE" 2>&1
# Only attempt to create GCP image in first container, wait for it to be created otherwise:
[ "$CIRCLE_NODE_INDEX" != "0" ] && export CREATE_IMAGE=0
# Provision and configure testing VMs:
cd "$SRCDIR/test" # Ensures we generate Terraform state files in the right folder, for later use by integration tests.
./run-integration-tests.sh configure >>"$TEST_VMS_SETUP_OUTPUT_FILE" 2>&1
echo "OK" >"$TEST_VMS_PROV_AND_CONF_LOCK_FILE"
echo "Test VMs now provisioned and configured. $(date)." >>"$TEST_VMS_SETUP_OUTPUT_FILE"
fi
+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
+19 -4
View File
@@ -89,6 +89,7 @@ build() {
## Inject the version numbers and build the distributables
## (library versions?)
sed -i "/SCRIPT_VERSION=/ c\SCRIPT_VERSION=\"$VERSION\"" ./weave
sed -i -e "s/:latest/:$VERSION/" -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset.yaml
make SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER
if make tests; then
@@ -157,6 +158,13 @@ draft() {
--name "weave" \
--file "./weave"
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 +173,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 +212,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 +244,13 @@ publish() {
--name "weave" \
--file "./weave"
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
-115
View File
@@ -1,115 +0,0 @@
#!/bin/bash
set -eu
# openssl enc -in do-setup-circleci-secrets.orig -out setup-circleci-secrets.orig -e -aes256 -pass stdin
# openssl base64 < setup-circleci-secrets.orig
openssl base64 -d << EOF \
| openssl enc \
-out bin/do-setup-circleci-secrets \
-d -aes256 -pass pass:$1
U2FsdGVkX1/3QHnDgpZn0srp+GiEQBTlag0CBdsw6Bp6iaIKy6Jy8gFshrsmvl3+
c+7hn1nqsBVpzVH0S5QA3Ex5nx9rl7/dcGoogsySFcwMmBFcauT0UTMK1bvX0Hqx
QrshYSndUkww72KA7EsSnjR1BBJWm3AhCDOTIcnO6nQhig1Fc+SBEj5FGS5xTQ5Z
/8hDsKf54Ms49vOO6QeE5w5ndZ+k7IvVJfq9Evhb7htD20RntDhR86foAwMnLV7R
Wh9qAqI3gnRq0GmbeRKaHmB7pcLq9f0OdScqM/Tn1D+q0556fqJjBziXpZiGbxVs
DxEp8zDJ8yNDAi0Wb2NXjoA79SXJ8Q7iTieaST4y2OmXQpY+Vw8RVDXxi6ERyVnH
41OeMzyLm0qvCoMl32pe1sSG5DRCUiAm7wOtDTVvNDRqmGJYUgwwexyayecJI1wQ
LlhYLJavUvw3UGDZOld8BaMQhfOKBVCdFrjmA4HuVxmOf3029qkgzOCSZiQVNqs+
fvM6J05zBuk+GPy8YInvRkzfxum/x00vmUyGjMs/lHDFfrmYDFK3ux41EoVqvWLG
S5uYxdZJFdR3Xsrs+sMr51XNBQGMmz6KoEEzFYyHs5fZgtdpRdPAuQS1m6FqgZyi
wSz6+EKsALtmGorEp+CF8JN5YzKJCrKzNkg0fILBqsqmJZGP64lmX69950lRLNGM
/l3KVR2zH31b4AnnzTcvldVSCKDXjaMw3JA2Ce/MK6XhOWOcpEv4oDt/62lbhUKP
QUQTPbfpQRvVfBcoIrfAm3ghi/CZc2TDVEuD7DhasLTZD3r7LoK261BWC9O5Wubi
vlXuFIF+uyrpTDf6EJKE/+XywtArppffMP6RkHu1Iqnd8JtsqPaIZsmMmZbjgb6j
BX4ZLb5U9R7jYoSgIke4+u6geFcrMQ+Lny4r7MxXaS0Y1UJ6Jo1bwpYw1TBIobZc
eQ30+xhbSeRC9vEw1NXI6qM2Ai2gIHtAZvEiBkBBXTG5Ld7N/mBAmDIJEzVRxh6F
jRkB3dzESF6eeTBm61OQepwV3aW6lslMaf26drPGv2W2q+K/WOpQOejfggtHUgVs
9SWqtn7hHYSpIASe1Ihi14HAWv3kPhQien0zY1DLKJWf4ilbRaICn1QSJjNuKwtl
A2ZwEw7FFddFcsF4okHPkxEoCre3shq0DEw9UA1gnwEaEF1Q+i9cvLtQg56zK3+R
MfTzFUv2K1z3j1s5tC6Z6LzL8j682EFOll7MkihqiIWh+po1zcNs6Ln0SkjB3v9T
OFRYVJis9GqXYO9PUW1mI69udR4nXbKlBl5tWNyAxn9hufJHLSAmbGMwActKLRM5
kROapKrN1Ra/sHUmhoSSDUK9AXeYKkqPXVMbhly9xC1Kya4hFaFokjRQIMLPmXdQ
lP46RL3HOq0v1BkXg05poSwDm+BtitZkcIhOzcmeucUqn1whsz39y3VoOhJqQu2j
0dUcj19Fue1CDZfwzACb9mLZr643h0yCIHQaVT7is/yiN2vEt0S0zynvOA1D+Xgy
4bFdjqed9DgBShLwF/lh4/hur5iZPpVr9A8rt3Vq0k5A1tdjsZpXP3qv5jLc7lJv
cAQxdVLEuv8WPwwTV/EQsoH7lpoEdjktw/gu0v5PkUgR/WBxEqJq4liTekViQ+8X
BAmdm/FGWeIxSSEm0a8I+muiBpIuKjuQoJit1f0k+lLUohoVDqpDDfeYHh1TxXHE
xSKAKNmFSc2XOr5Zg2mOInxeH7WoxH6iylXKADBgEgAQ4C55DoAPRjFNtGGz2iJl
WkzhQOfgsDss1VxpPZ4SWDQO+xxuuEnYcCYdJ6Tyi5hAwZ0+RZmXx0g9BCK+5qzc
Ffei066kCItBcayekwCs0i86r8JvDtsMUUkzEKDQTSWHpP8ypIZoz3P+Skdqcs6p
IcZHy2fODIsClctRAsHOjZ9BnWSY2rqf1lysqvRfOkNTViTOUVx2hf+LuL+8rT6g
K4GvS39Q+c9FYSMjCNxv1m37NfHJv2W7AlqVV95gMBEFB97M3388T7PfvmSLsyPv
qAKDE7genTOycQvEX9oeEACxPo08ai2Mgs/YXCig0g0btZoScoKPelQKtD0HLpZ+
j7ruaKFy4/vySDMostB3AKSkCE/SkGu/W9oI37n1guSYC/9yJjtTcwZULXAClfwt
LyHvLAw4+7BdGJqDe9Tf8z4zqVLax+BcBHkW7pbP+pvxC6fhIA4PO8k5HwwAVlRw
68lG6e3z9+Vst4zrFLewHJvkDRSOTSecs9h9SPOjReTK0ovlDzMHVakfUvqpk9mv
nCj8SWaMPF70z138AuRuKN7X4exNXPBFnOcseKp/NpT1DyvgoHm/oIO65mq9vvo+
42uSbyyegYiTdVK4SaXBc2hixkhaTteqdEy6GxfWqKCvHtYuRD2LyUSjZn/0Y6CG
3wZapylKL1sxfH+b1gogv2wAA8KtZAfiTlMISuymwQr5RbOFma7UVMVecCa7XrNG
fZwO8R+6++ru0efDzeC/gtLOItjn+yVfsbk2gfu0FikHIV1sogOjnsv3dl6IpH/s
w6WbuK/yZhyrrmhIIueHF30ES512Peogf/Gxp8U/ZAmqBa7p4qsv93XWDR52IPYz
yU1MtboLD02J39daBNrYZuO4Yfo/xAvU7Ijg2KIR9HS0bSWNuSFAZaZXlJ2bSag3
8l0dZMx2fZa0FALxWvY2+nd1tWcH+Wo99RSxX+4TH3guCpe1x/58yKOKL4d1xRpu
02nGaqerV9bHU6WjCUYTrrZurTp6yqivpSFCALDMhAU5Ihd/Qjz69zg4uZ7iqbNd
WqIYJ3SAOei2tSfoOJbdh8mohotnMFFbupck3Fv+lXAXYDp0V/sSuK32MSeJxan1
q3t0eenAh6zoBP0Tj53N8B9YmrgZ1i1AljQqYsAdb8N5Z3vecuzQa946U8H4axEc
BL5fgmqSfsbj1EjJVUrw3cE9hgqeqAYBBvZsyW5zSAsLq/RJKYtBxDGADqr0TOOu
TjVqfPObb1u9EAQj15ALBhhPORa2gBAK5gnhJWW5deNgA0UOYoWARFYfATuQvr1T
9xTVbqzZ0VJR4n7X5JyxJo2tZ44QYVzA0fqX0lt+uRkarrkbZMgplKp4MJTFCp2N
tLciWS0YSHPbKTm7svw5mROazUvEoj1N3SYrJT+Ai9UgSL1cA4FmQ5Jsi+GOeQbH
7E4pzjeST4b1aATY9ZZSy4TzK+UNYBcCVqY1dN5Xnk0e5yPMnrkkcYI41s/6oOaW
lQkp/yrHkvpzQWZa7vF2yWg54j3eX8YWx/TsLvmuJmSQqiIHfu9TXcAIPDispCpF
gp4ZbYPZ8RDQLw3ROc+bZ9E0J8e+FHwgXEELsMLW9n4d3PTj9pLFej1vmBKa03o3
g+JViNxb1gUPNmC6ADk4o7TQzBrjV2pmmuCza16kOmq6oAbJPOeCLtVWA5HJTX8d
AuOzBLO37tWP457dNqoNDaCMik3LCy8cslZjAz02D6VG/QGOAXP9x8bJ3zg9N7vW
EOn1BMtIeMI4yIxpC6HgotNWDNbUBWremAFWYQRgYQqo9L1SdW4hz6X8FqdlBFvK
ml7sdUwjEy2tNW+aiZI4cgAlI/VvMWYr5kPfhvaUu1wGYeS1TD1B+DPcjcXpOGWo
vB1f/uvGc61zZWD0ph9f3S9OnvEko5qV3VhxOnxYUZTrqlM7LVgy/sHrSaPdR7Eo
nb4QGdi5wEGMxVgQlDGwOmEmS5nCaA0RcfHbkQV4SebRleocLB9qcSwj5JzPICAB
sn1qeSv45LnGdTzUnCQErw1EzgrK1FXOknujjZ3GX5dM7a6Gag0E6cAxoQeC8Mh0
aUWolyBo9aSXltn7Vnywoe4X3v96eVH6tUQtN3wt51LBlfSDTWOQDeXLFyW57oYL
/ErbmJLaSHpANBcC9InI+rxNYePTTba7K8rdPDppmMEmdOXjaL+5aPay2Bay9K8T
FUyZdoyrbzxFZYT9/YyVJV/ukVcT9ru3HpzLTg9Vgc/CyRfIvCZY/Gzh+pPUbRsR
pHYDT09BFS+mjszTkcdbceweYXJvknXpajMiISrPUUkb9rwCTmLS4QR4y7I9zAgJ
9U72mCZB9yhhzS17kyKAANihXvOFrMXCO7QTWZbtSkobMBS2SybDxYP3rM5b6824
HQaY4MZW5qCndydfz4fa908XbPTDka9Nu3CZfI3fhGiiGDFWViotGEYE4i9BuGZJ
vmtzII7zeIoHwM4t5fb5mYDd9H+Rkct1yATGEIFEx7cu1fj4Ht2177EzhdkF3Q6I
Fccn43yGDW06nFvEjnjb+Lz4EvtGp6dDefUhNBohdzd4Rm2o+etKobm0lZ1xOX74
2gOGBLfXS6PF+msNkWP76mqKE6hG0+R1iPrN06Arti+ZRBhNGJDp1pnOERl7IyB0
hiLUqae7xVSMVRDeq4O04EUpMXh5ixs3RJXjthYILt7vX+6qskJC3rMuyThrsvMi
Kk0wErDpzR5U7KFnM2fk4jY5by/0b/jHZ/PWFGnaFrXNOiwK/mV1RIJtg5FCrvMv
xJN5Qo7o2ZYzUL+IBf5mP5O49FCnz3e++9r4ySY/K57ybhQft1l+cQPWS7xuvVAg
wZGM9DPl9AhBus0I3V3XzfkcWWHkMynMRcfTnkBHrmKjMopIOggsq05JPalM9b0V
NfwZngVvTFbQejbGjgQQQ+G7spav/icCIA8Iu8JPHaKZt2IX77L1xMcQOouqMrx8
JCXnJ7zsuU+8W3GQGm70H2kcen4bf4beA8TSkFmbVsaqDNtGaG+ZopWO8ctZX3CP
jFgIYgEGi137IWvs1KD5QNFHZI6l0JMzglmvcfnViRPDHLi+EQXAoL/98j/YzA9t
a9L4xMO0oucovKkqYOS2cdFaQKVIUM9L5ibcbW7Tol4ugMo5ibIsTgjZoyFohG6t
acg+h2wTTyxtrIapvOOBeAo9V/iQowTAPQf38LKQZ5tApksiCG1qvJerKALTMp1J
yUHjTCPCPsaiXVVO0mfa9OPtzVvi/icLmlz7umk82mew13djedgMS3/ghq5aEHbg
e7rtI5snFlm/GQnV6IaCDytb+jYxqQ0DZ9Mb0CHcMpnLyiBO6nzHfadpZYlrxrpx
dPx9MVqfLavj1UVjKuVj4Mgec9J38IBBRGMJZ4MGhde2hrw/s2jVzG1BzaIzcvFa
bWiJOkKKRC4BY9DBDYfae5c/obwzkxLmvkbWAVzoFXc+46K1IK6bbC2a4EerOAxc
C7B3X8BucD8OtiPORwXgjctd9AJ7cXq0EEVGoZZ8jkILnklsK6RXsxrT4gSOGFpx
cBU7TF4kHpH+o4KGQmjlFA2VYP1tXirjEep57LOHfL+zy+HiSXdsbexf6odkqLYA
1RR0TzSkmqJYvP0GfHPMvp2xredx1kP934fhTIUcWvErrG3NPd/Dod4BzQye1nNK
8Y8aFYF6fACcD4SFZ11ecK9DJmB+WXGlsxtO3w1LeEysny2lVkkH6HuMRIzPyXAM
/sEpwh3hwPJosAh6vGM6JxuL7CXP8hC1oUvK91VR0hxeDcO/LgdcHtDnlNMqt1wC
jvYt9Hg+3aY5GehBnQPRppnIMaGhiBrRC6HjBg8Umt6UTUr5PXNY2aia5wRcx4M6
Tj0O0dAt8WWZ9ySgzOoq4SRoaAp6m4E7CpRNMgXH031OWEeHqtt8rsYqAcvcQLuW
vIwts5hiXZOfgXyR6SBY3ANE1SjDY46na2G4oiG8FI7eAqYgehjHrXqCnGrzjefE
V1eVcIr7DBYuM8wq7C9x+qdMir6RNV4MrVD+7rO/drivnd3MaqDHlG0LfMZo6GIK
QZGIy0z1W5lOXm9x3RAz7/Ea11ynkZyPDDxBE5NRcV6JfukdjDrvsaQA/Qk2Wo7h
PdUZjv17H4syMdap6tUDTc8Cohut6n1UxnDnhaAYEDGR3TgPqI5vEaJ+yoaM9itv
b2I/K+0uK6GfWwca7PeTtYn92/5etO4czG99xEBFzw7tiEmBTA8KfseZIUe/i3fr
9LO+rKEGalFB4mVTYyCKPYYx4hOIvjdCox/jEBTFyYUEhgGnZvArgw9XabvII7eM
c1FmwnN2CM/MHUzM0Kw7cS/oaoRFcG/PqioO/krL2Bd+xThwSH4Zn+Y1UVO7aXNy
90MOehHSc2nhN984Y2re3ffVsjPhC3KdWxr8jbho/Az65rUkYg64roiO2ZqdqRvf
aYtX9fCe8N8SzgLTlWZt+l8sjY8HP2k9NoajphV1nG4iC/pX0ZJiVQ+VBRNaGhSl
6IhM9gM1ZsI86cULJpOTAhNu1fZBv+Mq8IXYD8SqlNVwVtjvshtlzBN4InSGEKiO
HM7coo7aDuu+Go5AEiIVMbR09jAa0VINsCVScfSbTFhlGRTrZr2DSO/s8WxbV+Mb
EQAfZmyrLF71Z3MfIukg+ps5iuqFhZ+gJSXXSFwumpg=
EOF
exec sh bin/do-setup-circleci-secrets
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# shellcheck disable=SC2155
wait_for() {
local timeout=$1
local lock_file=$2
for i in $(seq 1 "$timeout"); do
if [ -f "$lock_file" ]; then
local status="$(cat "$lock_file")"
if [ "$status" == "OK" ]; then
echo "[$i seconds]: $lock_file found and status: $status." && return
else
echo "[$i seconds]: $lock_file found and status: $status." && return 1
fi
fi
if ! ((i % 10)); then echo "[$i seconds]: Waiting for $lock_file to be created..."; fi
sleep 1
done
echo "Timed out waiting for test VMs to be ready. See details in: $TEST_VMS_SETUP_OUTPUT_FILE" >&2
return 1
}
+82 -6
View File
@@ -1,8 +1,84 @@
FROM golang:1.5.2
ENV GO15VENDOREXPERIMENT 1
RUN apt-get update && apt-get install -y libpcap-dev python-requests time file
RUN go get github.com/golang/lint/golint github.com/fzipp/gocyclo github.com/client9/misspell/cmd/misspell
RUN go clean -i net && go install -tags netgo std
RUN go install -race -tags netgo std
FROM golang:1.7.4
# Support Raspberry Pi 2 and newer
ENV GOARM 7
# The names of the architectures that we're fetching cross-compilers for from the Ubuntu packages
ENV DEB_CROSSPLATFORMS \
armhf \
arm64
# The go platforms we are supporting to cross-compile
ENV GO_CROSSPLATFORMS \
linux/arm \
linux/arm64
# 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 \
gopkg.in/mvdan/sh.v1/cmd/shfmt \
github.com/fatih/hclfmt \
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
# Allow full write access to the Go folders for anyone
RUN chmod -R a+w /usr/local/go
# 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"]
+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
+41 -29
View File
@@ -2,63 +2,75 @@ 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
STATE: /home/ubuntu/state.env
# Base name of VMs for integration tests:
NAME: test-$CIRCLE_BUILD_NUM-$CIRCLE_NODE_INDEX
TEST_VMS_SETUP_OUTPUT_FILE: $CIRCLE_ARTIFACTS/test_vms_setup_output.txt
TEST_VMS_PROV_AND_CONF_LOCK_FILE: $CIRCLE_ARTIFACTS/test_vms_provisioned_and_configured.txt
TEST_VMS_READY_LOCK_FILE: $CIRCLE_ARTIFACTS/test_vms_ready.txt
# Google Cloud Platorm images for integration tests:
USE_IMAGE: 1
DISK_NAME_PREFIX: test-$CIRCLE_BUILD_NUM-0
dependencies:
cache_directories:
- "~/docker"
post:
- "sudo apt-get update && sudo apt-get install bc jq"
- curl https://sdk.cloud.google.com | bash
- bin/setup-circleci-secrets "$SECRET_PASSWORD"
- "mkdir -p $(dirname $SRCDIR) && cp -r $(pwd)/ $SRCDIR"
- "cd $SRCDIR; git submodule update --init"
- cd $SRCDIR/test; ./gce.sh make_template:
parallel: false
- "cd $SRCDIR/build; ../tools/rebuild-image weaveworks/weavebuild . Dockerfile build.sh && touch $SRCDIR/.build.uptodate"
- bin/circle-dependencies-post-sources
# Provision & configure testing VMs:
- "while [ ! -d $SRCDIR ]; do sleep 1; done; $SRCDIR/bin/provision_test_vms.sh":
parallel: true
background: true
- bin/circle-dependencies-post
test:
pre:
- "$SRCDIR/bin/circle-test-pre":
parallel: true
background: true
override:
- cd $SRCDIR; make lint:
- "$SRCDIR/bin/circle-test-unit":
parallel: true
- cd $SRCDIR; COVERDIR=test/coverage make RM= tests:
parallel: true
- cd $SRCDIR; make COVERAGE=true RM= all:
parallel: true
- cd $SRCDIR; make testrunner:
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
post:
- cd $SRCDIR/test; ./gce.sh destroy:
parallel: true
- test "$CIRCLE_NODE_INDEX" != "0" || (cd $SRCDIR/test; ./gen_coverage_reports.sh):
- "$SRCDIR/bin/circle-test-teardown":
parallel: true
teardown:
pre:
- test "$CIRCLE_NODE_INDEX" != "0" || (go get github.com/mattn/goveralls && goveralls -repotoken $COVERALLS_REPO_TOKEN -coverprofile=$SRCDIR/test/profile.cov -service=circleci || true):
# Destroy testing VMs:
- "cd $SRCDIR/test && ./run-integration-tests.sh destroy":
parallel: true
- test "$CIRCLE_NODE_INDEX" != "0" || (cd $SRCDIR/test; cp coverage.* $CIRCLE_ARTIFACTS):
background: true
- "$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 clean-bin
- cd $SRCDIR; make publish
- "$SRCDIR/bin/circle-deploy-master"
issues:
branch: /.*/
owner: weaveworks
commands:
- "$SRCDIR/bin/circle-deploy-issues"
+9
View File
@@ -84,6 +84,15 @@ func (c *Client) Info() string {
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 {
go func() {
+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}
}
-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))
}
+7 -2
View File
@@ -21,8 +21,13 @@ func CreateDatapath(dpname string) (supported bool, err error) {
defer dpif.Close()
dp, err := dpif.CreateDatapath(dpname)
if err != nil && !odp.IsDatapathNameAlreadyExistsError(err) {
return true, err
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
+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 -138
View File
@@ -1,14 +1,6 @@
package common
import (
"fmt"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"net"
"os"
"runtime"
"strings"
)
import "strings"
// Assert test is true, panic otherwise
func Assert(test bool) {
@@ -24,132 +16,3 @@ func ErrorMessages(errors []error) string {
}
return strings.Join(result, "\n")
}
func WithNetNS(ns netns.NsHandle, work func() error) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
oldNs, err := netns.Get()
if err == nil {
defer oldNs.Close()
err = netns.Set(ns)
if err == nil {
defer netns.Set(oldNs)
err = work()
}
}
return err
}
type NetDev struct {
MAC net.HardwareAddr
CIDRs []*net.IPNet
}
// Search the network namespace of a process for interfaces matching a predicate
func FindNetDevs(processID int, match func(link netlink.Link) bool) ([]NetDev, error) {
var netDevs []NetDev
ns, err := netns.GetFromPid(processID)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
defer ns.Close()
err = WithNetNS(ns, func() error {
return forEachLink(func(link netlink.Link) error {
if match(link) {
netDev, err := linkToNetDev(link)
if err != nil {
return err
}
netDevs = append(netDevs, *netDev)
}
return nil
})
})
return netDevs, err
}
func forEachLink(f func(netlink.Link) error) error {
links, err := netlink.LinkList()
if err != nil {
return err
}
for _, link := range links {
if err := f(link); err != nil {
return err
}
}
return nil
}
func linkToNetDev(link netlink.Link) (*NetDev, error) {
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return nil, err
}
netDev := &NetDev{MAC: link.Attrs().HardwareAddr}
for _, addr := range addrs {
netDev.CIDRs = append(netDev.CIDRs, addr.IPNet)
}
return netDev, nil
}
// Lookup the weave interface of a container
func GetWeaveNetDevs(processID int) ([]NetDev, error) {
// Bail out if this container is running in the root namespace
nsToplevel, err := netns.GetFromPid(1)
if err != nil {
return nil, fmt.Errorf("unable to open root namespace: %s", err)
}
nsContainr, err := netns.GetFromPid(processID)
if err != nil {
return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err)
}
if nsToplevel.Equal(nsContainr) {
return nil, nil
}
weaveBridge, err := netlink.LinkByName("weave")
if err != nil {
return nil, fmt.Errorf("Cannot find weave bridge: %s", err)
}
// Scan devices in root namespace to find those attached to weave bridge
indexes := make(map[int]struct{})
err = forEachLink(func(link netlink.Link) error {
if link.Attrs().MasterIndex == weaveBridge.Attrs().Index {
peerIndex := link.Attrs().ParentIndex
if peerIndex == 0 {
// perhaps running on an older kernel where ParentIndex doesn't work.
// as fall-back, assume the indexes are consecutive
peerIndex = link.Attrs().Index - 1
}
indexes[peerIndex] = struct{}{}
}
return nil
})
if err != nil {
return nil, err
}
return FindNetDevs(processID, func(link netlink.Link) bool {
_, isveth := link.(*netlink.Veth)
_, found := indexes[link.Attrs().Index]
return isveth && found
})
}
// Get the weave bridge interface
func GetBridgeNetDev(bridgeName string) ([]NetDev, error) {
return FindNetDevs(1, func(link netlink.Link) bool {
return link.Attrs().Name == bridgeName
})
}
+30 -5
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/gob"
"fmt"
"time"
"github.com/boltdb/bolt"
)
@@ -23,14 +24,39 @@ var (
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)
}
// check the persistence version
err = db.Update(func(tx *bolt.Tx) error {
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
@@ -41,13 +67,12 @@ func NewBoltDB(dbPathname string) (*BoltDB, error) {
} else {
if checkVersion := top.Get(versionIdent); checkVersion != nil {
if checkVersion[0] != persistenceVersion[0] {
return fmt.Errorf("[boltDB] Cannot use persistence file %s - version %x", dbPathname, checkVersion)
return fmt.Errorf("mismatched version %x", checkVersion)
}
}
}
return nil
})
return &BoltDB{db: db}, err
}
}
func (d *BoltDB) Load(ident string, data interface{}) (bool, error) {
+155
View File
@@ -0,0 +1,155 @@
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
32 byte key and 4 byte salt. This combo provides the following security
properties:
* Data confidentiality.
* Data origin authentication.
* Integrity.
* Anti-replay.
* Limited traffic flow confidentiality as fast datapath VXLAN packets are fully
encrypted.
## 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
+2 -2
View File
@@ -52,9 +52,9 @@ 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
interface is statically configured with an MTU of 1376 bytes allowing
it to work with most underlay network provider MTUs, including GCE at
1460 bytes (the fifty byte difference accommodates the vxlan overhead).
1460 bytes (the eighty four byte difference accommodates the encrypted vxlan overhead).
This value can be overridden by setting `WEAVE_MTU` at launch if
necessary.
+22 -6
View File
@@ -65,14 +65,30 @@ peer for space:
- it will continue to ask for space until it receives some, or its
copy of the ring tells it all peers are full in that subnet.
### Data persistence
Key IPAM data is saved to disk, in a [BoltDB](https://github.com/boltdb/bolt)
file, stored within a [data volume container](https://docs.docker.com/engine/userguide/containers/dockervolumes/#creating-and-mounting-a-data-volume-container)
named `weavedb`.
This file is used to persist data for various Weave Net components; for IPAM it contains:
* the division of the IP allocation range amongst peers, and
* allocation of addresses to containers on the local peer,
so that it is immediately available when the peer restarts.
### Claiming an address
If a Weave process is restarted, in most cases it will hear from
another peer which ranges it used to own, but it needs to know which
individual IP addresses are assigned to containers in order to avoid
giving the same address out in subsequent allocation requests. The
weave script invokes the `claim` command in `populate_ipam` to do
this.
If a Weave process is restarted,
- if `weavedb` is present, then it loads persisted IPAM data from there, as
described, in the previous section;
- else, it learns from other peers which ranges it used to own.
Weave Net then consults the allocator to know which individual IP addresses
are assigned to containers, and therefore avoid giving the same address out in
subsequent allocation requests.
When the Allocator is told to claim an address, there are four
possibilities:
+5 -3
View File
@@ -6,8 +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`
* Ensure you are still on the right branch, since Go may switch to `master` as part of `make update`
## Release Types
@@ -133,9 +131,13 @@ Finally, for **Mainline** releases only:
### Finish up
* If not on master, merge branch into master and push to GitHub.
* Merge the branch you are on into `latest_release_doc_updates` 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
+106
View File
@@ -0,0 +1,106 @@
# 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
IPsets are implemented by the kernel module `xt_set`, without which
weave-npc will not work.
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
The above mechanism relies on the kernel module `br_netfilter` being
loaded and enabled via `/proc/sys/net/bridge/bridge-nf-call-iptables`.
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
+5 -4
View File
@@ -3,6 +3,7 @@ package ipam
import (
"fmt"
"github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/net/address"
)
@@ -13,9 +14,9 @@ type allocateResult struct {
type allocate struct {
resultChan chan<- allocateResult
ident string
ident string // a container ID, something like "weave:expose", or api.NoContainerID
r address.CIDR // Subnet we are trying to allocate within
isContainer bool
isContainer bool // true if ident is a container ID
hasBeenCancelled func() bool
}
@@ -33,7 +34,7 @@ func (g *allocate) Try(alloc *Allocator) bool {
return true
}
if !alloc.universe.Overlaps(g.r.Range()) {
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
}
@@ -43,7 +44,7 @@ func (g *allocate) Try(alloc *Allocator) bool {
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 == "_" {
if g.ident == api.NoContainerID {
g.ident = addr.String()
}
alloc.debugln("Allocated", addr, "for", g.ident, "in", g.r)
+152 -63
View File
@@ -14,6 +14,7 @@ import (
"github.com/weaveworks/weave/ipam/paxos"
"github.com/weaveworks/weave/ipam/ring"
"github.com/weaveworks/weave/ipam/space"
"github.com/weaveworks/weave/ipam/tracker"
"github.com/weaveworks/weave/net/address"
)
@@ -55,7 +56,7 @@ type Allocator struct {
stopChan chan<- struct{}
ourName mesh.PeerName
seed []mesh.PeerName // optional user supplied ring seed
universe address.Range // superset of all ranges
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
@@ -75,31 +76,52 @@ type Allocator struct {
now func() time.Time
}
// PreClaims are IP addresses discovered before we could initialize IPAM
type PreClaim struct {
Ident string // a container ID, something like "weave:expose", or api.NoContainerID
IsContainer bool // true if Ident is a container ID
Cidr address.CIDR
}
type Config struct {
OurName mesh.PeerName
OurUID mesh.PeerUID
OurNickname string
Seed []mesh.PeerName
Universe address.Range
Universe address.CIDR
IsObserver bool
PreClaims []PreClaim
Quorum func() uint
Db db.DB
IsKnownPeer func(name mesh.PeerName) bool
Tracker tracker.LocalRangeTracker
}
// NewAllocator creates and initialises a new Allocator
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)
}
return &Allocator{
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.Start, config.Universe.End, config.OurName),
ring: ring.New(config.Universe.Range().Start, config.Universe.Range().End, config.OurName, onUpdate),
owned: make(map[string]ownedData),
db: config.Db,
paxos: participant,
@@ -109,11 +131,48 @@ func NewAllocator(config Config) *Allocator {
dead: make(map[string]time.Time),
now: time.Now,
}
alloc.pendingClaims = make([]operation, len(config.PreClaims))
for i, c := range config.PreClaims {
alloc.pendingClaims[i] = &claim{ident: c.Ident, cidr: c.Cidr}
}
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() {
alloc.loadPersistedData()
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")
}
if loadedPersistedData { // do any pre-claims right away
alloc.tryOps(&alloc.pendingClaims)
}
actionChan := make(chan func(), mesh.ChannelSize)
stopChan := make(chan struct{})
alloc.actionChan = actionChan
@@ -263,7 +322,7 @@ func (alloc *Allocator) Lookup(ident string, r address.Range) ([]address.CIDR, e
}
// Claim an address that we think we should own (Sync)
func (alloc *Allocator) Claim(ident string, cidr address.CIDR, isContainer, 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,
@@ -271,6 +330,7 @@ func (alloc *Allocator) Claim(ident string, cidr address.CIDR, isContainer, noEr
cidr: cidr,
isContainer: isContainer,
noErrorOnUnknown: noErrorOnUnknown,
hasBeenCancelled: hasBeenCancelled,
}
alloc.doOperation(op, &alloc.pendingClaims)
return <-resultChan
@@ -279,7 +339,7 @@ func (alloc *Allocator) Claim(ident string, cidr address.CIDR, isContainer, noEr
// ContainerDied called from the updater interface. Async.
func (alloc *Allocator) ContainerDied(ident string) {
alloc.actionChan <- func() {
if alloc.hasOwned(ident) {
if alloc.hasOwnedByContainer(ident) {
alloc.debugln("Container", ident, "died; noting to remove later")
alloc.dead[ident] = alloc.now()
}
@@ -292,7 +352,7 @@ func (alloc *Allocator) ContainerDied(ident string) {
// ContainerDestroyed called from the updater interface. Async.
func (alloc *Allocator) ContainerDestroyed(ident string) {
alloc.actionChan <- func() {
if alloc.hasOwned(ident) {
if alloc.hasOwnedByContainer(ident) {
alloc.debugln("Container", ident, "destroyed; removing addresses")
alloc.delete(ident)
delete(alloc.dead, ident)
@@ -318,13 +378,13 @@ func (alloc *Allocator) ContainerStarted(ident string) {
}
}
func (alloc *Allocator) AllContainerIDs(ids []string) {
func (alloc *Allocator) PruneOwned(ids []string) {
idmap := make(map[string]struct{}, len(ids))
for _, id := range ids {
idmap[id] = struct{}{}
}
alloc.actionChan <- func() {
idmap := make(map[string]struct{}, len(ids))
for _, id := range ids {
idmap[id] = struct{}{}
}
alloc.syncOwned(idmap)
alloc.pruneOwned(idmap)
}
}
@@ -400,11 +460,12 @@ func (alloc *Allocator) Shutdown() {
alloc.cancelOps(&alloc.pendingClaims)
alloc.cancelOps(&alloc.pendingAllocates)
alloc.cancelOps(&alloc.pendingPrimes)
if heir := alloc.pickPeerForTransfer(); heir != mesh.UnknownPeerName {
alloc.ring.Transfer(alloc.ourName, heir)
alloc.space.Clear()
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{}{}
}
@@ -439,7 +500,7 @@ func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) address.C
}
before := alloc.space.NumFreeAddresses()
alloc.space.AddRanges(newRanges)
alloc.ringUpdated()
after := alloc.space.NumFreeAddresses()
alloc.gossip.GossipBroadcast(alloc.Gossip())
@@ -485,6 +546,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)
@@ -497,9 +574,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
@@ -614,11 +693,13 @@ func (alloc *Allocator) actorLoop(actionChan <-chan func(), stopChan <-chan stru
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.tryPendingOps()
}
alloc.assertInvariants()
@@ -647,8 +728,8 @@ func (alloc *Allocator) establishRing() {
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() {
@@ -727,7 +808,6 @@ 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
@@ -742,9 +822,10 @@ func (alloc *Allocator) update(sender mesh.PeerName, msg []byte) error {
// 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:
switch err = alloc.ring.Merge(*data.Ring); err {
updated, err := alloc.ring.Merge(*data.Ring)
switch err {
case nil:
if !alloc.ring.Empty() {
if updated {
alloc.pruneNicknames()
alloc.ringUpdated()
}
@@ -806,7 +887,6 @@ func (alloc *Allocator) donateSpace(r address.Range, to mesh.PeerName) {
// 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)
@@ -849,19 +929,20 @@ func (alloc *Allocator) reportFreeSpace() {
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"
nameIdent = "peername"
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(nameIdent, alloc.ourName); err != nil {
if err := alloc.db.Save(db.NameIdent, alloc.ourName); err != nil {
alloc.fatalf("Error persisting ring data: %s", err)
return
}
@@ -870,52 +951,57 @@ func (alloc *Allocator) persistRing() {
}
}
func (alloc *Allocator) loadPersistedData() {
// 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(nameIdent, &checkPeerName)
nameFound, err := alloc.db.Load(db.NameIdent, &checkPeerName)
if err != nil {
alloc.fatalf("Error loading persisted peer name: %s", err)
}
ringFound, err := alloc.db.Load(ringIdent, &alloc.ring)
var persistedRing *ring.Ring
ringFound, err := alloc.db.Load(ringIdent, &persistedRing)
if err != nil {
alloc.fatalf("Error loading persisted IPAM data: %s", err)
}
ownedFound, err := alloc.db.Load(ownedIdent, &alloc.owned)
var persistedOwned map[string]ownedData
ownedFound, err := alloc.db.Load(ownedIdent, &persistedOwned)
if err != nil {
alloc.fatalf("Error loading persisted address data: %s", err)
}
if nameFound {
if checkPeerName == alloc.ourName {
if ringFound {
if len(alloc.seed) != 0 {
alloc.infof("Found persisted IPAM data, ignoring supplied IPAM seed")
}
alloc.space.UpdateRanges(alloc.ring.OwnedRanges())
}
if ownedFound {
for _, d := range alloc.owned {
for _, cidr := range d.Cidrs {
alloc.space.Claim(cidr.Addr)
}
}
}
return
}
alloc.infof("Deleting persisted data for peername %s", checkPeerName)
overwritePersisted := func(fmt string, args ...interface{}) {
alloc.infof(fmt, args...)
alloc.persistRing()
alloc.persistOwned()
}
if len(alloc.seed) != 0 {
alloc.infof("Initialising with supplied IPAM seed")
alloc.createRing(alloc.seed)
} else if alloc.paxos.IsElector() {
alloc.infof("Initialising via deferred consensus")
} else {
alloc.infof("Initialising as observer - awaiting IPAM data from another peer")
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() {
@@ -926,9 +1012,9 @@ func (alloc *Allocator) persistOwned() {
// Owned addresses
func (alloc *Allocator) hasOwned(ident string) bool {
_, b := alloc.owned[ident]
return b
func (alloc *Allocator) hasOwnedByContainer(ident string) bool {
d, b := alloc.owned[ident]
return b && d.IsContainer
}
// NB: addr must not be owned by ident already
@@ -986,7 +1072,7 @@ func (alloc *Allocator) findOwner(addr address.Address) string {
}
// For each ID in the 'owned' map, remove the entry if it isn't in the map
func (alloc *Allocator) syncOwned(ids map[string]struct{}) {
func (alloc *Allocator) pruneOwned(ids map[string]struct{}) {
changed := false
for ident, d := range alloc.owned {
if !d.IsContainer {
@@ -1014,6 +1100,9 @@ func (alloc *Allocator) fatalf(fmt string, args ...interface{}) {
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{}) {
alloc.logf(common.Log.Infof, fmt, args...)
}
+60 -27
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"
@@ -41,11 +49,11 @@ func TestAllocFree(t *testing.T) {
cidr2, _ := address.ParseCIDR(subnet2)
alloc.claimRingForTesting()
addr1, err := alloc.Allocate(container1, cidr1, true, returnFalse)
addr1, err := alloc.SimplyAllocate(container1, cidr1)
require.NoError(t, err)
require.Equal(t, testAddr1, addr1.String(), "address")
addr2, err := alloc.Allocate(container1, cidr2, true, returnFalse)
addr2, err := alloc.SimplyAllocate(container1, cidr2)
require.NoError(t, err)
require.Equal(t, testAddr2, addr2.String(), "address")
@@ -54,28 +62,28 @@ func TestAllocFree(t *testing.T) {
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, true, 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, true, returnFalse)
addr1a, _ := alloc.SimplyAllocate(container1, cidr1)
require.Equal(t, testAddr1, addr1a.String(), "address")
addr2a, _ := alloc.Allocate(container1, cidr2, true, 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, true, returnFalse)
addr3, _ := alloc.SimplyAllocate(container3, cidr1)
require.Equal(t, testAddr1, addr3.String(), "address")
addr4, _ := alloc.Allocate(container3, cidr2, true, returnFalse)
addr4, _ := alloc.SimplyAllocate(container3, cidr2)
require.Equal(t, testAddr2, addr4.String(), "address")
alloc.ContainerDied(container2)
// Resurrect
addr1c, err := alloc.Allocate(container2, cidr1, true, returnFalse)
addr1c, err := alloc.SimplyAllocate(container2, cidr1)
require.NoError(t, err)
require.Equal(t, addr1b, addr1c, "address")
@@ -160,41 +168,51 @@ func TestAllocatorClaim(t *testing.T) {
container1 = "abcdef"
container3 = "b01df00d"
universe = "10.0.3.0/24"
testAddr1 = "10.0.3.2/24"
testAddr1 = "10.0.3.5/24"
testAddr2 = "10.0.4.2/24"
testPre = "10.0.3.1/24"
)
allocs, router, subnet := makeNetworkOfAllocators(2, universe)
preAddr, _ := address.ParseCIDR(testPre)
allocs, router, subnet := makeNetworkOfAllocators(2, universe, []PreClaim{{container1, true, preAddr}})
defer stopNetworkOfAllocators(allocs, router)
alloc := allocs[1]
addr1, _ := address.ParseCIDR(testAddr1)
// First claim should trigger "dunno, I'm going to wait"
err := alloc.Claim(container3, addr1, true, true)
err := alloc.SimplyClaim(container3, addr1)
require.NoError(t, err)
alloc.Prime()
// Do an allocate on the other peer, which we will try to claim later
addrx, err := allocs[0].Allocate(container1, subnet, true, returnFalse)
// Should not get the address we pre-claimed
require.NotEqual(t, addrx, preAddr)
router.Flush()
// Now try the claim again
err = alloc.Claim(container3, addr1, true, 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, true, returnFalse)
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, true)
err = alloc.SimplyClaim(container3, addr1)
require.NoError(t, err)
// claim for a different container should fail
err = alloc.Claim(container1, addr1, true, true)
err = alloc.SimplyClaim(container1, addr1)
require.Error(t, err)
// claiming the address allocated on the other peer should fail
err = alloc.Claim(container1, address.MakeCIDR(subnet, addrx), true, true)
err = alloc.SimplyClaim(container1, address.MakeCIDR(subnet, addrx))
require.Error(t, err, "claiming address allocated on other peer should fail")
// claiming the pre-claimed address should fail on both peers
err = alloc.SimplyClaim(container3, preAddr)
require.Error(t, err, "claiming address allocated on other peer should fail")
err = allocs[0].SimplyClaim(container3, preAddr)
require.Error(t, err, "claiming address allocated on other peer should fail")
// Check an address outside of our universe
addr2, _ := address.ParseCIDR(testAddr2)
err = alloc.Claim(container1, addr2, true, true)
err = alloc.SimplyClaim(container1, addr2)
require.NoError(t, err)
}
@@ -211,7 +229,7 @@ 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)
@@ -272,7 +290,7 @@ 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"
)
@@ -314,18 +332,33 @@ func TestGossipShutdown(t *testing.T) {
defer alloc.Stop()
alloc.claimRingForTesting()
alloc.Allocate(container1, subnet, true, returnFalse)
alloc.SimplyAllocate(container1, subnet)
alloc.Shutdown()
_, err := alloc.Allocate(container2, subnet, true, 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)
defer stopNetworkOfAllocators(allocs, router)
alloc0 := allocs[0]
@@ -365,7 +398,7 @@ func TestTransfer(t *testing.T) {
}
func TestFakeRouterSimple(t *testing.T) {
const cidr = "10.0.1.7/22"
const cidr = "10.0.4.0/22"
allocs, router, subnet := makeNetworkOfAllocators(2, cidr)
defer stopNetworkOfAllocators(allocs, router)
@@ -383,7 +416,7 @@ func TestAllocatorFuzz(t *testing.T) {
nodes = 5
maxAddresses = 1000
concurrency = 5
cidr = "10.0.1.7/22"
cidr = "10.0.4.0/22"
)
allocs, router, subnet := makeNetworkOfAllocators(nodes, cidr)
defer stopNetworkOfAllocators(allocs, router)
@@ -453,7 +486,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, true, returnFalse)
addr, err := alloc.SimplyAllocate(name, subnet)
if err != nil {
panic(fmt.Sprintf("Could not allocate addr"))
@@ -510,7 +543,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, true, 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))
@@ -531,7 +564,7 @@ func TestAllocatorFuzz(t *testing.T) {
addressIndex := rand.Int31n(int32(subnet.Size()))
alloc := allocs[allocIndex]
addr := address.Add(subnet.Addr, address.Offset(addressIndex))
err := alloc.Claim(name, address.MakeCIDR(subnet, addr), true, true)
err := alloc.SimplyClaim(name, address.MakeCIDR(subnet, addr))
if err == nil {
noteAllocation(allocIndex, name, addr)
}
+29 -15
View File
@@ -5,16 +5,18 @@ import (
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/net/address"
)
type claim struct {
resultChan chan<- error
ident string
cidr address.CIDR
isContainer bool
noErrorOnUnknown bool
ident string // a container ID, something like "weave:expose", or api.NoContainerID
cidr address.CIDR // single address being claimed
isContainer bool // true if ident is a container ID
noErrorOnUnknown bool // if false, error or block if we don't know; if true return ok but keep trying
hasBeenCancelled func() bool
}
// Send an error (or nil for success) back to caller listening on resultChan
@@ -33,6 +35,11 @@ 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 c.hasBeenCancelled != nil && 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("Address %s claimed by %s - not in our range", c.cidr, c.ident)
@@ -51,11 +58,10 @@ func (c *claim) Try(alloc *Allocator) bool {
// 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.cidr, c.ident)
c.sendResult(nil)
} else {
c.sendResult(fmt.Errorf("%s is in the range %s, but the allocator is not initialized yet", c.cidr, alloc.universe.AsCIDRString()))
}
return false
default:
@@ -73,25 +79,33 @@ 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.cidr.Addr); existingIdent {
case "":
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 == "_" { // Special "I don't have a unique ID" identifier
c.ident = c.cidr.String()
if c.ident == api.NoContainerID {
alloc.addOwned(c.cidr.Addr.String(), c.cidr, c.isContainer)
} else {
alloc.addOwned(c.ident, c.cidr, c.isContainer)
}
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 c.cidr.String():
// Address already allocated via "_" name
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.cidr.String(), existingIdent))
+52 -29
View File
@@ -17,15 +17,17 @@ func badRequest(w http.ResponseWriter, err error) {
}
func parseCIDR(w http.ResponseWriter, cidrStr string, net bool) (address.CIDR, bool) {
cidr, err := address.ParseCIDR(cidrStr)
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 net && !cidr.IsSubnet() {
badRequest(w, fmt.Errorf("Invalid subnet %s - bits after network prefix are not all zero", cidrStr))
return address.CIDR{}, false
}
return cidr, true
}
@@ -38,34 +40,54 @@ func writeAddresses(w http.ResponseWriter, cidrs []address.CIDR) {
}
}
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, checkAlive,
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
}
})
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)
}
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
}
w.WriteHeader(204)
}
// HandleHTTP wires up ipams HTTP endpoints to the provided mux.
func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CIDR, dockerCli *docker.Client) {
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)
})
@@ -73,13 +95,10 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID
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 {
noErrorOnUnknown := r.FormValue("noErrorOnUnknown") == "true"
ident := vars["id"]
checkAlive := r.FormValue("check-alive") == "true"
if err := alloc.Claim(vars["id"], cidr, checkAlive, noErrorOnUnknown); err != nil {
badRequest(w, fmt.Errorf("Unable to claim: %s", err))
return
}
w.WriteHeader(204)
noErrorOnUnknown := r.FormValue("noErrorOnUnknown") == "true"
alloc.handleHTTPClaim(dockerCli, w, ident, cidr, checkAlive, noErrorOnUnknown)
}
})
@@ -155,4 +174,8 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID
transferred := alloc.AdminTakeoverRanges(ident)
fmt.Fprintf(w, "%d IPs taken over from %s\n", transferred, ident)
})
router.Methods("GET").Path("/ipinfo/tracker").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, tracker)
})
}
+1 -1
View File
@@ -43,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 {
+2 -3
View File
@@ -14,8 +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
// Note: Free should perhaps be an address.Count, but we can't change the wire protocol
Free address.Count // Number of free IPs in this range
}
func (e *entry) Equal(e2 *entry) bool {
@@ -23,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)))
}
+131 -81
View File
@@ -18,12 +18,15 @@ import (
"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() {
@@ -38,9 +41,8 @@ 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!")
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 {
@@ -95,27 +97,46 @@ func (r *Ring) checkEntries(entries entries) 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)
@@ -127,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 -----------------
@@ -190,42 +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.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)
@@ -233,59 +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(theirs)
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) {
return errInconsistentEntry(mine, theirs)
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(mine, theirs)
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(theirs)
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 err := r.checkEntries(result); err != nil {
return fmt.Errorf("Merge of incoming data causes: %s", err)
}
if len(r.Seeds) == 0 {
r.Seeds = gossip.Seeds
}
r.Entries = result
return nil
return
}
// Empty returns true if the ring has no entries
@@ -318,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})
}
@@ -350,34 +395,37 @@ func (r *Ring) AllRangeInfo() (result []RangeInfo) {
}
// 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
}
}
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]
@@ -399,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.Count) {
// 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
@@ -432,13 +479,15 @@ func (r *Ring) ReportFree(freespace map[address.Address]address.Count) {
maxSize := r.distance(entry.Token, next.Token)
common.Assert(free <= address.Count(maxSize))
if address.Count(entries[i].Free) == free {
return
if entries[i].Free == free {
continue
}
entries[i].Free = address.Offset(free)
entries[i].Free = free
entries[i].Version++
updated = true
}
return
}
type weightedPeer struct {
@@ -455,7 +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 {
totalSpacePerPeer := make(map[mesh.PeerName]address.Offset)
totalSpacePerPeer := make(map[mesh.PeerName]address.Count)
// iterate through tokens
for i, entry := range r.Entries {
@@ -507,8 +556,9 @@ func (r *Ring) PickPeerForTransfer(isValid func(mesh.PeerName) bool) mesh.PeerNa
// and return ranges indicating the new space we picked up
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
+124 -107
View File
@@ -19,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")
@@ -30,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}}
@@ -42,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")
@@ -51,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() {
@@ -76,7 +86,7 @@ func TestInsert(t *testing.T) {
}
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
@@ -118,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},
@@ -153,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()
@@ -176,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)
@@ -200,48 +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}}
fmt.Println(ring1.Merge(*ring2))
require.Error(t, ring1.Merge(*ring2), "Expected error")
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.Error(t, ring1.Merge(*ring2), "Expected error")
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.Error(t, ring1.Merge(*ring2), "Expected error")
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)
@@ -252,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
@@ -328,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)
@@ -338,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)
@@ -350,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 {
@@ -366,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)
@@ -402,12 +412,12 @@ 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.Count)
for _, r := range ring2.OwnedRanges() {
@@ -417,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")
@@ -426,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())
@@ -465,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}}
@@ -480,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")
@@ -521,17 +531,24 @@ func makePeerName(i int) mesh.PeerName {
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 := dot10
peers := make([]mesh.PeerName, numPeers)
end := dot8
peers := makePeers(numPeers)
// Test for a range of peer counts
for i := 0; i < numPeers; i++ {
peers[i] = makePeerName(i)
ring := New(start, end, peers[0])
ring := NewRing(start, end, peers[0])
ring.ClaimForPeers(peers[:i+1])
}
}
@@ -569,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})
@@ -586,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()
@@ -603,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})
@@ -619,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()
@@ -641,7 +658,7 @@ func TestFuzzRingHard(t *testing.T) {
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++ {
@@ -680,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)
@@ -694,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()
}
}
@@ -723,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()
@@ -742,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()
}
+19 -5
View File
@@ -88,6 +88,14 @@ func (s *Space) Claim(addr address.Address) error {
return nil
}
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 {
@@ -122,8 +130,11 @@ func (s *Space) biggestFreeRange(r address.Range) (biggest address.Range) {
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
})
@@ -137,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, address.Offset(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)
+35 -31
View File
@@ -68,7 +68,7 @@ func TestLowlevel(t *testing.T) {
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()
@@ -78,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")
}
@@ -98,16 +98,19 @@ func TestSpaceAllocate(t *testing.T) {
space1 := makeSpace(start, size)
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.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.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()
@@ -124,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")
}
@@ -149,44 +153,44 @@ func TestSpaceFree(t *testing.T) {
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.22")))
require.NoError(t, space.Free(ip("10.0.3.21")))
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.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.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.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.10") && r.Size() == 4, "Wrong space")
require.Equal(t, address.NewRange(ip("10.0.3.30"), 2), r, "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 (
@@ -199,7 +203,7 @@ 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, "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())
@@ -241,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.Count(24), newRange.Size())
require.Equal(t, address.Count(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)
}
+2
View File
@@ -10,6 +10,7 @@ type Status struct {
Paxos *paxos.Status
Range string
RangeNumIPs int
ActiveIPs int
DefaultSubnet string
Entries []EntryStatus
PendingClaims []ClaimStatus
@@ -52,6 +53,7 @@ func NewStatus(allocator *Allocator, defaultSubnet address.CIDR) *Status {
paxosStatus,
allocator.universe.String(),
int(allocator.universe.Size()),
int(allocator.space.NumOwnedAddresses()),
defaultSubnet.String(),
newEntryStatusSlice(allocator),
newClaimStatusSlice(allocator),
+9 -4
View File
@@ -128,7 +128,7 @@ 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) {
func makeAllocator(name string, cidrStr string, quorum uint, preClaims ...PreClaim) (*Allocator, address.CIDR) {
peername, err := mesh.PeerNameFromString(name)
if err != nil {
panic(err)
@@ -143,8 +143,9 @@ func makeAllocator(name string, cidrStr string, quorum uint) (*Allocator, addres
OurName: peername,
OurUID: mesh.PeerUID(rand.Int63()),
OurNickname: "nick-" + name,
Universe: cidr.Range(),
Universe: cidr,
IsObserver: quorum == 0,
PreClaims: preClaims,
Quorum: func() uint { return quorum },
Db: new(mockDB),
IsKnownPeer: func(mesh.PeerName) bool { return true },
@@ -213,15 +214,19 @@ func AssertNothingSentErr(t *testing.T, ch <-chan error) {
}
}
func makeNetworkOfAllocators(size int, cidr string) ([]*Allocator, *gossip.TestRouter, address.CIDR) {
func makeNetworkOfAllocators(size int, cidr string, preClaims ...[]PreClaim) ([]*Allocator, *gossip.TestRouter, address.CIDR) {
gossipRouter := gossip.NewTestRouter(0.0)
allocs := make([]*Allocator, size)
var subnet address.CIDR
for i := 0; i < size; i++ {
var alloc *Allocator
preClaim := []PreClaim{}
if i < len(preClaims) {
preClaim = preClaims[i]
}
alloc, subnet = makeAllocator(fmt.Sprintf("%02d:00:00:02:00:00", i),
cidr, uint(size/2+1))
cidr, uint(size/2+1), preClaim...)
alloc.SetInterfaces(gossipRouter.Connect(alloc.ourName, alloc))
alloc.Start()
allocs[i] = alloc
+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
}
+77 -24
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,
@@ -173,7 +222,7 @@ func (h *handler) handleReverse(w dns.ResponseWriter, req *dns.Msg) {
return
}
ipStr := strings.TrimSuffix(req.Question[0].Name, "."+reverseDNSdomain)
ipStr := strings.TrimSuffix(strings.ToLower(req.Question[0].Name), "."+reverseDNSdomain)
ip, err := address.ParseIP(ipStr)
if err != nil {
h.nameError(w, req)
@@ -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
+9 -4
View File
@@ -15,17 +15,22 @@ import (
"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
}
+1 -1
View File
@@ -120,7 +120,7 @@ func (e1 *Entry) tombstone() bool {
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)) {
+1 -1
View File
@@ -199,7 +199,7 @@ 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)
}
// Filter to remove entries from unknown peers, done before we take
+2 -1
View File
@@ -36,9 +36,10 @@ func NewStatus(ns *Nameserver, dnsServer *DNSServer) *Status {
entry.Tombstone})
}
upstreamConfig, _ := dnsServer.upstream.Config()
return &Status{
dnsServer.domain,
dnsServer.upstream.Servers,
upstreamConfig.Servers,
dnsServer.address,
dnsServer.ttl,
entryStatusSlice}
+80 -1
View File
@@ -35,6 +35,35 @@ func (r Range) AsCIDRString() string {
return CIDR{Addr: r.Start, PrefixLen: prefixLen}.String()
}
// return the highest bit set in v
// algorithm from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
func msb(v Count) Count {
v |= v >> 1
v |= v >> 2
v |= v >> 4
v |= v >> 8
v |= v >> 16
// Cast to 64-bit to avoid overflow when original v >= 0x80000000
return Count((uint64(v) + 1) / 2)
}
func (r Range) BiggestCIDRRange() Range {
sizeMsb := Offset(msb(r.Size()))
maskedSize := Offset(r.Size()) & (sizeMsb - 1)
maskedStart := Offset(r.Start) & (sizeMsb - 1)
if maskedStart == 0 {
return NewRange(r.Start, sizeMsb)
}
if sizeMsb-maskedStart <= maskedSize {
return NewRange(Add(r.Start, sizeMsb-maskedStart), sizeMsb)
}
size := sizeMsb / 2
if size >= maskedStart {
return NewRange(Add(r.Start, size-maskedStart), size)
}
return NewRange(Add(r.Start, sizeMsb-maskedStart), size)
}
func MakeCIDR(subnet CIDR, addr Address) CIDR {
return CIDR{Addr: addr, PrefixLen: subnet.PrefixLen}
}
@@ -44,6 +73,40 @@ type CIDR struct {
PrefixLen int
}
// CIDRs returns a list of CIDR-aligned ranges which cover this range.
func (r Range) CIDRs() []CIDR {
const (
fullMask = ^Address(0)
cidrMaxPrefixLen = 32
)
var cidrs []CIDR
for start, end := r.Start, r.End-1; end >= start; {
mask, prefixLen := fullMask, cidrMaxPrefixLen
// Find the smallest mask which would cover some part of [start;end].
// Once we found such, apply it by OR'ing
for mask > 0 {
tmpMask := mask << 1
// Check whether mask neither too short nor too long
if (start&tmpMask) != start || (start|^tmpMask) > end {
break
}
mask = tmpMask
prefixLen--
}
cidrs = append(cidrs, CIDR{start, prefixLen})
// Apply mask
start |= ^mask
// Check for overflow
if start+1 < start {
break
}
start++
}
return cidrs
}
func ParseIP(s string) (Address, error) {
if ip := net.ParseIP(s); ip != nil {
return FromIP4(ip), nil
@@ -62,6 +125,22 @@ func ParseCIDR(s string) (CIDR, error) {
}
}
func NewCIDRs(ranges []Range) (cidrs []CIDR) {
for _, r := range ranges {
cidrs = append(cidrs, r.CIDRs()...)
}
return cidrs
}
func (cidr CIDR) Start() Address {
return cidr.Addr
}
// cidr = [Start; End)
func (cidr CIDR) End() Address {
return cidr.Range().End
}
func (cidr CIDR) IsSubnet() bool {
mask := cidr.Size() - 1
return Offset(cidr.Addr)&mask == 0
@@ -122,7 +201,7 @@ func Length(a, b Address) Count {
return Count(a - b)
}
func Min(a, b Offset) Offset {
func Min(a, b Count) Count {
if a > b {
return b
}
+69
View File
@@ -0,0 +1,69 @@
package address
import (
"testing"
"testing/quick"
"github.com/stretchr/testify/require"
)
func isPower2(x Count) bool {
if x == 0 {
return false
}
for ; x > 1; x /= 2 {
if x&1 != 0 {
return false
}
}
return true
}
func TestBiggestPow2AlignedRange(t *testing.T) {
require.Equal(t, NewRange(0, 1), NewRange(0, 1).BiggestCIDRRange())
require.Equal(t, NewRange(1, 1), NewRange(1, 2).BiggestCIDRRange())
require.Equal(t, NewRange(2, 2), NewRange(1, 3).BiggestCIDRRange())
require.Equal(t, NewRange(0, 0x40000000), NewRange(0, 0x7fffffff).BiggestCIDRRange())
require.Equal(t, NewRange(0xfffffffe, 1), NewRange(0xfffffffe, 1).BiggestCIDRRange())
prop := func(start Address, size Offset) bool {
if size > Offset(0xffffffff)-Offset(start) { // out of range
return true
}
r := NewRange(start, size)
result := r.BiggestCIDRRange()
return r.Contains(result.Start) &&
r.Contains(result.End-1) &&
isPower2(result.Size()) &&
result.Size() > r.Size()/4 &&
Count(result.Start)%result.Size() == 0
}
require.NoError(t, quick.Check(prop, &quick.Config{MaxCount: 1000000}))
}
func ip(s string) Address {
addr, _ := ParseIP(s)
return addr
}
func cidr(s string) CIDR {
c, err := ParseCIDR(s)
if err != nil {
panic(err)
}
return c
}
func TestCIDRs(t *testing.T) {
start := ip("10.0.0.1")
end := ip("10.0.0.9")
r := NewRange(start, Subtract(end, start))
require.Equal(t,
[]CIDR{cidr("10.0.0.1/32"), cidr("10.0.0.2/31"), cidr("10.0.0.4/30"), cidr("10.0.0.8/32")},
r.CIDRs())
}
func TestCIDRStartAndEnd(t *testing.T) {
cidr, _ := ParseCIDR("10.0.0.0/24")
require.Equal(t, ip("10.0.0.0"), cidr.Start(), "")
require.Equal(t, ip("10.0.1.0"), cidr.End(), "")
}
+1 -1
View File
@@ -1,4 +1,4 @@
package common
package net
import "fmt"
import "io"
+110
View File
@@ -0,0 +1,110 @@
package net
import (
"fmt"
"net"
"github.com/Sirupsen/logrus"
"github.com/vishvananda/netlink"
)
type BridgeType int
const (
WeaveBridgeName = "weave"
DatapathName = "datapath"
None BridgeType = iota
Bridge
Fastdp
BridgedFastdp
Inconsistent
)
func DetectBridgeType(weaveBridgeName, datapathName string) BridgeType {
bridge, _ := netlink.LinkByName(weaveBridgeName)
datapath, _ := netlink.LinkByName(datapathName)
switch {
case bridge == nil && datapath == nil:
return None
case isBridge(bridge) && datapath == nil:
return Bridge
case isDatapath(bridge) && datapath == nil:
return Fastdp
case isDatapath(datapath) && isBridge(bridge):
return BridgedFastdp
default:
return Inconsistent
}
}
func isBridge(link netlink.Link) bool {
_, isBridge := link.(*netlink.Bridge)
return isBridge
}
func isDatapath(link netlink.Link) bool {
switch link.(type) {
case *netlink.GenericLink:
return link.Type() == "openvswitch"
case *netlink.Device:
// Assume it's our openvswitch device, and the kernel has not been updated to report the kind.
return true
default:
return false
}
}
func DetectHairpin(portIfName string, log *logrus.Logger) error {
link, err := netlink.LinkByName(portIfName)
if err != nil {
return fmt.Errorf("Unable to find link %q: %s", portIfName, err)
}
ch := make(chan netlink.LinkUpdate)
// See EnsureInterface for why done channel is not passed
if err := netlink.LinkSubscribe(ch, nil); err != nil {
return fmt.Errorf("Unable to subscribe to netlink updates: %s", err)
}
pi, err := netlink.LinkGetProtinfo(link)
if err != nil {
return fmt.Errorf("Unable to get link protinfo %q: %s", portIfName, err)
}
if pi.Hairpin {
return fmt.Errorf("Hairpin mode enabled on %q", portIfName)
}
go func() {
for up := range ch {
if up.Attrs().Name == portIfName && up.Attrs().Protinfo != nil &&
up.Attrs().Protinfo.Hairpin {
log.Errorf("Hairpin mode enabled on %q", portIfName)
}
}
}()
return nil
}
var ErrBridgeNoIP = fmt.Errorf("Bridge has no IP address")
func FindBridgeIP(bridgeName string, subnet *net.IPNet) (net.IP, error) {
netdev, err := GetBridgeNetDev(bridgeName)
if err != nil {
return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err)
}
if len(netdev.CIDRs) == 0 {
return nil, ErrBridgeNoIP
}
if subnet != nil {
for _, cidr := range netdev.CIDRs {
if subnet.Contains(cidr.IP) {
return cidr.IP, nil
}
}
}
// No subnet, or none in the required subnet; just return the first one
return netdev.CIDRs[0].IP, nil
}
+60
View File
@@ -0,0 +1,60 @@
package net
import "fmt"
import "syscall"
import "unsafe"
const (
SIOCETHTOOL = 0x8946 // linux/sockios.h
ETHTOOL_GTXCSUM = 0x00000016 // linux/ethtool.h
ETHTOOL_STXCSUM = 0x00000017 // linux/ethtool.h
IFNAMSIZ = 16 // linux/if.h
)
// linux/if.h 'struct ifreq'
type IFReqData struct {
Name [IFNAMSIZ]byte
Data uintptr
}
// linux/ethtool.h 'struct ethtool_value'
type EthtoolValue struct {
Cmd uint32
Data uint32
}
func ioctlEthtool(fd int, argp uintptr) error {
_, _, errno := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(SIOCETHTOOL), argp)
if errno != 0 {
return errno
}
return nil
}
// Disable TX checksum offload on specified interface
func EthtoolTXOff(name string) error {
if len(name)+1 > IFNAMSIZ {
return fmt.Errorf("name too long")
}
socket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
if err != nil {
return err
}
defer syscall.Close(socket)
// Request current value
value := EthtoolValue{Cmd: ETHTOOL_GTXCSUM}
request := IFReqData{Data: uintptr(unsafe.Pointer(&value))}
copy(request.Name[:], name)
if err := ioctlEthtool(socket, uintptr(unsafe.Pointer(&request))); err != nil {
return err
}
if value.Data == 0 { // if already off, don't try to change
return nil
}
value = EthtoolValue{ETHTOOL_STXCSUM, 0}
return ioctlEthtool(socket, uintptr(unsafe.Pointer(&request)))
}
+562
View File
@@ -0,0 +1,562 @@
// package IPsec provides primitives for establishing IPsec in the fastdp mode.
package ipsec
import (
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"fmt"
"io"
"net"
"strconv"
"sync"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/coreos/go-iptables/iptables"
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
"golang.org/x/crypto/hkdf"
"github.com/weaveworks/mesh"
)
const (
keySize = 36 // AES-GCM key 32 bytes + 4 bytes salt
nonceSize = 32 // HKDF nonce size
mark = uint32(0x1) << 17 // iptables marks
markStr = "0x20000/0x20000" // update if the above mark changes
tableMangle = "mangle"
tableFilter = "filter"
chainIn = "WEAVE-IPSEC-IN"
chainInMark = "WEAVE-IPSEC-IN-MARK"
chainOut = "WEAVE-IPSEC-OUT"
chainOutMark = "WEAVE-IPSEC-OUT-MARK"
)
type SPI uint32
// Used to identify:
// - directional SPIs,
// - ipsec establishments.
type spiID [24]byte
func getSPIId(srcPeer, dstPeer mesh.PeerName, connUID uint64) (id spiID) {
binary.BigEndian.PutUint64(id[:], uint64(srcPeer))
binary.BigEndian.PutUint64(id[8:], uint64(dstPeer))
binary.BigEndian.PutUint64(id[16:], connUID)
return
}
type spiInfo struct {
spi SPI
isDirOut bool
}
// IPSec
type IPSec struct {
sync.RWMutex
ipt *iptables.IPTables
log *logrus.Logger
spiInfo map[spiID]spiInfo
// A reference to spiInfo; spiInfo might be of an expired SPI.
spis map[SPI]*spiInfo
}
func New(log *logrus.Logger) (*IPSec, error) {
ipt, err := iptables.New()
if err != nil {
return nil, errors.Wrap(err, "iptables new")
}
ipsec := &IPSec{
ipt: ipt,
log: log,
spiInfo: make(map[spiID]spiInfo),
spis: make(map[SPI]*spiInfo),
}
return ipsec, nil
}
// InitSALocal initializes inbound ipsec from remotePeer and triggers
// the initialization on remotePeer.
func (ipsec *IPSec) InitSALocal(localPeer, remotePeer mesh.PeerName, connUID uint64, localIP, remoteIP net.IP, udpPort int, sessionKey *[32]byte, initRemote func([]byte) error) error {
// ID of inbound SPI
spiID := getSPIId(remotePeer, localPeer, connUID)
ipsec.Lock()
defer ipsec.Unlock()
// Derive SA key
nonce, err := genNonce()
if err != nil {
return errors.Wrap(err, "generate nonce")
}
key, err := deriveKey(sessionKey[:], nonce, localPeer)
if err != nil {
return errors.Wrap(err, "derive key")
}
// Allocate SA
sa, err := netlink.XfrmStateAllocSpi(xfrmAllocSpiState(remoteIP, localIP))
if err != nil {
return errors.Wrap(err, fmt.Sprintf("ip xfrm state allocspi (in, %s, %s)", remoteIP, localIP))
}
// Use SPI generated by the kernel. The kernel ensures {dstIP, spi} to
// be unique.
spi := SPI(sa.Spi)
ipsec.log.Infof("ipsec: InitSALocal: %s -> %s :%d 0x%x", remoteIP, localIP, udpPort, spi)
// Create SA
if sa, err := xfrmState(remoteIP, localIP, spi, false, key); err == nil {
if err := netlink.XfrmStateUpdate(sa); err != nil {
return errors.Wrap(err, fmt.Sprintf("xfrm state update (in, %s, %s, 0x%x)", sa.Src, sa.Dst, sa.Spi))
}
} else {
return errors.Wrap(err, "new xfrm state (in)")
}
// Install iptables rules
if err := ipsec.installDropNonEncrypted(localIP, remoteIP, udpPort, spi); err != nil {
return errors.Wrap(err, fmt.Sprintf("install protecting rules (%s, %s, %d, 0x%x)", localIP, remoteIP, udpPort, spi))
}
si := spiInfo{spi: spi, isDirOut: false}
ipsec.spiInfo[spiID] = si
ipsec.spis[spi] = &si
// Trigger the initialization on the remote peer
msg := &msgInitSARemote{nonce, spi}
if err := initRemote(msg.serialize()); err != nil {
return errors.Wrap(err, "send InitSARemote")
}
return nil
}
// InitSARemote initializes outbound ipsec to remotePeer.
// Triggered by remotePeer.
func (ipsec *IPSec) InitSARemote(msgInitSARemote []byte, localPeer, remotePeer mesh.PeerName, connUID uint64, localIP, remoteIP net.IP, udpPort int, sessionKey *[32]byte) error {
// ID of outbound SPI
spiID := getSPIId(localPeer, remotePeer, connUID)
msg, err := deserializeMsgInitSARemote(msgInitSARemote)
if err != nil {
return errors.Wrap(err, "deserialize InitSARemote")
}
spi := msg.spi
ipsec.Lock()
defer ipsec.Unlock()
ipsec.log.Infof("ipsec: InitSARemote: %s -> %s :%d 0x%x", localIP, remoteIP, udpPort, spi)
// Derive SA key by using the received nonce
key, err := deriveKey(sessionKey[:], msg.nonce, remotePeer)
if err != nil {
return errors.Wrap(err, "derive key")
}
// Create SA
if sa, err := xfrmState(localIP, remoteIP, spi, true, key); err == nil {
if err := netlink.XfrmStateAdd(sa); err != nil {
return errors.Wrap(err, fmt.Sprintf("xfrm state update (out, %s, %s, 0x%x)", sa.Src, sa.Dst, sa.Spi))
}
} else {
return errors.Wrap(err, "new xfrm state (out)")
}
// Create or update SP
sp := xfrmPolicy(localIP, remoteIP, spi)
if err := netlink.XfrmPolicyUpdate(sp); err != nil {
return errors.Wrap(err, fmt.Sprintf("xfrm policy update (%s, %s, 0x%x)", localIP, remoteIP, spi))
}
si := spiInfo{spi: spi, isDirOut: true}
ipsec.spiInfo[spiID] = si
ipsec.spis[spi] = &si
return nil
}
// Destroy destroys any (inbound / outbound) ipsec establishment between the peers.
func (ipsec *IPSec) Destroy(localPeer, remotePeer mesh.PeerName, connUID uint64, localIP, remoteIP net.IP, udpPort int) error {
outSPIID := getSPIId(localPeer, remotePeer, connUID)
inSPIID := getSPIId(remotePeer, localPeer, connUID)
ipsec.Lock()
defer ipsec.Unlock()
// Destroy inbound
if inSPIInfo, ok := ipsec.spiInfo[inSPIID]; ok {
ipsec.log.Infof("ipsec: destroy: in %s -> %s 0x%x", remoteIP, localIP, inSPIInfo.spi)
inSPI := inSPIInfo.spi
inSA := &netlink.XfrmState{
Src: remoteIP,
Dst: localIP,
Proto: netlink.XFRM_PROTO_ESP,
Spi: int(inSPI),
}
if err := netlink.XfrmStateDel(inSA); err != nil {
ipsec.log.Warnf("ipsec: xfrm state del (in, %s, %s, 0x%x) failed: %s", inSA.Src, inSA.Dst, inSA.Spi, err)
}
if err := ipsec.removeDropNonEncrypted(localIP, remoteIP, udpPort, inSPI); err != nil {
ipsec.log.Warnf("ipsec: remove protecting rules (%s, %s, %d, 0x%x) failed: %s", localIP, remoteIP, udpPort, inSPI, err)
}
delete(ipsec.spiInfo, inSPIID)
delete(ipsec.spis, inSPI)
}
// Destroy outbound
if outSPIInfo, ok := ipsec.spiInfo[outSPIID]; ok {
ipsec.log.Infof("ipsec: destroy: out %s -> %s 0x%x", localIP, remoteIP, outSPIInfo.spi)
if err := netlink.XfrmPolicyDel(xfrmPolicy(localIP, remoteIP, outSPIInfo.spi)); err != nil {
ipsec.log.Warnf("ipsec: xfrm policy del (%s, %s, 0x%x) failed: %s", localIP, remoteIP, outSPIInfo.spi, err)
}
outSA := &netlink.XfrmState{
Src: localIP,
Dst: remoteIP,
Proto: netlink.XFRM_PROTO_ESP,
Spi: int(outSPIInfo.spi),
}
if err := netlink.XfrmStateDel(outSA); err != nil {
ipsec.log.Warnf("ipsec: xfrm state del (out, %s, %s, 0x%x) failed: %s", outSA.Src, outSA.Dst, outSA.Spi, err)
}
delete(ipsec.spiInfo, outSPIID)
delete(ipsec.spis, outSPIInfo.spi)
}
return nil
}
// Flush removes all policies/SAs established by us. Also, it removes chains and
// rules of iptables.
//
// If destroy is true, the chains and the rules won't be re-created.
func (ipsec *IPSec) Flush(destroy bool) error {
ipsec.Lock()
defer ipsec.Unlock()
policies, err := netlink.XfrmPolicyList(syscall.AF_INET)
if err != nil {
return errors.Wrap(err, "xfrm policy list")
}
for _, p := range policies {
if p.Mark != nil && p.Mark.Value == mark && len(p.Tmpls) != 0 {
spi := SPI(p.Tmpls[0].Spi)
if err := netlink.XfrmPolicyDel(&p); err != nil {
return errors.Wrap(err, fmt.Sprintf("xfrm policy del (%s, %s, 0x%x)", p.Src, p.Dst, spi))
}
}
}
states, err := netlink.XfrmStateList(syscall.AF_INET)
if err != nil {
return errors.Wrap(err, "xfrm state list")
}
for _, s := range states {
if _, ok := ipsec.spis[SPI(s.Spi)]; ok {
if err := netlink.XfrmStateDel(&s); err != nil {
return errors.Wrap(err, fmt.Sprintf("xfrm state list (%s, %s, 0x%x)", s.Src, s.Dst, s.Spi))
}
}
}
if err := ipsec.resetIPTables(destroy); err != nil {
return errors.Wrap(err, "reset ip tables")
}
return nil
}
// iptables
type chain struct {
table string
chain string
}
type rule struct {
table string
chain string
rulespec []string
unique bool
}
func (ipsec *IPSec) clearChains(chains []chain) error {
for _, c := range chains {
if err := ipsec.ipt.ClearChain(c.table, c.chain); err != nil {
return errors.Wrap(err, fmt.Sprintf("iptables clear chain (%s, %s)", c.table, c.chain))
}
}
return nil
}
func (ipsec *IPSec) deleteChains(chains []chain) error {
for _, c := range chains {
if err := ipsec.ipt.DeleteChain(c.table, c.chain); err != nil {
return errors.Wrap(err, fmt.Sprintf("iptables delete chain (%s, %s)", c.table, c.chain))
}
}
return nil
}
func (ipsec *IPSec) resetRules(rules []rule, destroy bool) error {
for _, r := range rules {
ok, err := ipsec.ipt.Exists(r.table, r.chain, r.rulespec...)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("iptables exists rule (%s, %s, %s)", r.table, r.chain, r.rulespec))
}
switch {
case !destroy && !ok:
if err := ipsec.ipt.Append(r.table, r.chain, r.rulespec...); err != nil {
return errors.Wrap(err, fmt.Sprintf("iptables append rule (%s, %s, %s)", r.table, r.chain, r.rulespec))
}
case destroy && ok:
if err := ipsec.ipt.Delete(r.table, r.chain, r.rulespec...); err != nil {
return errors.Wrap(err, fmt.Sprintf("iptables delete rule (%s, %s, %s)", r.table, r.chain, r.rulespec))
}
}
}
return nil
}
func (ipsec *IPSec) resetIPTables(destroy bool) error {
chains := []chain{
{tableMangle, chainIn},
{tableMangle, chainInMark},
{tableFilter, chainIn},
{tableMangle, chainOut},
{tableMangle, chainOutMark},
}
rules := []rule{
{tableMangle, "INPUT", []string{"-j", chainIn}, true},
{tableMangle, chainInMark, []string{"-j", "MARK", "--set-xmark", markStr}, true},
{tableFilter, "INPUT", []string{"-j", chainIn}, true},
{tableMangle, "OUTPUT", []string{"-j", chainOut}, true},
{tableMangle, chainOutMark, []string{"-j", "MARK", "--set-xmark", markStr}, true},
{tableFilter, "OUTPUT",
[]string{
"!", "-p", "esp",
"-m", "policy", "--dir", "out", "--pol", "none",
"-m", "mark", "--mark", markStr,
"-j", "DROP"}, true},
}
if err := ipsec.clearChains(chains); err != nil {
return err
}
if err := ipsec.resetRules(rules, destroy); err != nil {
return err
}
if destroy {
if err := ipsec.deleteChains(chains); err != nil {
return err
}
}
return nil
}
func ruleMarkInboundESP(srcIP, dstIP net.IP, inSPI SPI) rule {
return rule{tableMangle, chainIn,
[]string{
"-s", dstIP.String(), "-d", srcIP.String(),
"-p", "esp",
"-m", "esp", "--espspi", "0x" + strconv.FormatUint(uint64(inSPI), 16),
"-j", chainInMark,
}, true}
}
func rulesDropNonEncrypted(srcIP, dstIP net.IP, udpPort int, inSPI SPI) []rule {
udpPortStr := strconv.FormatUint(uint64(udpPort), 10)
return []rule{
ruleMarkInboundESP(srcIP, dstIP, inSPI),
{tableFilter, chainIn,
[]string{
"-s", dstIP.String(), "-d", srcIP.String(),
"-p", "udp", "--dport", udpPortStr,
"-m", "mark", "!", "--mark", markStr,
"-j", "DROP",
}, false},
{tableMangle, chainOut,
[]string{
"-s", srcIP.String(), "-d", dstIP.String(),
"-p", "udp", "--dport", udpPortStr,
"-j", chainOutMark,
}, false},
}
}
func (ipsec *IPSec) installDropNonEncrypted(srcIP, dstIP net.IP, udpPort int, inSPI SPI) error {
rules := rulesDropNonEncrypted(srcIP, dstIP, udpPort, inSPI)
for _, r := range rules {
appendFunc := ipsec.ipt.Append
if r.unique {
appendFunc = ipsec.ipt.AppendUnique
}
if err := appendFunc(r.table, r.chain, r.rulespec...); err != nil {
return errors.Wrap(err, fmt.Sprintf("iptables append (%s, %s, %s)", r.table, r.chain, r.rulespec))
}
}
return nil
}
func (ipsec *IPSec) removeDropNonEncrypted(srcIP, dstIP net.IP, udpPort int, inSPI SPI) error {
rules := rulesDropNonEncrypted(srcIP, dstIP, udpPort, inSPI)
if err := ipsec.resetRules(rules, true); err != nil {
return err
}
return nil
}
func (ipsec *IPSec) removeDropNonEncryptedInbound(srcIP, dstIP net.IP, inSPI SPI) error {
r := ruleMarkInboundESP(srcIP, dstIP, inSPI)
if err := ipsec.ipt.Delete(r.table, r.chain, r.rulespec...); err != nil {
return errors.Wrap(err, fmt.Sprintf("iptables delete unique (%s, %s, %s)", r.table, r.chain, r.rulespec))
}
return nil
}
// xfrm
func xfrmAllocSpiState(srcIP, dstIP net.IP) *netlink.XfrmState {
return &netlink.XfrmState{
Src: srcIP,
Dst: dstIP,
Proto: netlink.XFRM_PROTO_ESP,
Mode: netlink.XFRM_MODE_TRANSPORT,
ReplayWindow: 256,
ESN: true,
}
}
func xfrmState(srcIP, dstIP net.IP, spi SPI, isDirOut bool, key []byte) (*netlink.XfrmState, error) {
if len(key) != keySize {
return nil, fmt.Errorf("key should be %d bytes long", keySize)
}
state := xfrmAllocSpiState(srcIP, dstIP)
state.Spi = int(spi)
state.Aead = &netlink.XfrmStateAlgo{
Name: "rfc4106(gcm(aes))",
Key: key,
ICVLen: 128,
}
return state, nil
}
func xfrmPolicy(srcIP, dstIP net.IP, spi SPI) *netlink.XfrmPolicy {
ipMask := []byte{0xff, 0xff, 0xff, 0xff} // /32
return &netlink.XfrmPolicy{
Src: &net.IPNet{IP: srcIP, Mask: ipMask},
Dst: &net.IPNet{IP: dstIP, Mask: ipMask},
Proto: syscall.IPPROTO_UDP,
Dir: netlink.XFRM_DIR_OUT,
Mark: &netlink.XfrmMark{
Value: mark,
Mask: mark,
},
Tmpls: []netlink.XfrmPolicyTmpl{
{
Src: srcIP,
Dst: dstIP,
Proto: netlink.XFRM_PROTO_ESP,
Mode: netlink.XFRM_MODE_TRANSPORT,
Spi: int(spi),
},
},
}
}
// Key derivation
func genNonce() ([]byte, error) {
buf := make([]byte, nonceSize)
n, err := rand.Read(buf)
if err != nil {
return nil, fmt.Errorf("crypto rand failed: %s", err)
}
if n != nonceSize {
return nil, fmt.Errorf("not enough of random data: %d", n)
}
return buf, nil
}
func deriveKey(sessionKey []byte, nonce []byte, peerName mesh.PeerName) ([]byte, error) {
key := make([]byte, keySize)
info := make([]byte, 8)
binary.BigEndian.PutUint64(info, uint64(peerName))
hkdf := hkdf.New(sha256.New, sessionKey, nonce, info)
n, err := io.ReadFull(hkdf, key)
if err != nil {
return nil, err
}
if n != keySize {
return nil, fmt.Errorf("derived too short key: %d", n)
}
return key, nil
}
// Protocol Messages
type msgInitSARemote struct {
nonce []byte
spi SPI
}
func deserializeMsgInitSARemote(b []byte) (*msgInitSARemote, error) {
if len(b) == 0 {
return nil, fmt.Errorf("empty msg")
}
msg := &msgInitSARemote{}
if len(b) != msg.size() {
return nil, fmt.Errorf("invalid payload size: %d", len(b))
}
msg.nonce = make([]byte, nonceSize)
copy(msg.nonce, b[:nonceSize])
b = b[nonceSize:]
msg.spi = SPI(binary.BigEndian.Uint32(b))
return msg, nil
}
func (msg *msgInitSARemote) size() int {
return nonceSize + 32 // SPI
}
func (msg *msgInitSARemote) serialize() []byte {
b := make([]byte, msg.size())
copy(b[:nonceSize], msg.nonce)
binary.BigEndian.PutUint32(b[nonceSize:], uint32(msg.spi))
return b
}
+38
View File
@@ -0,0 +1,38 @@
package net
import (
"crypto/rand"
"crypto/sha256"
"net"
)
func RandomMAC() (net.HardwareAddr, error) {
mac := make([]byte, 6)
if _, err := rand.Read(mac); err != nil {
return nil, err
}
setUnicastAndLocal(mac)
return net.HardwareAddr(mac), nil
}
func MACfromUUID(uuid []byte) net.HardwareAddr {
hash := sha256.New()
// We salt the input just as a precaution to avoid clashes with
// other applications who might have had the bright idea of
// generating MACs in the same way.
hash.Write([]byte("9oBJ0Jmip-"))
hash.Write(uuid)
sum := hash.Sum(nil)
setUnicastAndLocal(sum)
return net.HardwareAddr(sum[:6])
}
// In the first byte of the MAC, the 'multicast' bit should be
// clear and 'locally administered' bit should be set.
func setUnicastAndLocal(mac []byte) {
mac[0] = (mac[0] & 0xFE) | 0x02
}
+116
View File
@@ -0,0 +1,116 @@
package net
import (
"encoding/json"
"fmt"
"net"
"os"
"strconv"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)
type Dev struct {
Name string `json:"Name,omitempty"`
MAC net.HardwareAddr `json:"MAC,omitempty"`
CIDRs []*net.IPNet `json:"CIDRs,omitempty"`
}
func LinkToNetDev(link netlink.Link) (Dev, error) {
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return Dev{}, err
}
netDev := Dev{Name: link.Attrs().Name, MAC: link.Attrs().HardwareAddr}
for _, addr := range addrs {
netDev.CIDRs = append(netDev.CIDRs, addr.IPNet)
}
return netDev, nil
}
// ConnectedToBridgeVethPeerIds returns peer indexes of veth links connected to
// the given bridge. The peer index is used to query from a container netns
// whether the container is connected to the bridge.
func ConnectedToBridgeVethPeerIds(bridgeName string) ([]int, error) {
var ids []int
br, err := netlink.LinkByName(bridgeName)
if err != nil {
return nil, err
}
links, err := netlink.LinkList()
if err != nil {
return nil, err
}
for _, link := range links {
if _, isveth := link.(*netlink.Veth); isveth && link.Attrs().MasterIndex == br.Attrs().Index {
peerID := link.Attrs().ParentIndex
if peerID == 0 {
// perhaps running on an older kernel where ParentIndex doesn't work.
// as fall-back, assume the peers are consecutive
peerID = link.Attrs().Index - 1
}
ids = append(ids, peerID)
}
}
return ids, nil
}
// Lookup the weave interface of a container
func GetWeaveNetDevs(processID int) ([]Dev, error) {
peerIDs, err := ConnectedToBridgeVethPeerIds("weave")
if err != nil {
return nil, err
}
return GetNetDevsByVethPeerIds(processID, peerIDs)
}
func GetNetDevsByVethPeerIds(processID int, peerIDs []int) ([]Dev, error) {
// Bail out if this container is running in the root namespace
netnsRoot, err := netns.GetFromPid(1)
if err != nil {
return nil, fmt.Errorf("unable to open root namespace: %s", err)
}
defer netnsRoot.Close()
netnsContainer, err := netns.GetFromPid(processID)
if err != nil {
// Unable to find a namespace for this process - just return nothing
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err)
}
defer netnsContainer.Close()
if netnsRoot.Equal(netnsContainer) {
return nil, nil
}
var netdevs []Dev
peersStr := make([]string, len(peerIDs))
for i, id := range peerIDs {
peersStr[i] = strconv.Itoa(id)
}
nds, err := WithNetNSByPid(processID, "list-netdevs", peersStr...)
if err != nil {
return nil, fmt.Errorf("list-netdevs failed: %s", err)
}
err = json.Unmarshal(nds, &netdevs)
return netdevs, err
}
// Get the weave bridge interface.
// NB: Should be called from the root network namespace.
func GetBridgeNetDev(bridgeName string) (Dev, error) {
link, err := netlink.LinkByName(bridgeName)
if err != nil {
return Dev{}, err
}
return LinkToNetDev(link)
}
+84
View File
@@ -0,0 +1,84 @@
package net
import (
"bytes"
"errors"
"fmt"
"os/exec"
"runtime"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)
var ErrLinkNotFound = errors.New("Link not found")
// NB: The following function is unsafe, because:
// - It changes a network namespace (netns) of an OS thread which runs
// the function. During execution, the Go runtime might clone a new OS thread
// for scheduling other go-routines, thus they might end up running in
// a "wrong" netns.
// - runtime.LockOSThread does not guarantee that a spawned go-routine on
// the locked thread will be run by it. Thus, the work function is
// not allowed to spawn any go-routine which is dependent on the given netns.
// Please see https://github.com/weaveworks/weave/issues/2388#issuecomment-228365069
// for more details and make sure that you understand the implications before
// using the function!
func WithNetNSUnsafe(ns netns.NsHandle, work func() error) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
oldNs, err := netns.Get()
if err == nil {
defer oldNs.Close()
err = netns.Set(ns)
if err == nil {
defer netns.Set(oldNs)
err = work()
}
}
return err
}
func WithNetNSLinkUnsafe(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error {
return WithNetNSUnsafe(ns, func() error {
link, err := netlink.LinkByName(ifName)
if err != nil {
if err.Error() == errors.New("Link not found").Error() {
return ErrLinkNotFound
}
return err
}
return work(link)
})
}
var WeaveUtilCmd = "weaveutil"
// A safe version of WithNetNS* which creates a process executing
// "nsenter --net=<ns-path> weaveutil <cmd> [args]".
func WithNetNS(nsPath string, cmd string, args ...string) ([]byte, error) {
var stdout, stderr bytes.Buffer
args = append([]string{"--net=" + nsPath, WeaveUtilCmd, cmd}, args...)
c := exec.Command("nsenter", args...)
c.Stdout = &stdout
c.Stderr = &stderr
if err := c.Run(); err != nil {
return nil, fmt.Errorf("%s: %s", string(stderr.Bytes()), err)
}
return stdout.Bytes(), nil
}
func WithNetNSByPid(pid int, cmd string, args ...string) ([]byte, error) {
return WithNetNS(NSPathByPid(pid), cmd, args...)
}
func NSPathByPid(pid int) string {
return fmt.Sprintf("/proc/%d/ns/net", pid)
}
+16 -2
View File
@@ -3,6 +3,7 @@ package net
import (
"fmt"
"net"
"os"
"github.com/vishvananda/netlink"
)
@@ -12,7 +13,7 @@ import (
func CheckNetworkFree(subnet *net.IPNet, ignoreIfaceNames map[string]struct{}) error {
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
if route.Dst != nil && overlaps(route.Dst, subnet) {
return fmt.Errorf("Network %s overlaps with existing route %s on host.", subnet, route.Dst)
return fmt.Errorf("Network %s overlaps with existing route %s on host", subnet, route.Dst)
}
return nil
})
@@ -28,7 +29,7 @@ func overlaps(n1, n2 *net.IPNet) bool {
func CheckAddressOverlap(addr net.IP, ignoreIfaceNames map[string]struct{}) error {
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
if route.Dst != nil && route.Dst.Contains(addr) {
return fmt.Errorf("Address %s overlaps with existing route %s on host.", addr, route.Dst)
return fmt.Errorf("Address %s overlaps with existing route %s on host", addr, route.Dst)
}
return nil
})
@@ -55,3 +56,16 @@ func forEachRoute(ignoreIfaceNames map[string]struct{}, check func(r netlink.Rou
}
return nil
}
func AddRoute(link netlink.Link, scope netlink.Scope, dst *net.IPNet, gw net.IP) error {
err := netlink.RouteAdd(&netlink.Route{
LinkIndex: link.Attrs().Index,
Scope: scope,
Dst: dst,
Gw: gw,
})
if os.IsExist(err) { // squash duplicate route errors
err = nil
}
return err
}
+84
View File
@@ -0,0 +1,84 @@
package net
import (
"errors"
"io/ioutil"
"net"
"os"
"github.com/weaveworks/mesh"
"github.com/weaveworks/weave/db"
)
func getOldStyleSystemUUID() ([]byte, error) {
uuid, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid")
if os.IsNotExist(err) {
uuid, err = ioutil.ReadFile("/sys/hypervisor/uuid")
}
return uuid, err
}
func getSystemUUID(hostRoot string) ([]byte, error) {
uuid, err := getOldStyleSystemUUID()
if err != nil && !os.IsNotExist(err) {
return nil, err
}
machineid, err := ioutil.ReadFile(hostRoot + "/etc/machine-id")
if os.IsNotExist(err) {
machineid, err = ioutil.ReadFile(hostRoot + "/var/lib/dbus/machine-id")
}
if err != nil && !os.IsNotExist(err) {
return nil, err
}
if len(uuid) == 0 && len(machineid) == 0 {
return nil, errors.New("All system IDs are blank")
}
return append(machineid, uuid...), nil
}
func getPersistedPeerName(pathName string) (mesh.PeerName, error) {
d, err := db.NewBoltDBReadOnly(pathName)
if err != nil {
return mesh.UnknownPeerName, err
}
defer d.Close()
var peerName mesh.PeerName
nameFound, err := d.Load(db.NameIdent, &peerName)
if err != nil || !nameFound {
return mesh.UnknownPeerName, err
}
return peerName, nil
}
// GetSystemPeerName returns an ID derived from concatenated machine-id
// (either systemd or dbus), the system (aka bios) UUID and the
// hypervisor UUID. It is tweaked and formatted to be usable as a mac address
func GetSystemPeerName(dbPrefix, hostRoot string) (string, error) {
// Check if we have a persisted name that matches the old-style ID for this host
if oldUUID, err := getOldStyleSystemUUID(); err == nil {
pathName := dbPrefix + db.FileName
if _, err := os.Stat(pathName); err == nil {
persistedPeerName, err := getPersistedPeerName(pathName)
if err != nil && !os.IsNotExist(err) {
return "", err
}
if persistedPeerName == mesh.PeerNameFromBin(MACfromUUID(oldUUID)) {
return persistedPeerName.String(), nil
}
}
} else if !os.IsNotExist(err) {
return "", err
}
var mac net.HardwareAddr
if uuid, err := getSystemUUID(hostRoot); err == nil {
mac = MACfromUUID(uuid)
} else if !os.IsNotExist(err) {
return "", err
} else {
mac, err = RandomMAC()
if err != nil {
return "", err
}
}
return mac.String(), nil
}
+310
View File
@@ -0,0 +1,310 @@
package net
import (
"fmt"
"net"
"strings"
"syscall"
"time"
"github.com/coreos/go-iptables/iptables"
"github.com/j-keck/arping"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"github.com/weaveworks/weave/common/odp"
)
// create and attach a veth to the Weave bridge
func CreateAndAttachVeth(name, peerName, bridgeName string, mtu int, keepTXOn bool, init func(peer netlink.Link) error) (*netlink.Veth, error) {
bridge, err := netlink.LinkByName(bridgeName)
if err != nil {
return nil, fmt.Errorf(`bridge "%s" not present; did you launch weave?`, bridgeName)
}
if mtu == 0 {
mtu = bridge.Attrs().MTU
}
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: name,
MTU: mtu},
PeerName: peerName,
}
if err := netlink.LinkAdd(veth); err != nil {
return nil, fmt.Errorf(`could not create veth pair %s-%s: %s`, name, peerName, err)
}
cleanup := func(format string, a ...interface{}) (*netlink.Veth, error) {
netlink.LinkDel(veth)
return nil, fmt.Errorf(format, a...)
}
switch bridgeType := DetectBridgeType(bridgeName, DatapathName); bridgeType {
case Bridge, BridgedFastdp:
if err := netlink.LinkSetMasterByIndex(veth, bridge.Attrs().Index); err != nil {
return cleanup(`unable to set master of %s: %s`, name, err)
}
if bridgeType == Bridge && !keepTXOn {
if err := EthtoolTXOff(peerName); err != nil {
return cleanup(`unable to set tx off on %q: %s`, peerName, err)
}
}
case Fastdp:
if err := odp.AddDatapathInterface(bridgeName, name); err != nil {
return cleanup(`failed to attach %s to device "%s": %s`, name, bridgeName, err)
}
default:
return cleanup(`invalid bridge configuration`)
}
if init != nil {
peer, err := netlink.LinkByName(peerName)
if err != nil {
return cleanup("unable to find peer veth %s: %s", peerName, err)
}
if err := init(peer); err != nil {
return cleanup("initializing veth: %s", err)
}
}
if err := netlink.LinkSetUp(veth); err != nil {
return cleanup("unable to bring veth up: %s", err)
}
return veth, nil
}
func AddAddresses(link netlink.Link, cidrs []*net.IPNet) (newAddrs []*net.IPNet, err error) {
existingAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return nil, fmt.Errorf("failed to get IP address for %q: %v", link.Attrs().Name, err)
}
for _, ipnet := range cidrs {
if contains(existingAddrs, ipnet) {
continue
}
if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: ipnet}); err != nil {
return nil, fmt.Errorf("failed to add IP address to %q: %v", link.Attrs().Name, err)
}
newAddrs = append(newAddrs, ipnet)
}
return newAddrs, nil
}
func contains(addrs []netlink.Addr, addr *net.IPNet) bool {
for _, x := range addrs {
if addr.IP.Equal(x.IPNet.IP) {
return true
}
}
return false
}
const (
VethName = "ethwe" // name inside container namespace
vethPrefix = "v" + VethName // starts with "veth" to suppress UI notifications
)
func interfaceExistsInNamespace(netNSPath string, ifName string) bool {
_, err := WithNetNS(netNSPath, "check-iface", ifName)
return err == nil
}
// NB: This function can be used only by a process that terminates immediately
// after calling the function as it changes netns via WithNetNSLinkUnsafe.
func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet, keepTXOn bool) error {
ns, err := netns.GetFromPath(netNSPath)
if err != nil {
return err
}
defer ns.Close()
ipt, err := iptables.New()
if err != nil {
return err
}
if !interfaceExistsInNamespace(netNSPath, ifName) {
maxIDLen := IFNAMSIZ - 1 - len(vethPrefix+"pl")
if len(id) > maxIDLen {
id = id[:maxIDLen] // trim passed ID if too long
}
name, peerName := vethPrefix+"pl"+id, vethPrefix+"pg"+id
_, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, keepTXOn, func(veth netlink.Link) error {
if err := netlink.LinkSetNsFd(veth, int(ns)); err != nil {
return fmt.Errorf("failed to move veth to container netns: %s", err)
}
if _, err := WithNetNS(netNSPath, "setup-iface", peerName, ifName); err != nil {
return fmt.Errorf("error setting up interface: %s", err)
}
return nil
})
if err != nil {
return err
}
}
if err := WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error {
newAddresses, err := AddAddresses(veth, cidrs)
if err != nil {
return err
}
// Add multicast ACCEPT rules for new subnets
for _, ipnet := range newAddresses {
acceptRule := []string{"-i", ifName, "-s", subnet(ipnet), "-d", "224.0.0.0/4", "-j", "ACCEPT"}
exists, err := ipt.Exists("filter", "INPUT", acceptRule...)
if err != nil {
return err
}
if !exists {
if err := ipt.Insert("filter", "INPUT", 1, acceptRule...); err != nil {
return err
}
}
}
if err := netlink.LinkSetUp(veth); err != nil {
return err
}
for _, ipnet := range newAddresses {
// If we don't wait for a bit here, we see the arp fail to reach the bridge.
time.Sleep(1 * time.Millisecond)
arping.GratuitousArpOverIfaceByName(ipnet.IP, ifName)
}
if withMulticastRoute {
/* Route multicast packets across the weave network.
This must come last in 'attach'. If you change this, change weavewait to match.
TODO: Add the MTU lock to prevent PMTU discovery for multicast
destinations. Without that, the kernel sets the DF flag on
multicast packets. Since RFC1122 prohibits sending of ICMP
errors for packets with multicast destinations, that causes
packets larger than the PMTU to be dropped silently. */
_, multicast, _ := net.ParseCIDR("224.0.0.0/4")
if err := AddRoute(veth, netlink.SCOPE_LINK, multicast, nil); err != nil {
return err
}
}
return nil
}); err != nil {
return err
}
return nil
}
// NB: This function can be used only by a process that terminates immediately
// after calling the function as it changes netns via WithNetNSLinkUnsafe.
func DetachContainer(netNSPath, id, ifName string, cidrs []*net.IPNet) error {
ns, err := netns.GetFromPath(netNSPath)
if err != nil {
return err
}
defer ns.Close()
ipt, err := iptables.New()
if err != nil {
return err
}
return WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error {
existingAddrs, err := netlink.AddrList(veth, netlink.FAMILY_V4)
if err != nil {
return fmt.Errorf("failed to get IP address for %q: %v", veth.Attrs().Name, err)
}
for _, ipnet := range cidrs {
if !contains(existingAddrs, ipnet) {
continue
}
if err := netlink.AddrDel(veth, &netlink.Addr{IPNet: ipnet}); err != nil {
return fmt.Errorf("failed to remove IP address from %q: %v", veth.Attrs().Name, err)
}
}
addrs, err := netlink.AddrList(veth, netlink.FAMILY_V4)
if err != nil {
return fmt.Errorf("failed to get IP address for %q: %v", veth.Attrs().Name, err)
}
// Remove multicast ACCEPT rules for subnets we no longer have addresses in
subnets := subnets(addrs)
rules, err := ipt.List("filter", "INPUT")
if err != nil {
return err
}
for _, rule := range rules {
ps := strings.Split(rule, " ")
if len(ps) == 10 &&
ps[0] == "-A" && ps[2] == "-s" && ps[4] == "-d" && ps[5] == "224.0.0.0/4" &&
ps[6] == "-i" && ps[7] == ifName && ps[8] == "-j" && ps[9] == "ACCEPT" {
if _, found := subnets[ps[3]]; !found {
if err := ipt.Delete("filter", "INPUT", ps[2:]...); err != nil {
return err
}
}
}
}
if len(addrs) == 0 { // all addresses gone: remove the interface
if err := ipt.Delete("filter", "INPUT", "-i", ifName, "-d", "224.0.0.0/4", "-j", "DROP"); err != nil {
return err
}
if err := netlink.LinkDel(veth); err != nil {
return err
}
}
return nil
})
}
func subnet(ipn *net.IPNet) string {
ones, _ := ipn.Mask.Size()
return fmt.Sprintf("%s/%d", ipn.IP.Mask(ipn.Mask).String(), ones)
}
func subnets(addrs []netlink.Addr) map[string]struct{} {
subnets := make(map[string]struct{})
for _, addr := range addrs {
subnets[subnet(addr.IPNet)] = struct{}{}
}
return subnets
}
func addNatRule(ipt *iptables.IPTables, rulespec ...string) error {
// Loop until we get an exit code other than "temporarily unavailable"
for {
if err := ipt.AppendUnique("nat", "WEAVE", rulespec...); err != nil {
if ierr, ok := err.(*iptables.Error); ok {
if status, ok := ierr.ExitError.Sys().(syscall.WaitStatus); ok {
// (magic exit code 4 found in iptables source code; undocumented)
if status.ExitStatus() == 4 {
continue
}
}
}
return err
}
return nil
}
}
func ExposeNAT(ipnet net.IPNet) error {
ipt, err := iptables.New()
if err != nil {
return err
}
cidr := ipnet.String()
if err := addNatRule(ipt, "-s", cidr, "-d", "224.0.0.0/4", "-j", "RETURN"); err != nil {
return err
}
if err := addNatRule(ipt, "-d", cidr, "!", "-s", cidr, "-j", "MASQUERADE"); err != nil {
return err
}
if err := addNatRule(ipt, "-s", cidr, "!", "-d", cidr, "-j", "MASQUERADE"); err != nil {
return err
}
return nil
}
+114
View File
@@ -0,0 +1,114 @@
package npc
import (
"fmt"
"k8s.io/client-go/pkg/api"
extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/pkg/util/intstr"
"github.com/weaveworks/weave/npc/ipset"
)
func (ns *ns) analysePolicy(policy *extnapi.NetworkPolicy) (
rules map[string]*ruleSpec,
nsSelectors, podSelectors map[string]*selectorSpec,
err error) {
nsSelectors = make(map[string]*selectorSpec)
podSelectors = make(map[string]*selectorSpec)
rules = make(map[string]*ruleSpec)
dstSelector, err := newSelectorSpec(&policy.Spec.PodSelector, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, err
}
podSelectors[dstSelector.key] = dstSelector
for _, ingressRule := range policy.Spec.Ingress {
if ingressRule.Ports != nil && len(ingressRule.Ports) == 0 {
// Ports is empty, this rule matches no ports (no traffic matches).
continue
}
if ingressRule.From != nil && len(ingressRule.From) == 0 {
// From is empty, this rule matches no sources (no traffic matches).
continue
}
if ingressRule.From == nil {
// From is not provided, this rule matches all sources (traffic not restricted by source).
if ingressRule.Ports == nil {
// Ports is not provided, this rule matches all ports (traffic not restricted by port).
rule := newRuleSpec(nil, nil, dstSelector, nil)
rules[rule.key] = rule
} else {
// Ports is present and contains at least one item, then this rule allows traffic
// only if the traffic matches at least one port in the ports list.
withNormalisedProtoAndPort(ingressRule.Ports, func(proto, port string) {
rule := newRuleSpec(&proto, nil, dstSelector, &port)
rules[rule.key] = rule
})
}
} else {
// From is present and contains at least on item, this rule allows traffic only if the
// traffic matches at least one item in the from list.
for _, peer := range ingressRule.From {
var srcSelector *selectorSpec
if peer.PodSelector != nil {
srcSelector, err = newSelectorSpec(peer.PodSelector, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, err
}
podSelectors[srcSelector.key] = srcSelector
}
if peer.NamespaceSelector != nil {
srcSelector, err = newSelectorSpec(peer.NamespaceSelector, "", ipset.ListSet)
if err != nil {
return nil, nil, nil, err
}
nsSelectors[srcSelector.key] = srcSelector
}
if ingressRule.Ports == nil {
// Ports is not provided, this rule matches all ports (traffic not restricted by port).
rule := newRuleSpec(nil, srcSelector, dstSelector, nil)
rules[rule.key] = rule
} else {
// Ports is present and contains at least one item, then this rule allows traffic
// only if the traffic matches at least one port in the ports list.
withNormalisedProtoAndPort(ingressRule.Ports, func(proto, port string) {
rule := newRuleSpec(&proto, srcSelector, dstSelector, &port)
rules[rule.key] = rule
})
}
}
}
}
return rules, nsSelectors, podSelectors, nil
}
func withNormalisedProtoAndPort(npps []extnapi.NetworkPolicyPort, f func(proto, port string)) {
for _, npp := range npps {
// If no proto is specified, default to TCP
proto := string(api.ProtocolTCP)
if npp.Protocol != nil {
proto = string(*npp.Protocol)
}
// If no port is specified, match any port. Let iptables executable handle
// service name resolution
port := "0:65535"
if npp.Port != nil {
switch npp.Port.Type {
case intstr.Int:
port = fmt.Sprintf("%d", npp.Port.IntVal)
case intstr.String:
port = npp.Port.StrVal
}
}
f(proto, port)
}
}
+40
View File
@@ -0,0 +1,40 @@
package npc
// These types are defined in https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/network-policy.md
// but not in the k8s API yet. Copies are included here for decoding the `net.beta.kubernetes.io/network-policy`
// annotation specified in the above document.
type IngressIsolationPolicy string
const (
// Deny all ingress traffic to pods in this namespace. Ingress means
// any incoming traffic to pods, whether that be from other pods within this namespace
// or any source outside of this namespace.
DefaultDeny IngressIsolationPolicy = "DefaultDeny"
)
// Standard NamespaceSpec object, modified to include a new
// NamespaceNetworkPolicy field.
type NamespaceSpec struct {
// This is a pointer so that it can be left undefined.
NetworkPolicy *NamespaceNetworkPolicy `json:"networkPolicy,omitempty"`
}
type NamespaceNetworkPolicy struct {
// Ingress configuration for this namespace. This config is
// applied to all pods within this namespace. For now, only
// ingress is supported. This field is optional - if not
// defined, then the cluster default for ingress is applied.
Ingress *NamespaceIngressPolicy `json:"ingress,omitempty"`
}
// Configuration for ingress to pods within this namespace.
// For now, this only supports specifying an isolation policy.
type NamespaceIngressPolicy struct {
// The isolation policy to apply to pods in this namespace.
// Currently this field only supports "DefaultDeny", but could
// be extended to support other policies in the future. When set to DefaultDeny,
// pods in this namespace are denied ingress traffic by default. When not defined,
// the cluster default ingress isolation policy is applied (currently allow all).
Isolation *IngressIsolationPolicy `json:"isolation,omitempty"`
}
+9
View File
@@ -0,0 +1,9 @@
package npc
const (
TableFilter = "filter"
MainChain = "WEAVE-NPC"
DefaultChain = "WEAVE-NPC-DEFAULT"
IngressChain = "WEAVE-NPC-INGRESS"
)
+173
View File
@@ -0,0 +1,173 @@
package npc
import (
"sync"
"github.com/coreos/go-iptables/iptables"
"github.com/pkg/errors"
coreapi "k8s.io/client-go/pkg/api/v1"
extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/ipset"
)
type NetworkPolicyController interface {
AddNamespace(ns *coreapi.Namespace) error
UpdateNamespace(oldObj, newObj *coreapi.Namespace) error
DeleteNamespace(ns *coreapi.Namespace) error
AddPod(obj *coreapi.Pod) error
UpdatePod(oldObj, newObj *coreapi.Pod) error
DeletePod(obj *coreapi.Pod) error
AddNetworkPolicy(obj *extnapi.NetworkPolicy) error
UpdateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error
DeleteNetworkPolicy(obj *extnapi.NetworkPolicy) error
}
type controller struct {
sync.Mutex
ipt *iptables.IPTables
ips ipset.Interface
nss map[string]*ns // ns name -> ns struct
nsSelectors *selectorSet // selector string -> nsSelector
}
func New(ipt *iptables.IPTables, ips ipset.Interface) NetworkPolicyController {
c := &controller{
ipt: ipt,
ips: ips,
nss: make(map[string]*ns)}
c.nsSelectors = newSelectorSet(ips, c.onNewNsSelector)
return c
}
func (npc *controller) onNewNsSelector(selector *selector) error {
for _, ns := range npc.nss {
if ns.namespace != nil {
if selector.matches(ns.namespace.ObjectMeta.Labels) {
if err := ns.ips.AddEntry(selector.spec.ipsetName, string(ns.allPods.ipsetName)); err != nil {
return err
}
}
}
}
return nil
}
func (npc *controller) withNS(name string, f func(ns *ns) error) error {
ns, found := npc.nss[name]
if !found {
newNs, err := newNS(name, npc.ipt, npc.ips, npc.nsSelectors)
if err != nil {
return err
}
npc.nss[name] = newNs
ns = newNs
}
if err := f(ns); err != nil {
return err
}
if ns.empty() {
if err := ns.destroy(); err != nil {
return err
}
delete(npc.nss, name)
}
return nil
}
func (npc *controller) AddPod(obj *coreapi.Pod) error {
npc.Lock()
defer npc.Unlock()
common.Log.Debugf("EVENT AddPod %s", js(obj))
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
return errors.Wrap(ns.addPod(obj), "add pod")
})
}
func (npc *controller) UpdatePod(oldObj, newObj *coreapi.Pod) error {
npc.Lock()
defer npc.Unlock()
common.Log.Debugf("EVENT UpdatePod %s %s", js(oldObj), js(newObj))
return npc.withNS(oldObj.ObjectMeta.Namespace, func(ns *ns) error {
return errors.Wrap(ns.updatePod(oldObj, newObj), "update pod")
})
}
func (npc *controller) DeletePod(obj *coreapi.Pod) error {
npc.Lock()
defer npc.Unlock()
common.Log.Debugf("EVENT DeletePod %s", js(obj))
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
return errors.Wrap(ns.deletePod(obj), "delete pod")
})
}
func (npc *controller) AddNetworkPolicy(obj *extnapi.NetworkPolicy) error {
npc.Lock()
defer npc.Unlock()
common.Log.Infof("EVENT AddNetworkPolicy %s", js(obj))
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
return errors.Wrap(ns.addNetworkPolicy(obj), "add network policy")
})
}
func (npc *controller) UpdateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error {
npc.Lock()
defer npc.Unlock()
common.Log.Infof("EVENT UpdateNetworkPolicy %s %s", js(oldObj), js(newObj))
return npc.withNS(oldObj.ObjectMeta.Namespace, func(ns *ns) error {
return errors.Wrap(ns.updateNetworkPolicy(oldObj, newObj), "update network policy")
})
}
func (npc *controller) DeleteNetworkPolicy(obj *extnapi.NetworkPolicy) error {
npc.Lock()
defer npc.Unlock()
common.Log.Infof("EVENT DeleteNetworkPolicy %s", js(obj))
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
return errors.Wrap(ns.deleteNetworkPolicy(obj), "delete network policy")
})
}
func (npc *controller) AddNamespace(obj *coreapi.Namespace) error {
npc.Lock()
defer npc.Unlock()
common.Log.Infof("EVENT AddNamespace %s", js(obj))
return npc.withNS(obj.ObjectMeta.Name, func(ns *ns) error {
return errors.Wrap(ns.addNamespace(obj), "add namespace")
})
}
func (npc *controller) UpdateNamespace(oldObj, newObj *coreapi.Namespace) error {
npc.Lock()
defer npc.Unlock()
common.Log.Infof("EVENT UpdateNamespace %s %s", js(oldObj), js(newObj))
return npc.withNS(oldObj.ObjectMeta.Name, func(ns *ns) error {
return errors.Wrap(ns.updateNamespace(oldObj, newObj), "update namespace")
})
}
func (npc *controller) DeleteNamespace(obj *coreapi.Namespace) error {
npc.Lock()
defer npc.Unlock()
common.Log.Infof("EVENT DeleteNamespace %s", js(obj))
return npc.withNS(obj.ObjectMeta.Name, func(ns *ns) error {
return errors.Wrap(ns.deleteNamespace(obj), "delete namespace")
})
}
+115
View File
@@ -0,0 +1,115 @@
package ipset
import (
"os/exec"
"github.com/pkg/errors"
)
type Name string
type Type string
const (
ListSet = Type("list:set")
HashIP = Type("hash:ip")
)
type Interface interface {
Create(ipsetName Name, ipsetType Type) error
AddEntry(ipsetName Name, entry string) error
DelEntry(ipsetName Name, entry string) error
Flush(ipsetName Name) error
Destroy(ipsetName Name) error
FlushAll() error
DestroyAll() error
}
type ipset struct {
refCount
}
func New() Interface {
return &ipset{refCount: newRefCount()}
}
func (i *ipset) Create(ipsetName Name, ipsetType Type) error {
return doExec("create", string(ipsetName), string(ipsetType))
}
func (i *ipset) AddEntry(ipsetName Name, entry string) error {
if i.inc(ipsetName, entry) > 1 { // already in the set
return nil
}
return doExec("add", string(ipsetName), entry)
}
func (i *ipset) DelEntry(ipsetName Name, entry string) error {
if i.dec(ipsetName, entry) > 0 { // still needed
return nil
}
return doExec("del", string(ipsetName), entry)
}
func (i *ipset) Flush(ipsetName Name) error {
i.removeSet(ipsetName)
return doExec("flush", string(ipsetName))
}
func (i *ipset) FlushAll() error {
i.refCount = newRefCount()
return doExec("flush")
}
func (i *ipset) Destroy(ipsetName Name) error {
i.removeSet(ipsetName)
return doExec("destroy", string(ipsetName))
}
func (i *ipset) DestroyAll() error {
i.refCount = newRefCount()
return doExec("destroy")
}
func doExec(args ...string) error {
if output, err := exec.Command("ipset", args...).CombinedOutput(); err != nil {
return errors.Wrapf(err, "ipset %v failed: %s", args, output)
}
return nil
}
// Reference-counting
type key struct {
ipsetName Name
entry string
}
// note no locking is required as all operations are serialised in the controller
type refCount struct {
ref map[key]int
}
func newRefCount() refCount {
return refCount{ref: make(map[key]int)}
}
func (rc *refCount) inc(ipsetName Name, entry string) int {
k := key{ipsetName, entry}
rc.ref[k]++
return rc.ref[k]
}
func (rc *refCount) dec(ipsetName Name, entry string) int {
k := key{ipsetName, entry}
rc.ref[k]--
return rc.ref[k]
}
func (rc *refCount) removeSet(ipsetName Name) {
for k := range rc.ref {
if k.ipsetName == ipsetName {
delete(rc.ref, k)
}
}
}
+10
View File
@@ -0,0 +1,10 @@
package npc
import (
"encoding/json"
)
func js(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
}
+111
View File
@@ -0,0 +1,111 @@
package metrics
import (
"net/http"
"os"
"strconv"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcapgo"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/weaveworks/weave/common"
)
var (
blockedConnections = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "weavenpc_blocked_connections_total",
Help: "Connection attempts blocked by policy controller.",
},
[]string{"protocol", "dport"},
)
)
func gatherMetrics() {
pipe, err := os.Open("/var/log/ulogd.pcap")
if err != nil {
common.Log.Fatalf("Failed to open pcap: %v", err)
}
reader, err := pcapgo.NewReader(pipe)
if err != nil {
common.Log.Fatalf("Failed to read pcap header: %v", err)
}
for {
data, _, err := reader.ReadPacketData()
if err != nil {
common.Log.Fatalf("Failed to read pcap packet: %v", err)
}
packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.TCP)
if tcp.SYN && !tcp.ACK { // Only plain SYN constitutes a NEW TCP connection
blockedConnections.With(prometheus.Labels{"protocol": "tcp", "dport": strconv.Itoa(int(tcp.DstPort))}).Inc()
common.Log.Warnf("TCP connection from %v:%d to %v:%d blocked by Weave NPC.", srcIP(packet), tcp.SrcPort, dstIP(packet), tcp.DstPort)
continue
}
}
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
udp, _ := udpLayer.(*layers.UDP)
blockedConnections.With(prometheus.Labels{"protocol": "udp", "dport": strconv.Itoa(int(udp.DstPort))}).Inc()
common.Log.Warnf("UDP connection from %v:%d to %v:%d blocked by Weave NPC.", srcIP(packet), udp.SrcPort, dstIP(packet), udp.DstPort)
continue
}
}
}
const unknownIP string = "<unknown IP>"
func srcIP(packet gopacket.Packet) string {
if layer := packet.Layer(layers.LayerTypeIPv4); layer != nil {
if ip, ok := layer.(*layers.IPv4); ok {
return ip.SrcIP.String()
}
}
if layer := packet.Layer(layers.LayerTypeIPv6); layer != nil {
if ip, ok := layer.(*layers.IPv6); ok {
return ip.SrcIP.String()
}
}
return unknownIP
}
func dstIP(packet gopacket.Packet) string {
if layer := packet.Layer(layers.LayerTypeIPv4); layer != nil {
if ip, ok := layer.(*layers.IPv4); ok {
return ip.DstIP.String()
}
}
if layer := packet.Layer(layers.LayerTypeIPv6); layer != nil {
if ip, ok := layer.(*layers.IPv6); ok {
return ip.DstIP.String()
}
}
return unknownIP
}
func Start(addr string) error {
if err := prometheus.Register(blockedConnections); err != nil {
return err
}
http.Handle("/metrics", promhttp.Handler())
go func() {
common.Log.Infof("Serving /metrics on %s", addr)
if err := http.ListenAndServe(addr, nil); err != nil {
common.Log.Fatalf("Failed to bind metrics server: %v", err)
}
}()
go gatherMetrics()
return nil
}
+338
View File
@@ -0,0 +1,338 @@
package npc
import (
"encoding/json"
"github.com/coreos/go-iptables/iptables"
"k8s.io/client-go/pkg/api/unversioned"
coreapi "k8s.io/client-go/pkg/api/v1"
extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/pkg/types"
"k8s.io/client-go/pkg/util/uuid"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/ipset"
)
type ns struct {
ipt *iptables.IPTables // interface to iptables
ips ipset.Interface // interface to ipset
name string // k8s Namespace name
namespace *coreapi.Namespace // k8s Namespace object
pods map[types.UID]*coreapi.Pod // k8s Pod objects by UID
policies map[types.UID]*extnapi.NetworkPolicy // k8s NetworkPolicy objects by UID
uid types.UID // surrogate UID to own allPods selector
allPods *selectorSpec // hash:ip ipset of all pod IPs in this namespace
nsSelectors *selectorSet
podSelectors *selectorSet
rules *ruleSet
}
func newNS(name string, ipt *iptables.IPTables, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
allPods, err := newSelectorSpec(&unversioned.LabelSelector{}, name, ipset.HashIP)
if err != nil {
return nil, err
}
ns := &ns{
ipt: ipt,
ips: ips,
name: name,
pods: make(map[types.UID]*coreapi.Pod),
policies: make(map[types.UID]*extnapi.NetworkPolicy),
uid: uuid.NewUUID(),
allPods: allPods,
nsSelectors: nsSelectors,
rules: newRuleSet(ipt)}
ns.podSelectors = newSelectorSet(ips, ns.onNewPodSelector)
if err := ns.podSelectors.provision(ns.uid, nil, map[string]*selectorSpec{ns.allPods.key: ns.allPods}); err != nil {
return nil, err
}
return ns, nil
}
func (ns *ns) empty() bool {
return len(ns.pods) == 0 && len(ns.policies) == 0 && ns.namespace == nil
}
func (ns *ns) destroy() error {
if err := ns.podSelectors.deprovision(ns.uid, map[string]*selectorSpec{ns.allPods.key: ns.allPods}, nil); err != nil {
return err
}
return nil
}
func (ns *ns) onNewPodSelector(selector *selector) error {
for _, pod := range ns.pods {
if hasIP(pod) {
if selector.matches(pod.ObjectMeta.Labels) {
if err := selector.addEntry(pod.Status.PodIP); err != nil {
return err
}
}
}
}
return nil
}
func (ns *ns) addPod(obj *coreapi.Pod) error {
ns.pods[obj.ObjectMeta.UID] = obj
if !hasIP(obj) {
return nil
}
return ns.podSelectors.addToMatching(obj.ObjectMeta.Labels, obj.Status.PodIP)
}
func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
delete(ns.pods, oldObj.ObjectMeta.UID)
ns.pods[newObj.ObjectMeta.UID] = newObj
if !hasIP(oldObj) && !hasIP(newObj) {
return nil
}
if hasIP(oldObj) && !hasIP(newObj) {
return ns.podSelectors.delFromMatching(oldObj.ObjectMeta.Labels, oldObj.Status.PodIP)
}
if !hasIP(oldObj) && hasIP(newObj) {
return ns.podSelectors.addToMatching(newObj.ObjectMeta.Labels, newObj.Status.PodIP)
}
if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) ||
oldObj.Status.PodIP != newObj.Status.PodIP {
for _, ps := range ns.podSelectors.entries {
oldMatch := ps.matches(oldObj.ObjectMeta.Labels)
newMatch := ps.matches(newObj.ObjectMeta.Labels)
if oldMatch == newMatch && oldObj.Status.PodIP == newObj.Status.PodIP {
continue
}
if oldMatch {
if err := ps.delEntry(oldObj.Status.PodIP); err != nil {
return err
}
}
if newMatch {
if err := ps.addEntry(newObj.Status.PodIP); err != nil {
return err
}
}
}
}
return nil
}
func (ns *ns) deletePod(obj *coreapi.Pod) error {
delete(ns.pods, obj.ObjectMeta.UID)
if !hasIP(obj) {
return nil
}
return ns.podSelectors.delFromMatching(obj.ObjectMeta.Labels, obj.Status.PodIP)
}
func (ns *ns) addNetworkPolicy(obj *extnapi.NetworkPolicy) error {
ns.policies[obj.ObjectMeta.UID] = obj
// Analyse policy, determine which rules and ipsets are required
rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
if err != nil {
return err
}
// Provision required resources in dependency order
if err := ns.nsSelectors.provision(obj.ObjectMeta.UID, nil, nsSelectors); err != nil {
return err
}
if err := ns.podSelectors.provision(obj.ObjectMeta.UID, nil, podSelectors); err != nil {
return err
}
if err := ns.rules.provision(obj.ObjectMeta.UID, nil, rules); err != nil {
return err
}
return nil
}
func (ns *ns) updateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error {
delete(ns.policies, oldObj.ObjectMeta.UID)
ns.policies[newObj.ObjectMeta.UID] = newObj
// Analyse the old and the new policy so we can determine differences
oldRules, oldNsSelectors, oldPodSelectors, err := ns.analysePolicy(oldObj)
if err != nil {
return err
}
newRules, newNsSelectors, newPodSelectors, err := ns.analysePolicy(newObj)
if err != nil {
return err
}
// Deprovision unused and provision newly required resources in dependency order
if err := ns.rules.deprovision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
return err
}
if err := ns.nsSelectors.deprovision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
return err
}
if err := ns.podSelectors.deprovision(oldObj.ObjectMeta.UID, oldPodSelectors, newPodSelectors); err != nil {
return err
}
if err := ns.nsSelectors.provision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
return err
}
if err := ns.podSelectors.provision(oldObj.ObjectMeta.UID, oldPodSelectors, newPodSelectors); err != nil {
return err
}
if err := ns.rules.provision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
return err
}
return nil
}
func (ns *ns) deleteNetworkPolicy(obj *extnapi.NetworkPolicy) error {
delete(ns.policies, obj.ObjectMeta.UID)
// Analyse network policy to free resources
rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
if err != nil {
return err
}
// Deprovision unused resources in dependency order
if err := ns.rules.deprovision(obj.ObjectMeta.UID, rules, nil); err != nil {
return err
}
if err := ns.nsSelectors.deprovision(obj.ObjectMeta.UID, nsSelectors, nil); err != nil {
return err
}
if err := ns.podSelectors.deprovision(obj.ObjectMeta.UID, podSelectors, nil); err != nil {
return err
}
return nil
}
func bypassRule(nsIpsetName ipset.Name) []string {
return []string{"-m", "set", "--match-set", string(nsIpsetName), "dst", "-j", "ACCEPT"}
}
func (ns *ns) ensureBypassRule(nsIpsetName ipset.Name) error {
return ns.ipt.Append(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName)...)
}
func (ns *ns) deleteBypassRule(nsIpsetName ipset.Name) error {
return ns.ipt.Delete(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName)...)
}
func (ns *ns) addNamespace(obj *coreapi.Namespace) error {
ns.namespace = obj
// Insert a rule to bypass policies if namespace is DefaultAllow
if !isDefaultDeny(obj) {
return ns.ensureBypassRule(ns.allPods.ipsetName)
}
// Add namespace ipset to matching namespace selectors
return ns.nsSelectors.addToMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
}
func (ns *ns) updateNamespace(oldObj, newObj *coreapi.Namespace) error {
ns.namespace = newObj
// Update bypass rule if ingress default has changed
oldDefaultDeny := isDefaultDeny(oldObj)
newDefaultDeny := isDefaultDeny(newObj)
if oldDefaultDeny != newDefaultDeny {
if oldDefaultDeny {
return ns.ensureBypassRule(ns.allPods.ipsetName)
}
if newDefaultDeny {
return ns.deleteBypassRule(ns.allPods.ipsetName)
}
}
// Re-evaluate namespace selector membership if labels have changed
if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) {
for _, selector := range ns.nsSelectors.entries {
oldMatch := selector.matches(oldObj.ObjectMeta.Labels)
newMatch := selector.matches(newObj.ObjectMeta.Labels)
if oldMatch == newMatch {
continue
}
if oldMatch {
if err := selector.delEntry(string(ns.allPods.ipsetName)); err != nil {
return err
}
}
if newMatch {
if err := selector.addEntry(string(ns.allPods.ipsetName)); err != nil {
return err
}
}
}
}
return nil
}
func (ns *ns) deleteNamespace(obj *coreapi.Namespace) error {
ns.namespace = nil
// Remove bypass rule
if !isDefaultDeny(obj) {
return ns.deleteBypassRule(ns.allPods.ipsetName)
}
// Remove namespace ipset from any matching namespace selectors
return ns.nsSelectors.delFromMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
}
func hasIP(pod *coreapi.Pod) bool {
// Ensure pod isn't dead, has an IP address and isn't sharing the host network namespace
return pod.Status.Phase != "Succeeded" && pod.Status.Phase != "Failed" &&
len(pod.Status.PodIP) > 0 && !pod.Spec.HostNetwork
}
func equals(a, b map[string]string) bool {
if len(a) != len(b) {
return false
}
for ak, av := range a {
if b[ak] != av {
return false
}
}
return true
}
func isDefaultDeny(namespace *coreapi.Namespace) bool {
nnpJSON, found := namespace.ObjectMeta.Annotations["net.beta.kubernetes.io/network-policy"]
if !found {
return false
}
var nnp NamespaceNetworkPolicy
if err := json.Unmarshal([]byte(nnpJSON), &nnp); err != nil {
common.Log.Warn("Ignoring network policy annotation: unmarshal failed:", err)
// If we can't understand the annotation, behave as if it isn't present
return false
}
return nnp.Ingress != nil &&
nnp.Ingress.Isolation != nil &&
*(nnp.Ingress.Isolation) == DefaultDeny
}
+78
View File
@@ -0,0 +1,78 @@
package npc
import (
"strings"
"github.com/coreos/go-iptables/iptables"
"k8s.io/client-go/pkg/types"
"github.com/weaveworks/weave/common"
)
type ruleSpec struct {
key string
args []string
}
func newRuleSpec(proto *string, srcHost *selectorSpec, dstHost *selectorSpec, dstPort *string) *ruleSpec {
args := []string{}
if proto != nil {
args = append(args, "-p", *proto)
}
if srcHost != nil {
args = append(args, "-m", "set", "--match-set", string(srcHost.ipsetName), "src")
}
if dstHost != nil {
args = append(args, "-m", "set", "--match-set", string(dstHost.ipsetName), "dst")
}
if dstPort != nil {
args = append(args, "--dport", *dstPort)
}
args = append(args, "-j", "ACCEPT")
key := strings.Join(args, " ")
return &ruleSpec{key, args}
}
type ruleSet struct {
ipt *iptables.IPTables
users map[string]map[types.UID]struct{}
}
func newRuleSet(ipt *iptables.IPTables) *ruleSet {
return &ruleSet{ipt, make(map[string]map[types.UID]struct{})}
}
func (rs *ruleSet) deprovision(user types.UID, current, desired map[string]*ruleSpec) error {
for key, spec := range current {
if _, found := desired[key]; !found {
delete(rs.users[key], user)
if len(rs.users[key]) == 0 {
common.Log.Infof("deleting rule: %v", spec.args)
if err := rs.ipt.Delete(TableFilter, IngressChain, spec.args...); err != nil {
return err
}
delete(rs.users, key)
}
}
}
return nil
}
func (rs *ruleSet) provision(user types.UID, current, desired map[string]*ruleSpec) error {
for key, spec := range desired {
if _, found := current[key]; !found {
if _, found := rs.users[key]; !found {
common.Log.Infof("adding rule: %v", spec.args)
if err := rs.ipt.Append(TableFilter, IngressChain, spec.args...); err != nil {
return err
}
rs.users[key] = make(map[types.UID]struct{})
}
rs.users[key][user] = struct{}{}
}
}
return nil
}
+130
View File
@@ -0,0 +1,130 @@
package npc
import (
"k8s.io/client-go/pkg/api/unversioned"
"k8s.io/client-go/pkg/labels"
"k8s.io/client-go/pkg/types"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/ipset"
)
type selectorSpec struct {
key string // string representation (for hash keying/equality comparison)
selector labels.Selector // k8s Selector object (for matching)
ipsetType ipset.Type // type of ipset to provision
ipsetName ipset.Name // generated ipset name
}
func newSelectorSpec(json *unversioned.LabelSelector, nsName string, ipsetType ipset.Type) (*selectorSpec, error) {
selector, err := unversioned.LabelSelectorAsSelector(json)
if err != nil {
return nil, err
}
key := selector.String()
return &selectorSpec{
key: key,
selector: selector,
// We prefix the selector string with the namespace name when generating
// the shortname because you can specify the same selector in multiple
// namespaces - we need those to map to distinct ipsets
ipsetName: ipset.Name("weave-" + shortName(nsName+":"+key)),
ipsetType: ipsetType}, nil
}
type selector struct {
ips ipset.Interface
spec *selectorSpec
}
func (s *selector) matches(labelMap map[string]string) bool {
return s.spec.selector.Matches(labels.Set(labelMap))
}
func (s *selector) addEntry(entry string) error {
common.Log.Infof("adding entry %s to %s", entry, s.spec.ipsetName)
return s.ips.AddEntry(s.spec.ipsetName, entry)
}
func (s *selector) delEntry(entry string) error {
common.Log.Infof("deleting entry %s from %s", entry, s.spec.ipsetName)
return s.ips.DelEntry(s.spec.ipsetName, entry)
}
type selectorFn func(selector *selector) error
type selectorSet struct {
ips ipset.Interface
onNewSelector selectorFn
users map[string]map[types.UID]struct{} // list of users per selector
entries map[string]*selector
}
func newSelectorSet(ips ipset.Interface, onNewSelector selectorFn) *selectorSet {
return &selectorSet{
ips: ips,
onNewSelector: onNewSelector,
users: make(map[string]map[types.UID]struct{}),
entries: make(map[string]*selector)}
}
func (ss *selectorSet) addToMatching(labelMap map[string]string, entry string) error {
for _, s := range ss.entries {
if s.matches(labelMap) {
if err := s.addEntry(entry); err != nil {
return err
}
}
}
return nil
}
func (ss *selectorSet) delFromMatching(labelMap map[string]string, entry string) error {
for _, s := range ss.entries {
if s.matches(labelMap) {
if err := s.delEntry(entry); err != nil {
return err
}
}
}
return nil
}
func (ss *selectorSet) deprovision(user types.UID, current, desired map[string]*selectorSpec) error {
for key, spec := range current {
if _, found := desired[key]; !found {
delete(ss.users[key], user)
if len(ss.users[key]) == 0 {
common.Log.Infof("destroying ipset: %#v", spec)
if err := ss.ips.Destroy(spec.ipsetName); err != nil {
return err
}
delete(ss.entries, key)
delete(ss.users, key)
}
}
}
return nil
}
func (ss *selectorSet) provision(user types.UID, current, desired map[string]*selectorSpec) error {
for key, spec := range desired {
if _, found := current[key]; !found {
if _, found := ss.users[key]; !found {
common.Log.Infof("creating ipset: %#v", spec)
if err := ss.ips.Create(spec.ipsetName, spec.ipsetType); err != nil {
return err
}
selector := &selector{ss.ips, spec}
if err := ss.onNewSelector(selector); err != nil {
return err
}
ss.users[key] = make(map[types.UID]struct{})
ss.entries[key] = selector
}
ss.users[key][user] = struct{}{}
}
}
return nil
}
+36
View File
@@ -0,0 +1,36 @@
package npc
import (
"crypto/sha1"
"math/big"
)
const (
// This array:
// * Must include only printable UTF8 characters that are represented with a single byte
// * Must be at least of length 85 (`len("weave-") + l(2^160)/l(85)` equals 31, the maximum ipset name length)
// * Must not include commas as those are treated specially by `ipset add` when adding a named set to a list:set
// * Should not include space for readability
// * Should not include single quote or backslash to be nice to shell users
ShortNameSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789(){}[]<>_$%^&*|/?.;:@#~"
)
// sha1 hash an arbitrary string and represent it using the full range of
// printable ascii characters
func shortName(arbitrary string) string {
symbols := []byte(ShortNameSymbols)
sum := sha1.Sum([]byte(arbitrary))
i := big.NewInt(0).SetBytes(sum[:])
base := big.NewInt(int64(len(symbols)))
zero := big.NewInt(0)
result := make([]byte, 0)
for i.Cmp(zero) > 0 {
remainder := new(big.Int).Mod(i, base)
i.Sub(i, remainder)
i.Div(i, base)
result = append(result, symbols[remainder.Int64()])
}
return string(result)
}
+34
View File
@@ -0,0 +1,34 @@
package ulogd
import (
"io"
"os"
"os/exec"
"syscall"
"github.com/weaveworks/weave/common"
)
func waitForExit(cmd *exec.Cmd) {
if err := cmd.Wait(); err != nil {
common.Log.Fatalf("ulogd terminated: %v", err)
}
common.Log.Fatal("ulogd terminated normally")
}
func Start() error {
cmd := exec.Command("/usr/sbin/ulogd", "-v")
cmd.SysProcAttr = &syscall.SysProcAttr{
Pdeathsig: syscall.SIGKILL,
}
stdout, err := cmd.StderrPipe()
if err != nil {
return err
}
if err := cmd.Start(); err != nil {
return err
}
go io.Copy(os.Stdout, stdout)
go waitForExit(cmd)
return nil
}
+2 -2
View File
@@ -9,6 +9,6 @@ to integrate Weave Net with [Kubernetes](http://kubernetes.io/).
The Docker plugin runs automatically when you `weave launch`, provided your
Docker daemon is version 1.9 or newer.
More detail on the Docker plugin [here](http://docs.weave.works/weave/latest_release/plugin.html).
More detail on the Docker plugin [here](https://www.weave.works/docs/net/latest/plugin/).
More detail on the CNI plugin [here](https://github.com/weaveworks/weave/blob/master/site/plugin/cni-plugin-how-to.md).
More detail on the CNI plugin [here](https://www.weave.works/docs/net/latest/cni-plugin/).
+25 -14
View File
@@ -54,34 +54,40 @@ func (i *Ipam) ReleasePool(poolID string) error {
return nil
}
func (i *Ipam) RequestAddress(poolID string, address net.IP, options map[string]string) (ip *net.IPNet, _ map[string]string, err error) {
i.logReq("RequestAddress", poolID, address, options)
defer func() { i.logRes("RequestAddress", err, ip) }()
// If we pass magic string "_" to weave IPAM it stores the address under its own string
if poolID == "weavepool" { // old-style
ip, err = i.weave.AllocateIP("_")
return
}
func splitPoolID(poolID string) (subnet, iprange *net.IPNet, err error) {
parts := strings.Split(poolID, "-")
if len(parts) != 3 || parts[0] != "weave" {
err = fmt.Errorf("Unrecognized pool ID: %s", poolID)
return
}
var subnet, iprange *net.IPNet
if _, subnet, err = net.ParseCIDR(parts[1]); err != nil {
return
}
if _, iprange, err = net.ParseCIDR(parts[2]); err != nil {
return
}
return
}
func (i *Ipam) RequestAddress(poolID string, address net.IP, options map[string]string) (ip *net.IPNet, _ map[string]string, err error) {
i.logReq("RequestAddress", poolID, address, options)
defer func() { i.logRes("RequestAddress", err, ip) }()
if poolID == "weavepool" { // old-style
ip, err = i.weave.AllocateIP(api.NoContainerID)
return
}
subnet, iprange, err := splitPoolID(poolID)
if err != nil {
return
}
if address != nil { // try to claim specific address requested
ip = &net.IPNet{IP: address, Mask: subnet.Mask}
if err = i.weave.ClaimIP("_", ip); err != nil {
if err = i.weave.ClaimIP(api.NoContainerID, ip); err != nil {
return
}
} else {
if _, iprange, err = net.ParseCIDR(parts[2]); err != nil {
return
}
// We are lying slightly to IPAM here: the range is not a subnet
if ip, err = i.weave.AllocateIPInSubnet("_", iprange); err != nil {
if ip, err = i.weave.AllocateIPInSubnet(api.NoContainerID, iprange); err != nil {
return
}
ip.Mask = subnet.Mask // fix up the subnet we lied about
@@ -91,6 +97,11 @@ func (i *Ipam) RequestAddress(poolID string, address net.IP, options map[string]
func (i *Ipam) ReleaseAddress(poolID string, address net.IP) error {
i.logReq("ReleaseAddress", poolID, address)
if subnet, _, err := splitPoolID(poolID); err != nil {
return err
} else if address.Equal(subnet.IP) { // is it the gateway address we faked earlier?
return nil
}
return i.weave.ReleaseIPsFor(address.String())
}
+67 -112
View File
@@ -5,7 +5,7 @@ import (
"encoding/json"
"fmt"
"net"
"os"
"syscall"
"github.com/appc/cni/pkg/ipam"
"github.com/appc/cni/pkg/skel"
@@ -13,7 +13,7 @@ import (
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
weaveapi "github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/common"
weavenet "github.com/weaveworks/weave/net"
ipamplugin "github.com/weaveworks/weave/plugin/ipam"
)
@@ -32,7 +32,7 @@ func NewCNIPlugin(weave *weaveapi.Client) *CNIPlugin {
func loadNetConf(bytes []byte) (*NetConf, error) {
n := &NetConf{
BrName: "weave",
BrName: weavenet.WeaveBridgeName,
}
if err := json.Unmarshal(bytes, n); err != nil {
return nil, fmt.Errorf("failed to load netconf: %v", err)
@@ -40,6 +40,19 @@ func loadNetConf(bytes []byte) (*NetConf, error) {
return n, nil
}
func (c *CNIPlugin) getIP(ipamType string, args *skel.CmdArgs) (result *types.Result, err error) {
// Default IPAM is Weave's own
if ipamType == "" {
result, err = ipamplugin.NewIpam(c.weave).Allocate(args)
} else {
result, err = ipam.ExecAdd(ipamType, args.StdinData)
}
if err == nil && result.IP4 == nil {
return nil, fmt.Errorf("IPAM plugin failed to allocate IP address")
}
return result, err
}
func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
conf, err := loadNetConf(args.StdinData)
if err != nil {
@@ -53,9 +66,37 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
return fmt.Errorf("IP Masquerading functionality not supported")
}
result, err := c.getIP(conf.IPAM.Type, args)
if err != nil {
return fmt.Errorf("unable to allocate IP address: %s", err)
}
// If config says nothing about routes or gateway, default one will be via the bridge
if result.IP4.Routes == nil && result.IP4.Gateway == nil {
bridgeIP, err := weavenet.FindBridgeIP(conf.BrName, &result.IP4.IP)
if err == weavenet.ErrBridgeNoIP {
bridgeArgs := *args
bridgeArgs.ContainerID = "weave:expose"
bridgeIPResult, err := c.getIP(conf.IPAM.Type, &bridgeArgs)
if err != nil {
return fmt.Errorf("unable to allocate IP address for bridge: %s", err)
}
if err := assignBridgeIP(conf.BrName, bridgeIPResult.IP4.IP); err != nil {
return fmt.Errorf("unable to assign IP address to bridge: %s", err)
}
if err := weavenet.ExposeNAT(bridgeIPResult.IP4.IP); err != nil {
return fmt.Errorf("unable to create NAT rules: %s", err)
}
bridgeIP = bridgeIPResult.IP4.IP.IP
} else if err != nil {
return err
}
result.IP4.Gateway = bridgeIP
}
ns, err := netns.GetFromPath(args.Netns)
if err != nil {
return err
return fmt.Errorf("error accessing namespace %q: %s", args.Netns, err)
}
defer ns.Close()
@@ -69,93 +110,36 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
id = fmt.Sprintf("%x", data)
}
local, err := createAndAttach(id, conf.BrName, conf.MTU)
if err != nil {
if err := weavenet.AttachContainer(args.Netns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&result.IP4.IP}, false); err != nil {
return err
}
cleanup := func(err error) error {
netlink.LinkDel(local)
return err
}
guest, err := netlink.LinkByName(local.PeerName)
if err != nil {
return cleanup(err)
}
if err = netlink.LinkSetNsFd(guest, int(ns)); err != nil {
return cleanup(fmt.Errorf("failed to move veth to container netns: %s", err))
}
if err := netlink.LinkSetUp(local); err != nil {
return cleanup(fmt.Errorf("unable to bring veth up: %s", err))
}
var result *types.Result
// Default IPAM is Weave's own
if conf.IPAM.Type == "" {
result, err = ipamplugin.NewIpam(c.weave).Allocate(args)
} else {
result, err = ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
}
if err != nil {
return cleanup(fmt.Errorf("unable to allocate IP address: %s", err))
}
if result.IP4 == nil {
return cleanup(fmt.Errorf("IPAM plugin failed to allocate IP address"))
}
// If config says nothing about routes or gateway, default one will be via the bridge
if result.IP4.Routes == nil && result.IP4.Gateway == nil {
bridgeIP, err := findBridgeIP(conf.BrName, result.IP4.IP)
if err != nil {
return cleanup(err)
}
result.IP4.Gateway = bridgeIP
}
err = common.WithNetNS(ns, func() error {
return setupGuestIP4(local.PeerName, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes)
})
if err != nil {
return cleanup(fmt.Errorf("error setting up interface: %s", err))
if err := weavenet.WithNetNSLinkUnsafe(ns, args.IfName, func(link netlink.Link) error {
return setupRoutes(link, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes)
}); err != nil {
return fmt.Errorf("error setting up routes: %s", err)
}
result.DNS = conf.DNS
return result.Print()
}
func setupGuestIP4(origName, name string, ipnet net.IPNet, gw net.IP, routes []types.Route) error {
guest, err := netlink.LinkByName(origName)
if err != nil {
return err
}
if err = netlink.LinkSetName(guest, name); err != nil {
return err
}
if err = netlink.LinkSetUp(guest); err != nil {
return err
}
if err = common.ConfigureARPCache(name); err != nil {
return err
}
func setupRoutes(link netlink.Link, name string, ipnet net.IPNet, gw net.IP, routes []types.Route) error {
var err error
if routes == nil { // If config says nothing about routes, add a default one
if !ipnet.Contains(gw) {
// The bridge IP is not on the same subnet; add a specific route to it
gw32 := &net.IPNet{IP: gw, Mask: mask32}
if err = addRoute(guest, netlink.SCOPE_LINK, gw32, nil); err != nil {
if err = weavenet.AddRoute(link, netlink.SCOPE_LINK, gw32, nil); err != nil {
return err
}
}
routes = []types.Route{{Dst: zeroNetwork}}
}
if err = netlink.AddrAdd(guest, &netlink.Addr{IPNet: &ipnet}); err != nil {
return fmt.Errorf("failed to add IP address to %q: %v", name, err)
}
for _, r := range routes {
if r.GW != nil {
err = addRoute(guest, netlink.SCOPE_UNIVERSE, &r.Dst, r.GW)
err = weavenet.AddRoute(link, netlink.SCOPE_UNIVERSE, &r.Dst, r.GW)
} else {
err = addRoute(guest, netlink.SCOPE_UNIVERSE, &r.Dst, gw)
err = weavenet.AddRoute(link, netlink.SCOPE_UNIVERSE, &r.Dst, gw)
}
if err != nil {
return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, name, err)
@@ -164,37 +148,20 @@ func setupGuestIP4(origName, name string, ipnet net.IPNet, gw net.IP, routes []t
return nil
}
func addRoute(link netlink.Link, scope netlink.Scope, dst *net.IPNet, gw net.IP) error {
err := netlink.RouteAdd(&netlink.Route{
LinkIndex: link.Attrs().Index,
Scope: scope,
Dst: dst,
Gw: gw,
})
if os.IsExist(err) { // squash duplicate route errors
err = nil
}
return err
}
func findBridgeIP(bridgeName string, subnet net.IPNet) (net.IP, error) {
netdevs, err := common.GetBridgeNetDev(bridgeName)
func assignBridgeIP(bridgeName string, ipnet net.IPNet) error {
link, err := netlink.LinkByName(bridgeName)
if err != nil {
return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err)
return err
}
if len(netdevs) == 0 {
return nil, fmt.Errorf("Could not find %q bridge", bridgeName)
}
if len(netdevs[0].CIDRs) == 0 {
return nil, fmt.Errorf("Bridge %q has no IP addresses", bridgeName)
}
for _, cidr := range netdevs[0].CIDRs {
if subnet.Contains(cidr.IP) {
return cidr.IP, nil
if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: &ipnet}); err != nil {
// Treat as non-error if this address is already there
// - maybe another copy of this program just added it
if err == syscall.Errno(syscall.EEXIST) {
return nil
}
return fmt.Errorf("failed to add IP address to %q: %v", bridgeName, err)
}
// None in the required subnet; just return the first one
return netdevs[0].CIDRs[0].IP, nil
return nil
}
func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
@@ -203,20 +170,8 @@ func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
return err
}
ns, err := netns.GetFromPath(args.Netns)
if err != nil {
return err
}
defer ns.Close()
err = common.WithNetNS(ns, func() error {
link, err := netlink.LinkByName(args.IfName)
if err != nil {
return err
}
return netlink.LinkDel(link)
})
if err != nil {
return fmt.Errorf("error removing interface: %s", err)
if _, err = weavenet.WithNetNS(args.Netns, "del-iface", args.IfName); err != nil {
return fmt.Errorf("error removing interface %q: %s", args.IfName, err)
}
// Default IPAM is Weave's own
+110 -85
View File
@@ -2,35 +2,45 @@ package plugin
import (
"fmt"
"strconv"
"sync"
"github.com/docker/libnetwork/drivers/remote/api"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types"
"golang.org/x/sys/unix"
"github.com/vishvananda/netlink"
weaveapi "github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/common/docker"
"github.com/weaveworks/weave/common/odp"
weavenet "github.com/weaveworks/weave/net"
"github.com/weaveworks/weave/plugin/skel"
)
const (
WeaveBridge = "weave"
MulticastOption = "works.weave.multicast"
)
type driver struct {
scope string
noMulticastRoute bool
sync.RWMutex
endpoints map[string]struct{}
type network struct {
isOurs bool
hasMulticastRoute bool
}
func New(client *docker.Client, weave *weaveapi.Client, scope string, noMulticastRoute bool) (skel.Driver, error) {
type driver struct {
name string
scope string
docker *docker.Client
sync.RWMutex
networks map[string]network
}
func New(client *docker.Client, weave *weaveapi.Client, name, scope string) (skel.Driver, error) {
driver := &driver{
noMulticastRoute: noMulticastRoute,
scope: scope,
endpoints: make(map[string]struct{}),
name: name,
scope: scope,
docker: client,
networks: make(map[string]network),
}
_, err := NewWatcher(client, weave, driver)
@@ -53,25 +63,53 @@ func (driver *driver) GetCapabilities() (*api.GetCapabilityResponse, error) {
func (driver *driver) CreateNetwork(create *api.CreateNetworkRequest) error {
driver.logReq("CreateNetwork", create, create.NetworkID)
_, err := driver.setupNetworkInfo(create.NetworkID, true, stringOptions(create))
return err
}
// Deal with excessively-generic way the options get decoded from JSON
func stringOptions(create *api.CreateNetworkRequest) map[string]string {
if create.Options != nil {
if data, found := create.Options[netlabel.GenericData]; found {
if options, ok := data.(map[string]interface{}); ok {
out := make(map[string]string, len(options))
for key, value := range options {
if str, ok := value.(string); ok {
out[key] = str
}
}
return out
}
}
}
return nil
}
func (driver *driver) DeleteNetwork(delete *api.DeleteNetworkRequest) error {
driver.logReq("DeleteNetwork", delete, delete.NetworkID)
func (driver *driver) DeleteNetwork(delreq *api.DeleteNetworkRequest) error {
driver.logReq("DeleteNetwork", delreq, delreq.NetworkID)
driver.Lock()
delete(driver.networks, delreq.NetworkID)
driver.Unlock()
return nil
}
func (driver *driver) CreateEndpoint(create *api.CreateEndpointRequest) (*api.CreateEndpointResponse, error) {
driver.logReq("CreateEndpoint", create, create.EndpointID)
endID := create.EndpointID
common.Log.Debugf("interface %+v", create.Interface)
if create.Interface == nil {
return nil, driver.error("CreateEndpoint", "Not supported: creating an interface from within CreateEndpoint")
}
driver.Lock()
driver.endpoints[endID] = struct{}{}
driver.Unlock()
resp := &api.CreateEndpointResponse{}
// create veths. note we assume endpoint IDs are unique in the first 9 chars
name, peerName := vethPair(create.EndpointID)
if _, err := weavenet.CreateAndAttachVeth(name, peerName, weavenet.WeaveBridgeName, 0, false, nil); err != nil {
return nil, driver.error("JoinEndpoint", "%s", err)
}
// Send back the MAC address
link, _ := netlink.LinkByName(peerName)
resp := &api.CreateEndpointResponse{Interface: &api.EndpointInterface{MacAddress: link.Attrs().HardwareAddr.String()}}
driver.logRes("CreateEndpoint", resp)
return resp, nil
@@ -79,19 +117,20 @@ func (driver *driver) CreateEndpoint(create *api.CreateEndpointRequest) (*api.Cr
func (driver *driver) DeleteEndpoint(deleteReq *api.DeleteEndpointRequest) error {
driver.logReq("DeleteEndpoint", deleteReq, deleteReq.EndpointID)
driver.Lock()
delete(driver.endpoints, deleteReq.EndpointID)
driver.Unlock()
name, _ := vethPair(deleteReq.EndpointID)
veth := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: name}}
if err := netlink.LinkDel(veth); err != nil {
// Try again using the name construction from earlier plugin version,
// in case user has upgraded with endpoints still extant
veth.Name = "vethwl" + deleteReq.EndpointID[:5]
if err2 := netlink.LinkDel(veth); err2 != nil {
// Note we report the first error
driver.warn("LeaveEndpoint", "unable to delete veth %q: %s", name, err)
}
}
return nil
}
func (driver *driver) HasEndpoint(endpointID string) bool {
driver.Lock()
_, found := driver.endpoints[endpointID]
driver.Unlock()
return found
}
func (driver *driver) EndpointInfo(req *api.EndpointInfoRequest) (*api.EndpointInfoResponse, error) {
driver.logReq("EndpointInfo", req, req.EndpointID)
return &api.EndpointInfoResponse{Value: map[string]interface{}{}}, nil
@@ -100,24 +139,19 @@ func (driver *driver) EndpointInfo(req *api.EndpointInfoRequest) (*api.EndpointI
func (driver *driver) JoinEndpoint(j *api.JoinRequest) (*api.JoinResponse, error) {
driver.logReq("JoinEndpoint", j, fmt.Sprintf("%s:%s to %s", j.NetworkID, j.EndpointID, j.SandboxKey))
local, err := createAndAttach(j.EndpointID, WeaveBridge, 0)
network, err := driver.findNetworkInfo(j.NetworkID)
if err != nil {
return nil, driver.error("JoinEndpoint", "%s", err)
}
if err := netlink.LinkSetUp(local); err != nil {
return nil, driver.error("JoinEndpoint", "unable to bring up veth %s-%s: %s", local.Name, local.PeerName, err)
}
ifname := &api.InterfaceName{
SrcName: local.PeerName,
DstPrefix: "ethwe",
return nil, driver.error("JoinEndpoint", "unable to find network info: %s", err)
}
_, peerName := vethPair(j.EndpointID)
response := &api.JoinResponse{
InterfaceName: ifname,
InterfaceName: &api.InterfaceName{
SrcName: peerName,
DstPrefix: weavenet.VethName,
},
}
if !driver.noMulticastRoute {
if network.hasMulticastRoute {
multicastRoute := api.StaticRoute{
Destination: "224.0.0.0/4",
RouteType: types.CONNECTED,
@@ -128,53 +162,48 @@ func (driver *driver) JoinEndpoint(j *api.JoinRequest) (*api.JoinResponse, error
return response, nil
}
// create and attach local name to the Weave bridge
func createAndAttach(id, bridgeName string, mtu int) (*netlink.Veth, error) {
maybeBridge, err := netlink.LinkByName(bridgeName)
func (driver *driver) findNetworkInfo(id string) (network, error) {
driver.Lock()
network, found := driver.networks[id]
driver.Unlock()
if found {
return network, nil
}
info, err := driver.docker.NetworkInfo(id)
if err != nil {
return nil, fmt.Errorf(`bridge "%s" not present; did you launch weave?`, bridgeName)
return network, err
}
return driver.setupNetworkInfo(id, info.Driver == driver.name, info.Options)
}
local := vethPair(id[:5])
if mtu == 0 {
local.Attrs().MTU = maybeBridge.Attrs().MTU
} else {
local.Attrs().MTU = mtu
}
if err := netlink.LinkAdd(local); err != nil {
return nil, fmt.Errorf(`could not create veth pair %s-%s: %s`, local.Name, local.PeerName, err)
}
func (driver *driver) setupNetworkInfo(id string, isOurs bool, options map[string]string) (network, error) {
network := network{isOurs: isOurs}
if isOurs {
for key, value := range options {
switch key {
case MulticastOption:
if value == "" { // interpret "--opt works.weave.multicast" as "turn it on"
network.hasMulticastRoute = true
} else {
var err error
if network.hasMulticastRoute, err = strconv.ParseBool(value); err != nil {
return network, fmt.Errorf("unrecognized value %q for option %s", value, key)
}
switch maybeBridge.(type) {
case *netlink.Bridge:
if err := netlink.LinkSetMasterByIndex(local, maybeBridge.Attrs().Index); err != nil {
return nil, fmt.Errorf(`unable to set master of %s: %s`, local.Name, err)
}
default:
driver.warn("setupNetworkInfo", "unrecognized option: %s", key)
}
}
case *netlink.GenericLink:
if maybeBridge.Type() != "openvswitch" {
return nil, fmt.Errorf(`device "%s" is of type "%s"`, bridgeName, maybeBridge.Type())
}
if err := odp.AddDatapathInterface(bridgeName, local.Name); err != nil {
return nil, fmt.Errorf(`failed to attach %s to device "%s": %s`, local.Name, bridgeName, err)
}
case *netlink.Device:
// Assume it's our openvswitch device, and the kernel has not been updated to report the kind.
if err := odp.AddDatapathInterface(bridgeName, local.Name); err != nil {
return nil, fmt.Errorf(`failed to attach %s to device "%s": %s`, local.Name, bridgeName, err)
}
default:
return nil, fmt.Errorf(`device "%s" is not a bridge`, bridgeName)
}
return local, nil
driver.Lock()
driver.networks[id] = network
driver.Unlock()
return network, nil
}
func (driver *driver) LeaveEndpoint(leave *api.LeaveRequest) error {
driver.logReq("LeaveEndpoint", leave, fmt.Sprintf("%s:%s", leave.NetworkID, leave.EndpointID))
local := vethPair(leave.EndpointID[:5])
if err := netlink.LinkDel(local); err != nil {
driver.warn("LeaveEndpoint", "unable to delete veth: %s", err)
}
return nil
}
@@ -188,13 +217,9 @@ func (driver *driver) DiscoverDelete(disco *api.DiscoveryNotification) error {
return nil
}
// ===
func vethPair(suffix string) *netlink.Veth {
return &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: "vethwl" + suffix},
PeerName: "vethwg" + suffix,
}
func vethPair(id string) (string, string) {
// IFNAMSIZ is buffer length; subtract 6 for "vethwl" and 1 for terminating nul
return "vethwl" + id[:unix.IFNAMSIZ-7], "vethwg" + id[:unix.IFNAMSIZ-7]
}
// logging
+11 -2
View File
@@ -5,6 +5,7 @@ import (
weaveapi "github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/common/docker"
weavenet "github.com/weaveworks/weave/net"
)
const (
@@ -32,13 +33,21 @@ func (w *watcher) ContainerStarted(id string) {
w.driver.warn("ContainerStarted", "error inspecting container %s: %s", id, err)
return
}
// check that it's on our network, via the endpointID
// check that it's on our network
for _, net := range info.NetworkSettings.Networks {
if w.driver.HasEndpoint(net.EndpointID) {
network, err := w.driver.findNetworkInfo(net.NetworkID)
if err != nil {
w.driver.warn("ContainerStarted", "unable to find network %s info: %s", net.NetworkID, err)
continue
}
if network.isOurs {
fqdn := fmt.Sprintf("%s.%s", info.Config.Hostname, info.Config.Domainname)
if err := w.weave.RegisterWithDNS(id, fqdn, net.IPAddress); err != nil {
w.driver.warn("ContainerStarted", "unable to register %s with weaveDNS: %s", id, err)
}
if _, err := weavenet.WithNetNSByPid(info.State.Pid, "configure-arp", weavenet.VethName); err != nil {
w.driver.warn("ContainerStarted", "unable to configure interfaces: %s", err)
}
}
}
}
+55
View File
@@ -0,0 +1,55 @@
package main
import (
"fmt"
"log"
"k8s.io/client-go/kubernetes"
api "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/rest"
)
func getKubePeers() ([]string, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, err
}
c, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
nodeList, err := c.Nodes().List(api.ListOptions{})
if err != nil {
// Fallback for cases (e.g. from kube-up.sh) where kube-proxy is not running on master
config.Host = "http://localhost:8080"
log.Print("error contacting APIServer: ", err, "; trying with fallback: ", config.Host)
c, err = kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
nodeList, err = c.Nodes().List(api.ListOptions{})
}
if err != nil {
return nil, err
}
addresses := make([]string, 0, len(nodeList.Items))
for _, peer := range nodeList.Items {
for _, addr := range peer.Status.Addresses {
if addr.Type == "InternalIP" {
addresses = append(addresses, addr.Address)
}
}
}
return addresses, nil
}
func main() {
peers, err := getKubePeers()
if err != nil {
log.Fatalf("Could not get peers: %v", err)
}
for _, addr := range peers {
fmt.Println(addr)
}
}
@@ -1,3 +1,3 @@
FROM weaveworks/weaveexec
FROM DOCKERHUB_USER/weaveARCH_EXT
ADD ./plugin /home/weave/
ENTRYPOINT ["/home/weave/plugin"]
Loaded 100 of 318 files, more files were not shown because too many files have changed in this diff. Show more