Compare commits

...
358 Commits
Author SHA1 Message Date
Martynas Pumputis e2d6ee4223 Add release v2.4.0 2018-07-25 10:32:04 +02:00
Bryan Boreham 90a81ce736 Merge pull request #3319 from weaveworks/weave-reset-err
Make error "Weave is not running" less confusing when running on Kubernetes
2018-07-24 10:18:24 +01:00
Bryan Boreham 9cf0dd1b87 Merge pull request #3313 from weaveworks/issues/2624-egress-npc
Implement Egress NPC
2018-07-24 10:17:45 +01:00
Martynas Pumputis e65cf32372 npc: Flush chain if rules mismatch in AddChainWithRules
Also, move the helper function to net/iptables.go.
2018-07-24 10:06:55 +02:00
Martynas Pumputis 0ad2001ab4 npc: ACCEPT already established connections in egress chain
It's safe to accept such connections as they will be accepted
in the ingress chain anyway.
2018-07-24 10:06:55 +02:00
Martynas Pumputis 70ff510e49 npc: Document egress rules 2018-07-24 10:06:55 +02:00
Martynas Pumputis 6377aeabdd npc: Do not ignore errors when creating chains
Also, move ensureRulesAtTop to net/iptables.go
2018-07-24 10:06:55 +02:00
Martynas Pumputis 1649080a35 npc: Add ns name into ipBlock ipset name
Otherwise, the same ipBlock ipset can be used among different namespaces which
results in panic as refcounting of ipsets happens only per namespace, so
npc will try to create the same ipset twice.
2018-07-24 10:06:55 +02:00
Martynas Pumputis c1ee358f66 npc: Fix ipset package import path after rebase 2018-07-24 10:06:55 +02:00
Martynas Pumputis 2c708b57a1 npc: Improve analyser comments 2018-07-24 10:06:55 +02:00
Martynas Pumputis c5772c814c npc: Add comments for traffic steering 2018-07-24 10:06:55 +02:00
Martynas Pumputis 10a5b6fb51 npc: Use constants for chains 2018-07-24 10:06:55 +02:00
Martynas Pumputis 07d31a8558 npc: Get rid of the legacy netpol 2018-07-24 10:06:55 +02:00
Martynas Pumputis cf3a3be8f2 npc: Replace isNil by reflect.IsNil 2018-07-24 10:06:23 +02:00
Martynas Pumputis 49224ec9f7 npc: Rename policy{Ingress,Egress} to policyType{Ingress,Egress} 2018-07-24 10:06:23 +02:00
Martynas Pumputis dee24aec65 npc: Add integration test for egress
Also, install dig (bind-tools) in the network-tester image.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 9a63ade1b5 npc: Do not create WEAVE-NPC-EGRESS* chains in legacy netpol mode 2018-07-24 10:06:23 +02:00
Martynas Pumputis 18a6237ec7 npc: Check whether weave-local-pods exists before creating
We do not destroy it anymore, thus the check.
2018-07-24 10:06:23 +02:00
Martynas Pumputis be8298926a npc: Pass --use-legacy-netpol to weaver in 840 2018-07-24 10:06:23 +02:00
Martynas Pumputis 86958be6cf npc: Add --use-legacy-netpol flag to weaver
Egress does not work in the legacy netpol mode, so in the legacy case
we don't have to create the egress traffic steering rules. Otherwise,
some traffic will be blocked.
2018-07-24 10:06:23 +02:00
Martynas Pumputis a2d07c85da npc: Remove WEAVE-NPC-EGRESS* chains upon "weave reset"
Also, fix removal of rule which steers traffic for ingress
processing.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 295ddc5248 npc: Try not to clear WEAVE-NPC-EGRESS chain
First check whether the chain exists with the required rules, and
if not - create it.

If we flush each time we start weave-npc then we create a (short)
time window during which all egress traffic is allowed.
2018-07-24 10:06:23 +02:00
Martynas Pumputis a85a19e40a npc: Add unit test for egress policy with ipblock 2018-07-24 10:06:23 +02:00
Martynas Pumputis cec3c8a846 npc: Add iptables mocked interface 2018-07-24 10:06:23 +02:00
Martynas Pumputis 7da7ce85df npc: Extend TestDefaultAllow unit test to include egress 2018-07-24 10:06:23 +02:00
Martynas Pumputis 6055431b6f npc: Refactor bypassRules 2018-07-24 10:06:23 +02:00
Martynas Pumputis c0e2deb5a0 npc: Add WEAVE-NPC-EGRESS-ACCEPT chain
For improving readability of NPC rules. The chain marks to-be-allowed egress
traffic.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 1f86ed55ba npc: Ensure default-allow rules for egress 2018-07-24 10:06:23 +02:00
Martynas Pumputis 35f1ba17e1 npc: Provision egress rules 2018-07-24 10:06:23 +02:00
Martynas Pumputis b84fbf86ec npc: Add a dummy isNil method to ruleHost interface 2018-07-24 10:06:23 +02:00
Martynas Pumputis a5e0b3452d npc: Create rules with IPBlock (egress only) 2018-07-24 10:06:23 +02:00
Martynas Pumputis 0a1ca30aae npc: Add getRuleSpec for ipBlockSpec 2018-07-24 10:06:23 +02:00
Martynas Pumputis 2e85018c26 npc: Add ruleHost interface
The idea for the interface is taken from the kitt1987/ipblock work.

The interface is going to be implemented by selectorSpec and
ipBlockSpec.
2018-07-24 10:06:23 +02:00
Martynas Pumputis affdc6f5af npc: Provision networkingv1.IPBlock (only for Egress) 2018-07-24 10:06:23 +02:00
Martynas Pumputis 9198bb5a68 npc: Refactor npc/ipblock.go
- No need to validate networkingv1.IPBlock fields as k8s does it.
- Fix provisioning.
2018-07-24 10:06:23 +02:00
Kitt Hsu 9769c8d5b9 support ipblock in npc
NOTE(brb): This commit is cherry-picked from the kitt1987/ipblock
branch.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 688328dc57 npc: Steer traffic for egress processing
We need two rules:

* `-A INPUT -i weave -j WEAVE-NPC-EGRESS`: applies to packets destined
  to a local node.
* `-A FORWARD -i weave -j WEAVE-NPC-EGRESS`: the rest. It can match
  an ingress packet.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 8904a4b144 npc: Get rid of selectorSpec.target
We treat selectorSpec as a target selector if len(selectorSpec.policyTypes) > 0.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 8d1ee752d4 npc: Rename dstSelector to targetSelector
dstSelector becomes ambiguous once we introduce the egress.

So, from now on, we call selector a target selector if it selects
pods to which a netpol applies (aka NetworkPolicySpec.podSelector).
2018-07-24 10:06:23 +02:00
Martynas Pumputis f02a11b27b npc: Analyse egress policy
This is a copy-paste from the ingress part with small modifications.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 5e675f26f7 npc: Embed policyType into rule
This ensures two rules with the same rulespec but of different
policyType will end up having different keys.

Sharing the same key would prevent from provisioning the rules.
2018-07-24 10:06:23 +02:00
Martynas Pumputis 497a9c7fd0 npc: Replace rulesType by policyType 2018-07-24 10:06:23 +02:00
Martynas Pumputis 5afcd0595d npc: Parse PolicyTypes field when analysing a netpol 2018-07-24 10:06:23 +02:00
Martynas Pumputis f27d4d2117 npc: Add defaultAllowIPSetName helper 2018-07-24 10:06:23 +02:00
Martynas Pumputis 79727a86fa npc: Manage entries in egressDefaultAllowIPSet 2018-07-24 10:06:23 +02:00
Martynas Pumputis d474c1c26d npc: Add policyType to selectorSpec
This allows us to distinguish between ingress and egress
dst selectors (required when managing entries in default-allow
ipsets).
2018-07-24 10:06:23 +02:00
Martynas Pumputis 29ec43bdc8 npc: Rename default-allow ipset for ingress
As we're going to introduce one for egress, we cannot use
"default-allow" name for ingress.
2018-07-24 10:06:23 +02:00
Martynas Pumputis cabc05b06c npc: Add rule type (ingress, egress) 2018-07-24 10:06:23 +02:00
Martynas Pumputis 89e820d62e npc: Create WEAVE-NPC-EGRESS chain with the base rules
The following rules are provisioned by weave-npc:

-A WEAVE-NPC-EGRESS -m state --state RELATED,ESTABLISHED -j RETURN
-A WEAVE-NPC-EGRESS -m set ! --match-set weave-local-pods src -j RETURN
-A WEAVE-NPC-EGRESS -d 224.0.0.0/4 -j RETURN
-A WEAVE-NPC-EGRESS -m state --state NEW -j WEAVE-NPC-EGRESS-DEFAULT
-A WEAVE-NPC-EGRESS -m state --state NEW -m mark ! --mark 0x40000/0x40000 -j WEAVE-NPC-EGRESS-CUSTOM
-A WEAVE-NPC-EGRESS -m state --state NEW -m mark ! --mark 0x40000/0x40000 -j NFLOG --nflog-group 86
-A WEAVE-NPC-EGRESS -m mark ! --mark 0x40000/0x40000 -j DROP

-A WEAVE-NPC-EGRESS-CUSTOM <rulespec> -j MARK --set-xmark 0x40000/0x40000
-A WEAVE-NPC-EGRESS-CUSTOM <rulespec> -j RETURN

-A WEAVE-NPC-EGRESS-DEFAULT <rulespec> -j MARK --set-xmark 0x40000/0x40000
-A WEAVE-NPC-EGRESS-DEFAULT <rulespec> -j RETURN

For each rule we create two (mark and return). We cannot just accept
a packet if it matches any rule, as a packet might need to traverse
the ingress npc as well which happens later in the chain (in some cases
we cannot detect whether packet is ingress or egress, so we need to
check both chains).
2018-07-24 10:06:23 +02:00
Bryan Boreham 88616007b0 Merge pull request #3353 from louismunro/fix_xtables_lock
Fix xtables.lock race condition between weave and kube-proxy.
2018-07-23 13:35:26 +01:00
Munro, Louis b262a1eedc Fix xtables.lock race condition between weave and kube-proxy.
Fixes #3351
2018-07-22 13:12:00 -04:00
Bryan Boreham b8ce722a2c Merge pull request #3346 from murali-reddy/issue-3206
3206: Protect against CNI plugin being called with the host namespace
2018-07-19 12:02:49 +01:00
Bryan Boreham b8fa4af06a Merge branch '2.3' 2018-07-17 12:25:49 +01:00
Bryan Boreham ea8f041a20 Fix indentation of TOC 2018-07-17 11:38:09 +01:00
Bryan Boreham 52e8cdb011 Merge pull request #3348 from weaveworks/check-running
Add instructions to check weave-kube logs
2018-07-17 11:35:29 +01:00
Bryan Boreham ac9f47783c Review feedback 2018-07-17 10:24:26 +01:00
Murali Reddy 27f9aa16d6 3206: Protect against CNI plugin being called with the host namespace
adding a check to verify if network namespace is not host network namespace

Fixes #3206
2018-07-16 12:43:09 +05:30
Bryan Boreham 08dc649b9a Merge branch '2.3' 2018-07-12 08:58:54 +00:00
Bryan Boreham bb1a373272 Add instructions to check weave-kube logs
"Check it is running" and "check the logs" are important steps when
troubleshooting.
2018-07-12 08:53:02 +00:00
Martynas Pumputis e192f68891 Merge pull request #3345 from stevenjohnstone/issues/3337-symlink-upgrades-broken
Issue #3337: fix upgrade_cni_plugin

Fix #3337
2018-07-09 12:17:32 +02:00
Stevie Johnstone 73654791c1 Issue #3337: fix upgrade_cni_plugin 2018-07-09 10:33:04 +01:00
Martynas Pumputis 8908458942 Merge pull request #3340 from weaveworks/k8s-1-11
Update smoke tests to use Kubernetes 1.11
2018-07-09 09:49:11 +02:00
Bryan Boreham 26792283ab Merge pull request #3328 from weaveworks/minikube-docs
Add minikube caveat to docs
2018-07-05 13:39:06 +01:00
Bryan Boreham 32a92a4695 Add --force flag to kubeadm reset 2018-06-28 10:26:09 +00:00
Bryan Boreham 3bea2ae419 Bump to Kubernetes 1.11 2018-06-28 09:25:56 +00:00
Martynas Pumputis 58eaf19026 Merge pull request #3334 from weaveworks/issues/3332-add-nodestatus-perms
Add permissions to set node status
2018-06-21 17:37:11 +02:00
Bryan Boreham d513e68fab Add permissions to set node status
This is needed to update the node NetworkUnavailable conditon
see https://github.com/weaveworks/weave/issues/3249
2018-06-21 11:08:27 +00:00
Martynas Pumputis ca8bbb27a0 Add minikube caveat to docs 2018-06-16 18:04:03 +02:00
Martynas Pumputis 287dab27ae Merge pull request #3317 from weaveworks/break-infinite-loop
Break out of kube rm-peers loop if nothing changes
2018-06-12 14:52:39 +02:00
Martynas Pumputis 25c26519ed Merge remote-tracking branch 'origin/2.3' 2018-06-12 14:47:42 +02:00
Bryan Boreham cf66c8d507 Don't remove myself when reclaiming
Some logs from users show an entry of X with annotation X, which
suggests we have gone down the path of removing ourselves. This change
avoids that possibility.
2018-06-12 11:52:03 +00:00
Bryan Boreham 318bb767a5 Merge pull request #3320 from weaveworks/manifest-tool-make
Fix manifest-tool cmd in Makefile
2018-06-12 10:48:30 +01:00
Bryan Boreham ad6148f0f6 Break out of kube rm peers loop if nothing changes
Avoid getting into an infinite loop if some of the logic or underlying
data is bad
2018-06-12 08:31:35 +00:00
Martynas Pumputis 8042d3f22a Fix manifest-tool cmd in Makefile 2018-06-12 10:19:47 +02:00
Martynas Pumputis c7259fc424 Make error "Weave is not running" less confusing when running on Kubernetes 2018-06-12 09:58:08 +02:00
Bryan Boreham 62c949df6e Merge pull request #3316 from weaveworks/fix-makefile
Fix $HOME usage in Makefile
2018-06-11 16:39:36 +01:00
Martynas Pumputis 8c7dc342e0 Fix $HOME var in Makefile 2018-06-11 17:23:22 +02:00
Martynas Pumputis d15439aeac Merge remote-tracking branch 'origin/2.3' 2018-06-11 16:39:03 +02:00
Martynas Pumputis c19c64a990 Merge pull request #3305 from weaveworks/issues/3289-many-namespaces
Make the ipset list size bigger
2018-06-11 16:36:26 +02:00
Bryan Boreham 8e374d9416 D'oh 2018-06-11 13:52:15 +00:00
Martynas Pumputis 49216ce365 Merge pull request #3307 from weaveworks/set-kube-netstatus
Set Kubernetes NodeNetworkUnavailable to false when starting
2018-06-11 15:20:14 +02:00
Bryan Boreham 812c58297f Merge pull request #3298 from weaveworks/issues/2924-preserve-src-ip-on-local
2924: Preserve the client source IP
2018-06-11 13:21:12 +01:00
Bryan Boreham 2a04df1049 Rename "kube-peers" to "kube-utils"
It's now doing things like network status that are outside of the
scope of "peers".
2018-06-11 11:22:07 +00:00
Martynas Pumputis 2eda624653 Merge pull request #3291 from weaveworks/withnetns-inproc
Remove subprocess for changing netns
2018-06-05 16:49:37 +02:00
Martynas Pumputis 2f8aa7a351 Add random nonce to test ipset name to prevent race
As ipset.New(...) can be called by two processes (weaver and weave-npc)
at the same time, there is a possibility for a race when they both
check the comment support. To prevent the race, we append a random
nonce to the test ipset name.
2018-06-05 08:52:21 +02:00
Martynas Pumputis b6115f0147 Address the PR comments
- Track only local changes.
- Add comment to the iptables rule which prevents SNAT'ing.
- Rename the ipset to weaver-no-masq-local to prevent NPC from destroying it.
- Fix comment about create/flush WEAVE-EXPOSE.
- Add comment about reexpose being no-op if bridge hasn't been exposed.
- Add comment that the feature is not only for Kubernetes.
- Reuse the ipset instance.
2018-06-04 19:22:48 +02:00
Bryan Boreham 5ff22a1a77 Review feedback: tidied up function names 2018-06-04 13:28:28 +00:00
Martynas Pumputis 7fdf8fee13 Mention NO_MASQ_LOCAL opt in the docs 2018-06-04 14:08:24 +02:00
Martynas Pumputis 45a9ea666e Add k8s integration test case for preserving client IP addr
Also, increase timeout for smoke tests to 360 sec.
2018-06-04 14:08:24 +02:00
Martynas Pumputis efd5d0e410 Add /client_ip to network-tester
The endpoint is going to be used by --no-masq-local integration tests.
2018-06-04 14:08:24 +02:00
Martynas Pumputis 6dbe95a0b5 Add NO_MASQ_LOCAL to weave-kube/launch.sh
One can enable the feature by setting NO_MASQ_LOCAL=1 among
env vars of the weave-kube DaemonSet.
2018-06-04 14:08:24 +02:00
Martynas Pumputis a0ec06a487 Destroy weave-no-masq-local ipset upon "weave reset" 2018-06-04 14:08:24 +02:00
Martynas Pumputis ebf4b4b48a Implement and start using NoMasqLocalTracker
The tracker updates the "no-masq-local" ipset with CIDR ranges allocated
by IPAM.
2018-06-04 14:08:24 +02:00
Martynas Pumputis 4f99efaaf4 Export tracker.RemoveCommon and tracker.Merge
It's going to be used by NoMasqLocalTracker.
2018-06-04 14:08:24 +02:00
Martynas Pumputis 62c30d9130 Extern LocalRangeTracker interface with String method
Cleaner approach than passing a tracker name to ipam/http.
2018-06-04 14:08:24 +02:00
Martynas Pumputis 21fb953d0f Create weave-no-masq-local ipset
The ipset is used to track locally allocated CIDRs. If requested,
external traffic sent to pods within these CIDR ranges will
avoid SNAT'ing (NYI).
2018-06-04 14:08:24 +02:00
Martynas Pumputis 27c98070e8 Move npc/ipset package to net/ipset
It's going to be used by net/bridge.go.
2018-06-04 14:08:24 +02:00
Martynas Pumputis 039750a7fa Re-expose weave bridge in EnsureBridge
This ensures that all exposing-related iptables rules are created.

As we do the re-expose, we need to clear the WEAVE-EXPOSE chain
if such exists. Thus, we use ClearChain instead of NewChain to
create the chain.
2018-06-04 14:06:09 +02:00
Bryan Boreham 9b0d1bd054 Set Kubernetes NodeNetworkUnavailable to false when starting 2018-05-26 14:06:57 +00:00
Bryan Boreham 4c1c2a5661 Add --max-list-size option for ipset lists
and default it to 1024 for cases where the size is fixed by the kernel
2018-05-25 17:24:22 +00:00
Bryan Boreham 791d9aecfc Extend k8s test to cover namespaceSelector and >10 Namespaces 2018-05-25 17:24:22 +00:00
Bryan Boreham 48aaac90fb Merge pull request #3277 from weaveworks/ml-release-docs
Add instruction for validating whether imgs were pushed for all platforms
2018-05-23 13:51:38 +01:00
Martynas Pumputis bfaa3a3a92 Merge pull request #3278 from weaveworks/seeded-docs
Add instructions for 'seeded by different peers' message
2018-05-22 17:23:06 +02:00
Martynas Pumputis 6dce685105 Merge remote-tracking branch 'origin/2.3' 2018-05-22 17:21:03 +02:00
Martynas Pumputis 8c4e33faef Merge pull request #3301 from Nodraak/nodraak-doc
[Docs] Improve the installation page concerning firewall
2018-05-22 17:14:19 +02:00
Adrien Chardon 81582b04f9 Add firewall warning on installation page 2018-05-16 14:23:35 +02:00
Marc Carré dbcc72a6f6 Merge pull request #3299 from weaveworks/add-opencontainers-labels-to-dockerfiles
Add org.opencontainers.image.* labels to Dockerfiles
2018-05-15 09:44:39 +01:00
Marc Carré 9f207f161a Add org.opencontainers.image.* labels to Dockerfiles
- This should ultimately help for image-to-code back references.
- `org.label-schema.*` labels are now deprecated, in favour of `org.opencontainers.image.*` labels.
  See also: https://github.com/opencontainers/image-spec/blob/master/annotations.md#back-compatibility-with-label-schema
- Git revision is now injected at `docker build` time.
2018-05-14 11:51:40 +01:00
Bryan Boreham 1ee4039681 Add build constraint for go1.10 onwards 2018-05-03 07:15:36 +01:00
Bryan Boreham 3203814940 Merge pull request #3283 from weaveworks/note-ip-forward
Add note about ip forward setting
2018-05-02 13:58:32 +02:00
Bryan Boreham acc8c33260 Merge pull request #3284 from weaveworks/docs-k8s-src-ip
Add docs/k8s-src-ip.md
2018-05-02 13:58:15 +02:00
Bryan Boreham 22ecf505e3 Added note about security implications of enabling IP forwarding 2018-05-02 06:06:58 +01:00
Bryan Boreham c2c14410d2 Remove subprocess for changing netns
Now that Go 1.10 has removed the issue which made us do this.
2018-04-30 23:40:59 +01:00
Martynas Pumputis ba578c91a7 Merge pull request #3268 from weaveworks/try-dep
Convert vendoring from git submodules to copy, using 'dep'
2018-04-27 16:04:00 +02:00
Bryan Boreham 7b46391e30 Add vendor instructions 2018-04-27 14:34:49 +01:00
Bryan Boreham ae551cafea Run manifest-tool from a container image
The source code has incompatible dependencies so we can't build it.
2018-04-27 14:34:49 +01:00
Bryan Boreham 672c770dbe Rework /report handler to pull format from URL
Otherwise test 150 would fail - Gorilla mux was not handling a newline
in the format parameter.  This way you also get a better error if you
have an error in the parameter - instead of a 404.
2018-04-27 14:34:49 +01:00
Bryan Boreham 847046a225 Update to match upstream changes 2018-04-27 14:34:48 +01:00
Bryan Boreham 4da998ab45 Move to lower-case logrus import 2018-04-27 14:34:48 +01:00
Bryan Boreham b534ea60f5 Copy dependencies into vendor dir, using dep 2018-04-27 14:34:48 +01:00
Bryan Boreham 549ccff5eb Don't need to update submodules to build exes 2018-04-27 14:34:47 +01:00
Bryan Boreham 9cf6749b2e Remove vendor submodules 2018-04-27 14:34:47 +01:00
Martynas Pumputis d2999cf1d7 Add docs/k8s-src-ip.md 2018-04-24 14:02:29 +02:00
Bryan Boreham 391b55ceaf Add note about ip forward setting 2018-04-23 14:24:44 +01:00
Bryan Boreham e05345d3bb Add instructions for 'seeded by different peers' message 2018-04-17 10:24:00 +01:00
Martynas Pumputis 67bd54e55d Add instruction for validating whether imgs were pushed for all platforms 2018-04-10 12:41:24 +02:00
Martynas Pumputis 20919fd6db Add release v2.3.0 2018-04-09 14:56:31 +00:00
Martynas Pumputis ada2af04ff Merge pull request #3271 from weaveworks/metrics-addr
Only expose metrics by default in weave-kube
2018-04-09 15:05:22 +02:00
Bryan Boreham fcb6f762a9 Review feedback 2018-04-09 13:42:09 +01:00
Bryan Boreham 5645f31934 Update docs for metrics endpoints 2018-04-09 13:11:29 +01:00
Bryan Boreham a7295e2d03 Mention metrics and status addresses in the docs 2018-04-09 11:55:50 +01:00
Bryan Boreham c3e6ac2cac Merge pull request #3273 from weaveworks/go1.10.1
Use go1.10.1 for building
2018-04-09 11:40:11 +01:00
Martynas Pumputis f1f3c8c8fe Use go1.10.1 for building 2018-04-09 09:46:45 +02:00
Bryan Boreham 81b2f2e15a Merge pull request #3266 from weaveworks/test-k8s-1-10
Update tests to run against Kubernetes 1.10
2018-04-04 15:17:42 +01:00
Bryan Boreham f6fdaf6492 Only expose metrics by default in weave-kube 2018-04-04 15:00:53 +01:00
Bryan Boreham 519c5d686a Remove test for k8s 1.6 which breaks on 1.10 2018-04-04 12:26:18 +01:00
Bryan Boreham f7e62ccbcc Bump Kubernetes to 1.10 2018-04-04 12:26:09 +01:00
Bryan Boreham 19161c0c92 Merge branch '2.2' 2018-03-30 19:17:18 +00:00
Bryan Boreham c528303841 Merge pull request #3265 from weaveworks/raise-kube-conn-limit
Raise weave-kube default connection limit from 30 to 100
2018-03-28 10:20:30 +01:00
Bryan Boreham a439288765 Raise weave-kube default connection limit from 30 to 100
This was missed from 265bfcf
2018-03-27 21:06:41 +00:00
Bryan Boreham 416410912d Merge pull request #3263 from weaveworks/faq-unique-peers
Add 'peer names collision' to FAQ
2018-03-23 15:14:21 +00:00
Bryan Boreham b3f26f00e2 Add some hints how to set the unique ID 2018-03-23 14:55:54 +00:00
Bryan Boreham 90e6ecdd11 Add 'peer names collision' to FAQ 2018-03-23 14:10:05 +00:00
Marc Carré 842354bc5a Add links from email received from Docker Store. 2018-03-20 10:30:52 +00:00
Marc Carré 4d3875cec2 Add details on email for Docker Store release. 2018-03-20 10:29:50 +00:00
Marc Carré 74dfe49046 Fix format in Docker Store instructions. 2018-03-19 14:19:47 +00:00
Marc Carré d0f23ed9e0 Document Docker Store release process. 2018-03-19 11:49:40 +00:00
Martynas Pumputis 8a0992315e Merge branch '2.2' 2018-03-12 18:27:04 +01:00
Martynas Pumputis 18b5cb10dc Add release v2.2.1 2018-03-12 15:02:36 +01:00
Bryan Boreham 8afc6f208d Merge pull request #3253 from NathanHaim/issues/3245_change_golang_version
Update golang version to 1.10
2018-03-12 12:11:30 +00:00
Martynas Pumputis d35d931179 Fix invalid format in ipam/testutils_test.go
Caught after upgrading Go to 1.10 in build tools.
2018-03-12 11:04:41 +00:00
NathanHaim 093174e757 add golang:1.10.0 2018-03-11 23:08:41 +01:00
Martynas Pumputis ac78762910 Merge branch '2.2' 2018-03-08 14:38:46 +01:00
Martynas Pumputis fff656f7e4 Merge pull request #3235 from weaveworks/wait-5-sec
Wait 5 seconds to let pod connect before rolling next pod
2018-03-08 14:36:11 +01:00
Martynas Pumputis 83b36e4c76 Merge branch '2.2' 2018-03-08 14:26:32 +01:00
Martynas Pumputis b42895b5c0 Merge pull request #3250 from alok87/del_default_ipset
Delete defaultAllowIPSet on namespace delete

Fix #3247

Duplicate merge commit as the PR got merged to "master" instead of "2.2"
2018-03-08 14:22:33 +01:00
Martynas Pumputis 42e4b9addc Merge pull request #3250 from alok87/del_default_ipset
Delete defaultAllowIPSet on namespace delete

Fix #3247
2018-03-08 14:01:10 +01:00
alok87 91ab0e4a76 Clean defaultAllowIPSet on namespace delete 2018-03-05 22:52:56 +05:30
NathanHaim 51feec3785 change golang version 2018-03-05 02:46:35 +01:00
Bryan Boreham 20eee3818e Merge pull request #3236 from weaveworks/apk-ca-certs
Install ca-certificates instead of copying them
2018-02-28 17:00:31 +00:00
Bryan Boreham 94cd6226ea Merge branch '2.2' 2018-02-28 16:58:22 +00:00
Bryan Boreham 5534ecf1b1 Merge pull request #3237 from weaveworks/issues/3222-dst-selector
Fix bug when dstSelector is overwritten by srcSelector
2018-02-28 16:56:07 +00:00
Bryan Boreham d498df3933 Merge branch '2.2' 2018-02-28 10:32:45 +00:00
Bryan Boreham 75bf62ca80 Merge pull request #3234 from weaveworks/raise-conn-limit
Raise default connection limit from 30 to 100
2018-02-26 17:15:56 +00:00
Marc Carré ad42357dd6 Improve formatting. 2018-02-21 10:31:04 +00:00
Marc Carré 2de899342a Improve naming consistency. 2018-02-21 10:30:35 +00:00
Marc Carré 8df48dc69d Document how to pull submodules on first checkout: git submodule update --init 2018-02-21 10:25:33 +00:00
Marc Carré 0f2809d2e9 Document how to pull submodules on first checkout: git submodule update --init 2018-02-21 10:23:08 +00:00
Marc Carré aa44153af7 Minor typos and improvements. 2018-02-21 10:19:38 +00:00
Bryan Boreham ce9c5162bd Merge pull request #3238 from weaveworks/fix-k8s-weave-passwd-howto
Fix HOWTO for setting weave-kube passwd
2018-02-04 16:29:14 +00:00
Martynas Pumputis 5c0da56ad5 Fix HOWTO for setting weave-kube passwd
A quick fix.

LG generates secretKeyRef.key w/o the ".txt" extension which makes it
inaccessible to weave-kube when passwd is stored in "weave-passwd.txt".
2018-02-04 14:43:41 +01:00
Martynas Pumputis 08858c2a10 npc: Fix bug when dstSelector is overwritten by srcSelector
There was a bug in the npc analyser when adding a netpol with
dstSelector == srcSelector. The analyser was overwriting
dstSelector with srcSelector which resulted in Pod selected
by dstSelector not being removed from a corresponding
"default-allow" ipset.

This applies only to non-legacy netpols.
2018-02-04 13:23:38 +01:00
Martynas Pumputis 0268aeb25f Install ca-certificates instead of copying them
There is a package for alpine:
https://pkgs.alpinelinux.org/packages?name=ca-certificates&branch=v3.6
2018-02-01 14:44:00 +01:00
Bryan Boreham ea3aba8971 Wait 5 seconds to let pod connect before rolling next pod 2018-01-31 10:54:07 +00:00
Bryan Boreham 265bfcf9d7 Raise default connection limit from 30 to 100 2018-01-31 10:48:05 +00:00
Bryan Boreham 7a9fae5892 Add release v2.2 2018-01-30 12:10:05 +00:00
Martynas Pumputis f66b0cc0aa Merge pull request #3196 from weaveworks/issues/1770-proxy-dns-address
Make proxy use configured WeaveDNS address
2018-01-29 17:20:03 +01:00
Bryan Boreham e7f30106c0 Pass the WeaveDNS Domain into the proxy
instead of obtaining it via the http api
2018-01-29 15:55:36 +00:00
Bryan Boreham 86d2800b59 Make proxy use configured WeaveDNS address
rather than assuming it is listening on the weave bridge
2018-01-29 15:55:36 +00:00
Bryan Boreham e65006042d Remove obsolete --dns-effective-listen-address parameter
it was needed when we ran inside a container network namespace
2018-01-29 15:55:36 +00:00
Bryan Boreham 65efc89b78 Merge pull request #3227 from weaveworks/issues/3223-update-miekgdns
Update miekg/dns to 1.0.4
2018-01-29 15:49:45 +00:00
Bryan Boreham ae38834507 Merge pull request #3229 from weaveworks/k8s-1.9
Update k8s in CI to 1.9.2 and fix flaky tests
2018-01-29 15:49:06 +00:00
Martynas Pumputis 4261777613 Remove "-j KUBESERVICES" during teardown in 840 smoke test
Remove the rule to ensure that api-server is not accessible while
kube-proxy is not ready.

Otherwise, we have a race between "-j KUBE-FORWARD" and "-j WEAVE-NPC"
which makes the NodePort isolation test case to fail.
2018-01-29 16:20:22 +01:00
Martynas Pumputis 7bc089f5c5 Add iproute2 scope info to assertions
The latest alpine linux changed iproute2 of busybox which now
includes scope info.
2018-01-29 16:20:22 +01:00
Martynas Pumputis c46e3e8cf7 Skip CA verification in k8s smoke tests 2018-01-29 16:20:22 +01:00
Martynas Pumputis 180d554205 Do not pin k8s vsn in 840 smoke test 2018-01-29 16:20:22 +01:00
Martynas Pumputis a450d2e741 Bump CI k8s vsn to 1.9.2 2018-01-29 16:20:22 +01:00
Bryan Boreham d528196033 Merge pull request #3224 from weaveworks/fix-ipt-rules-order
Fix subnet isolation and bump build-tools to latest
2018-01-29 15:19:13 +00:00
Martynas Pumputis 0da2cbf84e Update build-tools to include the defunct process fix 2018-01-29 15:52:24 +01:00
Martynas Pumputis 20f981bc42 Update miekg/dns to 1.0.4
Includes the fix for CVE-2017-15133.
2018-01-29 13:55:03 +01:00
Martynas Pumputis 9a5514ffe0 Add comment about the FORWARD rule order
Should help debugging.
2018-01-20 14:44:40 +01:00
Martynas Pumputis 439b4ad190 Improve naming of ensureRulesAtTop function 2018-01-20 12:51:31 +01:00
Martynas Pumputis 9a9c06966b Bring the weave bridge isolation iptables rule to the top
Make the rule creation to use the same mechanism (via ensureRules)
as other rules from filter/FORWARD. Otherwise, the rule is preceded
by "-j WEAVE-EXPOSE" rule which can break the subnet isolation.
2018-01-20 12:47:11 +01:00
Martynas Pumputis b3f9baac8f Merge pull request #3210 from weaveworks/issues/3209-npc-rules-first
Move weave-npc checks to top of FORWARD chain

Fixes #3209
2018-01-14 12:45:18 +01:00
Bryan Boreham bb961489b0 Merge branch '2.1' 2018-01-12 10:47:29 +00:00
Bryan Boreham d6ae1f8375 Add CONN_LIMIT to kube-addon docs 2018-01-12 09:48:30 +00:00
Bryan Boreham 5a1361167e Move our rules to the top of the FORWARD chain
We want our DROP rule to be executed ahead of any ACCEPT rules which
might have been added by another program on the system.
2018-01-11 15:35:19 +00:00
Bryan Boreham 4d5172f67e Run test with Kubernetes 1.8.5 and --cluster-cidr 2018-01-11 15:24:25 +00:00
Bryan Boreham 6f01c31458 Extend kubernetes test to nodePort and virtual IP 2018-01-11 15:24:25 +00:00
Bryan Boreham 6cfb208f3f Merge pull request #3204 from weaveworks/issues/3133-idempotent-bridge
Do not skip bridge creation if bridge exists
2018-01-09 17:20:06 +00:00
Bryan Boreham 3074892f1b Merge pull request #3216 from weaveworks/update-release-process
Update docs release process
2018-01-09 17:18:58 +00:00
Brice Fernandes b05d977cf9 Merge pull request #3217 from weaveworks/improve-test-readme
Improve instructions for running tests against a remote cluster
2018-01-09 17:08:49 +00:00
Brice Fernandes 36d183d988 Improve readme 2018-01-09 14:51:25 +00:00
Brice Fernandes b154fd56fb Fix typo 2018-01-09 13:58:07 +00:00
Brice Fernandes 3419f69246 Make sure to mention Ansible in instructions 2018-01-09 13:41:02 +00:00
Bryan Boreham 8e23301028 Merge pull request #3214 from weaveworks/vagrant-more-mem
Give more memory to vagrant test machines
2018-01-08 17:36:59 +00:00
Bryan Boreham 72724ee389 Merge pull request #3215 from weaveworks/fix-k8s-use-legacy-mode-docs
Fix link to k8s legacy netpol docs
2018-01-08 17:36:29 +00:00
Brice Fernandes ae59a053b1 Improve readme formatting 2018-01-08 16:45:00 +00:00
Brice Fernandes e71919226b Add cloud build instructions to test readme 2018-01-08 16:38:22 +00:00
Martynas Pumputis 6c5dd75216 Merge pull request #3183 from weaveworks/trim-npc-json
Trim the JSON logged for Kubernetes objects by weave-npc
2018-01-06 17:51:34 +01:00
Bryan Boreham 23095728f5 Merge branch '2.1' 2018-01-06 15:41:56 +00:00
Martynas Pumputis 498dacb4d2 Update docs release process 2018-01-06 14:55:01 +01:00
Martynas Pumputis b373a069e9 Fix link to k8s legacy netpol docs 2018-01-06 14:48:20 +01:00
Martynas Pumputis 1d67e2f955 Add test case for restoring iptables rules after weaver restart 2018-01-06 13:20:02 +01:00
Martynas Pumputis 9a6935bf40 Give more memory to vagrant test machines
To be able to run k8s smoke tests.
2018-01-06 12:48:17 +01:00
Martynas Pumputis 921ffefd90 Ensure the order of filter/FORWARD iptables rules 2018-01-05 08:33:50 +01:00
Bryan Boreham a4fccd43eb Merge pull request #3185 from weaveworks/note-kube-dns
Note that WeaveDNS is disabled in Kubernetes addon
2018-01-04 14:57:14 +00:00
Bryan Boreham 48e1a8295b Update Kubernetes docs info 2018-01-04 15:01:06 +00:00
Bryan Boreham 890c8c1905 Extend description of weave-kube
and mention WeaveDNS is disabled
2018-01-04 14:59:43 +00:00
Bryan Boreham 38d50ce6fb Note that WeaveDNS is disabled in Kubernetes addon 2018-01-04 14:59:43 +00:00
Martynas Pumputis 14768d6947 Add smoke test for bridge re-creation after restart 2017-12-22 10:39:02 +01:00
Bryan Boreham b96399b563 Merge branch '2.1' 2017-12-20 16:10:58 +00:00
Bryan Boreham d8c008dc7d Merge pull request #3203 from weaveworks/mac-messages-to-debug
Demote messages about MAC discovery and expiry to DEBUG level
2017-12-20 11:29:27 +00:00
Bryan Boreham b2ae5f4f4b Demote messages about MAC discovery and expiry to DEBUG level 2017-12-18 11:36:24 +00:00
Bryan Boreham ba871d7855 Merge branch '2.1' 2017-12-18 11:25:30 +00:00
Martynas Pumputis a0c8fc2ddb Pass WEAVE_NO_BRIDGED_FASTDP to weaver 2017-12-17 19:05:12 +01:00
Martynas Pumputis 2a12053122 Do not skip bridge initialization if such exists
EnsureBridge used to skip creation and initialization of the weave
bridge and friends if such existed. This caused problems when
EnsureBridge failed before completing all init steps and so, subsequent
weaver could not work without "weave reset".

This change makes EnsureBridge idempotent.
2017-12-17 18:51:05 +01:00
Martynas Pumputis 1860f21efb Remove "create_bridge" routines
No longer needed in the weave script and thus, in weaveutil.
2017-12-16 21:19:25 +01:00
Martynas Pumputis 541adf6bb1 Make "weave attach" to depend on running weaver
"weave attach $CIDR $CONTAINER_ID" is no longer possible w/o
running weaver. This feature was undocumented and complicated
the weave script, as "weave attach" required to call "create_bridge".
Removing the feature allows us to eliminate the bridge creation
from the script.

Running "weave attach" w/o weaver results in the following err:

    bridge "weave" not present; did you launch weave?

Also, this commit simplifies the "attach-container" cmd from
weaveutil by removing "mtu" as a param. The cmd is used
only by "weave attach", and a mtu is value for an attached
container interface is exactly the same as one of the weave bridge.
2017-12-16 21:17:45 +01:00
Martynas Pumputis a71e90ddb8 Do not create bridge upon "weave expose" or "weave hide"
Both cmds depend on running weaver which creates the bridge
during its initialization. So, calling "create_bridge"
during execution of the cmds is redundant.
2017-12-16 20:52:24 +01:00
Bryan Boreham 60f4b3cdb8 Merge pull request #3198 from weaveworks/explain-active
Add meaning of 'active' in 'weave status ipam'
2017-12-15 11:53:43 +00:00
Martynas Pumputis 0c249fa126 Update netlink dependency
To include LinkNotFoundError.
2017-12-14 16:56:59 +01:00
Bryan Boreham db1b57900b Merge pull request #3197 from vetal4444/log_level_setting
Add ability to set log level for net-plugin, and default to INFO
2017-12-14 12:26:01 +00:00
Shevchenko Vitaliy 12b4898b3d Add ability to set log level for net-plugin 2017-12-14 14:19:33 +02:00
Bryan Boreham f5f9bab77c Add meaning of 'active' in 'weave status ipam' 2017-12-14 10:18:53 +00:00
Bryan Boreham ba7aa674d1 Merge branch '2.1' 2017-12-04 15:03:02 +00:00
Bryan Boreham f670be4315 Add release v2.1.3 2017-12-04 14:38:05 +00:00
Bryan Boreham a658861fde Merge pull request #3189 from weaveworks/release-latest-plugin
Fix release script for plugin latest_release
2017-12-04 06:33:02 -08:00
Bryan Boreham 192e5a1f79 Merge branch '2.1' 2017-12-04 13:51:30 +00:00
Bryan Boreham 475b15e372 Merge pull request #3192 from weaveworks/issues/3190-deepcopy-configmaps
Fix ipam reclaim
2017-12-01 12:33:48 -08:00
Bryan Boreham d2ed91ccc8 Clean up log messages a bit 2017-12-01 14:20:39 +00:00
Bryan Boreham 333f4a1d3c Make sure Annotation names conform to Kubernetes requirements.
E.g. replace "26:c6:0b:ba:fd:31" with "26_c6_0b_ba_fd_31"
2017-12-01 14:20:39 +00:00
Bryan Boreham 832fe2f0b0 Update local copy of annotations even after error
e.g. if we get a clash because someone else has updated the data, it
returns the new data so we should work off that next time.

Also re-fetch the Annotations every time round the main loop for safety.
2017-12-01 14:20:39 +00:00
Martynas Pumputis ea76185873 Update k8s netpol docs
- Mention `--use-legacy-netpol` flag.
- Link to NetworkPolicy from 1.7.
2017-12-01 14:20:21 +00:00
Bryan Boreham 51c3ea184a Fix release script for plugin latest_release
We should never update the latest_release plugin on a PRERELEASE.
We should always update it on a MAINLINE or BRANCH release.
2017-11-27 15:04:39 +00:00
Bryan Boreham 692bccc4fc Merge branch '2.1' 2017-11-27 15:03:48 +00:00
Bryan Boreham 59fe76f29b Add release v2.1.2 2017-11-27 14:06:33 +00:00
Bryan Boreham 51c2a0d732 Merge pull request #3174 from weaveworks/issues/docs-use-legacy-netpol
Update k8s netpol docs
2017-11-27 12:45:59 +00:00
Bryan Boreham 2ab01b55c9 Merge branch 'master' into 2.1 2017-11-27 11:45:15 +00:00
Bryan Boreham 461f9e736b Merge pull request #3186 from weaveworks/issues/3184-update-mesh
Update vendored mesh dep
2017-11-27 11:34:15 +00:00
Bryan Boreham 8e16b03ae8 Merge pull request #3181 from weaveworks/issues/3177-ooo
npc: Track ipset entries per user and refcount default-allow ipsets
2017-11-27 11:01:59 +00:00
Martynas Pumputis 6469809b9a Update vendored mesh dep 2017-11-22 16:07:19 +02:00
Bryan Boreham 0205adcedb Trim the JSON logged for Kubernetes objects by weave-npc
Remove things like "args" and "env" which bulk the logs, aren't
relevant to the function of weave-npc, and may include sensitive
information.

Use a black-list rather than a white-list because we can't be sure
what information will be necessary in future.
2017-11-22 11:17:50 +00:00
Martynas Pumputis 0a0dbe115a npc: Track ipset entries per user
There was a bug in handling "default-allow" ipsets - it could not
cope with out of order receive of Pod updates. E.g:

    1) AddPod(Pod_A, PodIP_A),
    2) AddPod(Pod_B, PodIP_A),
    3) DeletePod(Pod_A),

would result with PodIP_A being removed from "default-allow" ipset,
as such ipset entries were not refcounted. Bypassing of refcounting
was due to the fact that adding a netpol which dst-selects a Pod which
IP addr is in "default-allow" ipset has to remove the IP addr from
the ipset regardless of refcount value of the IP addr entry in the
ipset. So, refcounting in such case didn't make sense and it was
bypassed.

This commit changes the way entries are refcounted in ipsets, and
it makes "default-allow" ipset the same citizen as other ipsets, so
from now "default-allow" ipset is refcounted.
2017-11-21 14:41:29 +02:00
Bryan Boreham ebbf3d4244 Add release v2.1.1 2017-11-17 14:17:31 +00:00
Bryan Boreham ceb36d1891 Typo 2017-11-17 14:15:10 +00:00
Bryan Boreham 4caa850853 Merge pull request #3176 from weaveworks/issues/3175-fix-install
Fix 2.1.0 install issues
2017-11-17 14:14:41 +00:00
Bryan Boreham 96cecf1796 Pull images before running inside weaveexec container
Now we don't bundle the docker command inside weaveexec, we need to do
an explicit 'docker pull' to ensure the images are there.

Also set the weavedb tag to :latest to remove a warning from docker
2017-11-17 13:51:10 +00:00
Bryan Boreham 51c7af8fb4 Set IMAGE before using it 2017-11-17 13:31:46 +00:00
Bryan Boreham 347466aba2 Add release v2.1.0 2017-11-17 11:10:52 +00:00
Bryan Boreham bee1c44859 Merge pull request #3173 from weaveworks/reclaim-tweaks
Rearrange peer reclaim checks in weave-kube launch script
2017-11-16 17:05:46 +00:00
Martynas Pumputis a3fd36e2bb Update k8s netpol docs
- Mention `--use-legacy-netpol` flag.
- Link to NetworkPolicy from 1.7.
2017-11-16 17:00:27 +02:00
Bryan Boreham f07238c8bb Move info log to after error check 2017-11-16 14:31:40 +00:00
Bryan Boreham 3b499ce27c Rearrange peer reclaim checks in weave-kube launch script
This is to make it behave better on fresh start, and in the case where
the manifest has not been updated to give it permissions.
2017-11-16 14:14:54 +00:00
Bryan Boreham 4dda216398 Merge pull request #3172 from weaveworks/issues/3170-fix-upgrade
weave-kube reclaim: check for upgrade case
2017-11-15 17:59:54 +00:00
Bryan Boreham f0e511510a Don't print a message on flag not found 2017-11-15 12:35:19 +00:00
Bryan Boreham 570ab0b10b Avoid deleting persisted data on weave-kube upgrade
Add a feature to weaveutil to get and set flags, then use this feature
to mark the DB when this version runs
2017-11-15 11:26:43 +00:00
Bryan Boreham 214cf6cb2e Flip result code when checking for new peer
This avoids mistaking an error condition for the result we should act on
2017-11-15 10:11:02 +00:00
Bryan Boreham 07459f0cec Merge pull request #3149 from weaveworks/fix-2797-loosing-ipam-ips
Fix 2797 on Kubernetes - Cluster goes down because all IPs become unreachable
2017-11-14 15:31:06 +00:00
Brice Fernandes 90f4f7b62c Add test to ensure that weave recovers unreachable IPs on launch 2017-11-14 14:18:21 +00:00
Brice Fernandes 987ac98fbf Add up command to integration tests to make launching cluster easier 2017-11-14 14:16:01 +00:00
Brice Fernandes 49ed40a301 Add test function to recover clean output from command run on remote host 2017-11-14 14:16:01 +00:00
Bryan Boreham c67bc704e1 Temporarily raise kube-peers log level to debug 2017-11-14 14:16:01 +00:00
Bryan Boreham 3501ad45e6 Cope with a Kubernetes node being deleted and coming back
Add features to weaver and kube-peers to find the peer name and check
if it is in the list, then in launch.sh delete persisted data if not.
2017-11-14 14:15:31 +00:00
Bryan Boreham 70a13c9c12 Make kube-peers logging consistent and add -log-level flag
Also tag kube-peer log messages with "[kube-peers]": in a standard
deployment they end up interspersed with weaver log messages so this
makes it easier to pick them out.
2017-11-14 14:06:34 +00:00
Brice Fernandes 3afb8d3ddf Add log messages to detect dying peer edge case 2017-11-14 14:06:34 +00:00
Brice Fernandes fd2f91e2ee Refactor: Improve naming 2017-11-14 14:06:33 +00:00
Brice Fernandes cb0c9e5fba Document: Add file-level docstrings for kube-peers 2017-11-14 14:06:33 +00:00
Brice Fernandes 6a0e39e5ee Minor refactor for clarity 2017-11-14 14:06:33 +00:00
Bryan Boreham a552f194b4 Code to reclaim IP address space from removed peers 2017-11-14 14:06:33 +00:00
Bryan Boreham 267bd8b51d Pseudo-code to clean up dead peers 2017-11-14 14:06:33 +00:00
Brice Fernandes 497dddabc1 Improve config locking by using optimistic locking strategy
Loop using jitter until the update succeeds
2017-11-14 14:06:33 +00:00
Bryan Boreham 71b39489da Maintain a list of peers in a Kubernetes annotation
This is prework for a feature which will remove 'dead' peers
2017-11-14 14:06:33 +00:00
Bryan Boreham ed8d92cfc6 RBAC to read and write ConfigMaps 2017-11-14 14:06:33 +00:00
Bryan Boreham f431ee289b Refactor: create config in main function 2017-11-14 14:06:33 +00:00
Martynas Pumputis 7ea82204e0 Merge pull request #3089 from weaveworks/improve-flags
Improve flag handling
2017-11-13 17:31:33 +02:00
Bryan Boreham 44692b997c Merge pull request #3169 from weaveworks/issues/k8s-netpol-testing
Extend NetworkPolicy smoke tests
2017-11-13 15:30:48 +00:00
Bryan Boreham 21086a0b2a Merge branch '2.0' 2017-11-13 12:51:29 +00:00
Bryan Boreham d7119169df Add length to log message for too-big DF broadcast frame 2017-11-13 11:06:34 +00:00
Martynas Pumputis e1eb0a8617 npc: Fix typo 2017-11-13 10:41:45 +02:00
Martynas Pumputis cacc190764 npc: Extend NetworkPolicy test cases in 840
- Add a test case for default allow all ingress traffic.
- Fix misleading comment.
2017-11-13 09:40:07 +02:00
Brice Fernandes 89e5d935a6 Document test runner feature to pick number of hosts
Merge pull request #3164 from weaveworks/improve-test-docs
2017-11-09 17:00:31 +00:00
Brice Fernandes 884e1d7a6b Document test runner feature to pick number of hosts 2017-11-09 15:48:21 +00:00
Bryan Boreham 5b1ca02ecc Merge pull request #3151 from weaveworks/issues/3105-k8s-17-netpolicies-whitelist
Implement Kubernetes 1.7 NetworkPolicy semantics
2017-11-07 16:31:01 +00:00
Martynas Pumputis f51347feac npc: Address PR comments
* Add comments about presence of `analysePolicyLegacy` and `analysePolicy`.
* Use non-legacy netpol in TestRegressionPolicyNamespaceOrdering3059.
2017-11-07 15:40:58 +02:00
Martynas Pumputis b605b832ed npc: Extend k8s NetworkPolicy smoke tests
- Test that pods not matching ingress rules are not able to access
  the nettest pods.
- Test upgrading of NPC (from legacy to non-legacy).
- Test new semantics of k8s netpol.
2017-11-07 14:55:03 +02:00
Bryan Boreham e148b72284 Merge branch '2.0' 2017-11-06 11:48:29 +00:00
Bryan Boreham 16db921349 Merge pull request #3128 from weaveworks/k8s-notes
Added 'things to watch out for' section in Kubernetes instructions
2017-11-03 10:59:35 +00:00
Bryan Boreham 4c235b3648 Merge pull request #3160 from weaveworks/2017-11-02-update-gopacket
Update gopacket to latest master to benefit from memory optimization
2017-11-03 10:32:35 +00:00
Damien Lespiau 1a8d479227 Update gopacket to latest master to benefit from memory optimization
Upstream has done some work saving 133k allocated objects on startup (init()),
which translates into a saving of 30-50MB RSS memory.

Details: https://github.com/google/gopacket/pull/377#issuecomment-338984309
2017-11-02 17:07:31 +00:00
Matthias Radestock 7aad364116 Merge pull request #3158 from weaveworks/2.0
merge branch 2.0
2017-10-31 08:11:17 +00:00
Matthias Radestock 4958d9e423 Merge pull request #3156 from weaveworks/3153-v2-plugin-dockerhub
document using v2 plugin from dockerhub rather than store

Fixes #3153.
2017-10-31 07:08:50 +00:00
Matthias Radestock 474f1f3673 document using v2 plugin from dockerhub rather than store
Since the latter is hard to update and hence frequently out of date.

Fixes #3153.
2017-10-30 20:43:45 +00:00
Martynas Pumputis 9aa7044f1e npc: Add unit tests for default-allow ipsets 2017-10-22 19:42:08 +02:00
Martynas Pumputis 7c39f96d08 npc: Implement networking.k8s.io/v1/NetworkPolicy semantics (k8s 1.7)
The main difference between new and legacy (pre-1.7) netpol semantics
are the following:

    * The DenyDefault ingress isolation annotation is obsoleted.
    * Traffic is allowed to a pod if there are no netpol selecting
      the pod.

See https://kubernetes.io/docs/api-reference/v1.6/#networkpolicyspec-v1beta1-extensions
vs https://kubernetes.io/docs/api-reference/v1.7/#networkpolicyspec-v1-networking
for more details.

weave-npc can operate either in the legacy or the new mode (default). To
use the legacy, pass "--use-legacy-netpol" arg when starting the npc.

In non-legacy mode we create for each Namespace a default-allow ipset
which stores IP addrs of such Pods which are not selected by any
NetworkPolicy.The ipsets are dst's in rules of the WEAVE-NPC-DEFAULT chain.
2017-10-22 19:37:18 +02:00
Martynas Pumputis 3c3e0b0352 Enable access to "networkpolicies" of "networking.k8s.io" API group
Since 1.7, k8s netpol is no longer in beta, so NPC can start subscribing
from the non-beta API group.
2017-10-22 19:32:52 +02:00
Martynas Pumputis 8467742d6d Increase smoke test timeout from 240 to 300 sec
The 840 smoke test (k8s + npc) sometimes might take longer than 240 sec.
2017-10-22 19:29:52 +02:00
Martynas Pumputis 5cfc3f8c47 Bump k8s version in smoke tests to 1.7.8 2017-10-22 19:29:21 +02:00
Bryan Boreham 62dbe03193 Don't log nil errors in CNI DEL 2017-10-17 16:13:48 +00:00
Martynas Pumputis 8755da4b5a Add smoke tests to check FORWARDing after 'expose' 2017-10-17 12:08:43 +01:00
Martynas Pumputis 25cff16bd1 Create WEAVE-EXPOSE iptables chain
Docker 1.13 has changed a default policy of FORWARD chain to DROP
(https://github.com/moby/moby/pull/28257) which makes containers
inaccessible from a remote host when the bridge is exposed.

The change breaks e.g. the AWSVPC mode. To overcome this we install
an explicit rule for accepting forwarded ingress traffic to an
exposed subnet which is appended to the WEAVE-EXPOSE chain.

The chain is a target of the rule "-t filter -A FORWARD -o weave".
2017-10-17 12:08:43 +01:00
Martynas Pumputis ade6738789 Handle "weave expose" in weaver
The change makes "weave expose" to call the "/expose" HTTP
endpoint implemented in router which exposes the bridge.

Such architectural change required as we need to know whether NPC is
enabled when exposing the bridge and weaver knows this fact the best.

Unfortunately, this change makes impossible to "weave expose"
when weaver is not running.
2017-10-17 12:08:43 +01:00
Bryan Boreham ea0e3a14e0 Merge branch '2.0' 2017-10-17 10:17:25 +00:00
Bryan Boreham 4a1a1e83c8 Update Python 'setuptools' module to resolve issue
Symptom of issue was this message:

error in cryptography setup command: Invalid environment marker: platform_python_implementation != 'PyPy'
2017-10-17 10:17:06 +00:00
Bryan Boreham ee48700b40 Merge pull request #3141 from bjhaid/upgrade_client_go
Upgrading client go and vendoring its extra dependencies.
2017-10-11 16:08:00 +01:00
Bryan Boreham 0791ce8ab0 Merge branch '2.0' 2017-10-11 10:49:13 +00:00
Ayodele Abejide 1ac543aba7 Upgrading client go and vendoring it's extra dependencies. 2017-10-10 16:48:35 +00:00
Bryan Boreham 3d5f80630d Merge pull request #3142 from weaveworks/fixnotes
Fixnotes
2017-10-10 16:10:00 +01:00
abuehrle be2da07735 fix note pins 2017-10-10 09:46:35 -05:00
Martynas Pumputis 80b286ebf7 Merge pull request #3138 from weaveworks/issues/3136-fix-etc-hosts
Add back EXEC_IMAGE so proxy can docker-run itself

Fixes #3136
2017-10-05 13:14:16 +02:00
Bryan Boreham be412812f9 Remove unused variable assignment 2017-10-05 10:45:51 +00:00
Bryan Boreham bfed7c24f8 Merge pull request #3129 from mkumatag/ppc64le_suuport
Add ppc64le support
2017-10-04 17:29:30 +01:00
Bryan Boreham fe859952e0 Merge branch '2.0' 2017-10-04 16:05:07 +00:00
Brice Fernandes 6bc69199d3 Merge pull request #3135 from weaveworks/fix-build-osx
Fix builds on OSX
2017-10-04 14:00:18 +01:00
Brice Fernandes 292cbc484a Fix other occurences of GNU-specific sed invocation 2017-10-04 12:12:28 +01:00
Brice Fernandes 1a98cbfff9 Ignore sed backup files 2017-10-04 12:03:12 +01:00
Brice Fernandes 071f077cc5 Fix broken builds on OSX due to BSD vs GNU sed 2017-10-04 11:58:14 +01:00
Damien Lespiau b157544394 Bump license copyright year to 2017 (#3132) 2017-10-03 14:52:03 +01:00
Matthias Radestock 18f65a1914 fix typo 2017-10-01 21:12:29 +01:00
Bryan Boreham df688cfb53 Added weave_ipam_unreachable_percentage metric 2017-09-26 15:55:38 +00:00
Bryan Boreham 88679d66fc Improve wording 2017-09-26 15:53:14 +00:00
Carlos Alexandro Becker ab1cbcbbf8 prometheus: export count of unreachable peers (#3119)
* prometheus: export count of unreachable peers
* extracted part of printIPAMRanges
2017-09-26 16:50:10 +01:00
Bryan Boreham a02fb753df Use the configured Docker host for the proxy, not the default one 2017-09-26 09:44:46 +00:00
Bryan Boreham 98b002f7c0 Remove unnecessary 'Version' in proxy 2017-09-26 09:44:46 +00:00
Bryan Boreham e251bfe807 Move use of command-line params to after we know them 2017-09-26 09:44:46 +00:00
Bryan Boreham eb88893312 Rename configureProxy to newProxyConfig 2017-09-26 09:44:46 +00:00
Bryan Boreham a362bf68bb Merge branch '2.0' 2017-09-26 09:41:29 +00:00
Manjunath A Kumatagi b0f78e97f4 Add ppc64le support 2017-09-26 13:49:35 +05:30
Bryan Boreham 2e7f44feee Added 'things to watch out for' 2017-09-25 16:36:57 +00:00
Matthias Radestock 48ceb49832 refactor: inline and simplify proxy_addrs() 2017-09-18 09:16:37 +01:00
Matthias Radestock dd772f04fe cosmetic: move cidr functions to better place 2017-09-18 08:57:50 +01:00
Matthias Radestock 47597c941d refactor(ish): create volumes just before weave container
It's the most logical sequencing and reduces the chances of debris
being left behind when things go wrong.
2017-09-18 08:49:02 +01:00
Matthias Radestock c0e8af56e2 refactor: inline attach() 2017-09-18 08:24:13 +01:00
Matthias Radestock 72c0172c48 refactor: inline rewrite_etc_hosts 2017-09-18 07:37:01 +01:00
Matthias Radestock 507f5345c5 refactor: inline kill_container 2017-09-18 07:24:34 +01:00
Matthias Radestock 79d4aec1ec cosmetic: move kill_container to correct section 2017-09-18 07:18:27 +01:00
Matthias Radestock 89c7e6d337 refactor weave setup for clarity 2017-09-17 16:33:37 +01:00
Bryan Boreham b8d7af3822 Don't call 'docker pull' inside weaveexec 2017-09-16 18:51:58 +00:00
Bryan Boreham 3c9c968174 Merge pull request #3110 from dtshepherd/issues/2957-rm-docker-binary-from-weaveexec
Remove docker binary from weaveexec container
2017-09-13 13:38:07 +01:00
David Shepherd 38ca0f90c7 Simplify mac generation on attach|expose|hide
`weaveexec` no longer mounting '/' so we can't access the weavedb file
to get persistent peer ID.  If `weaver` was running, we couldn't have
read the file anyway because BoltDB does not support concurrent access
from two processes.

Consequence is that if someone really does need the bridge creation on
'weave expose' the peer ID may change if created pre-1.9.0.  We'll just
live with that (per @bboreham).
2017-09-13 08:04:04 -04:00
David Shepherd 8bf08c3cf8 Remove docker binary from weaveexec container
Fixes #2957

- replace `docker stop` with `weaveuitl stop-container`
- replace `docker kill` with `weaveutil kill-container`
- replace `docker rm` with `weaveutil remove-container`
- replace `docker run` with minimal `weaveutil container-run`
- replace `docker inspect -f {{.ID}}` with `weaveutil container-id`
- replace data-only container `docker create` with `weaveutil create-volume-container`
- remove `docker inspect` dependencies from `weave` script
  `rewrite_etc_hosts` and `with_container_fqdn`
- rework `weave` script `check_running` and `check_not_running` to use `weaveutil`
- rework `weave version` to use `weaver` /report API or `weaver --version` if not running
- rework `weave setup`'s `docker pull` to run locally rather than in `weaveexec` container
2017-09-13 08:03:58 -04:00
Martynas Pumputis 14c79d2184 Merge remote-tracking branch 'origin/2.0' 2017-09-09 13:17:29 +02:00
Bryan Boreham c0388c0136 Improve "What is Weave Cloud" link 2017-09-07 20:32:24 +01:00
Bryan Boreham aeca987a4c Merge branch '2.0' 2017-08-25 15:25:55 +00:00
Bryan Boreham ff1cd7c008 Merge branch '2.0' 2017-08-23 11:18:52 +00:00
Bryan Boreham 4b720bffdf Merge branch '2.0' 2017-08-18 14:02:58 +00:00
Bryan Boreham 5c210c90b5 Merge branch '2.0' 2017-08-16 16:37:29 +00:00
Bryan Boreham 2ede1066e9 Remove unused WeaveDomain
(left over from a22b88ed89)
2017-08-14 13:56:53 +00:00
3021 changed files with 950378 additions and 6243 deletions

No files matched your search

+6 -2
View File
@@ -33,6 +33,9 @@ coverage.html
# Vim backup files
*.swp
# Sed backup files
*.bak
# Project specific
prog/weaver/weaver
prog/weavedns/weavedns
@@ -43,8 +46,8 @@ 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/kube-utils/kube-utils
prog/weave-kube/kube-utils
prog/weave-npc/weave-npc
prog/plugin/plugin
testing/cover/cover
@@ -65,6 +68,7 @@ test/tls/tls
test/tls/*.pem
test/coverage
test/coverage.*
test/images/network-tester/webserver
*qemu-*-static
terraform.tfstate
terraform.tfstate.backup
-132
View File
@@ -1,135 +1,3 @@
[submodule "tools"]
path = tools
url = https://github.com/weaveworks/build-tools
[submodule "vendor/github.com/vishvananda/netlink"]
path = vendor/github.com/vishvananda/netlink
url = https://github.com/vishvananda/netlink.git
[submodule "vendor/github.com/gorilla/mux"]
path = vendor/github.com/gorilla/mux
url = https://github.com/gorilla/mux.git
[submodule "vendor/github.com/gorilla/context"]
path = vendor/github.com/gorilla/context
url = https://github.com/gorilla/context.git
[submodule "vendor/github.com/google/gopacket"]
path = vendor/github.com/google/gopacket
url = https://github.com/google/gopacket.git
[submodule "vendor/github.com/weaveworks/go-odp"]
path = vendor/github.com/weaveworks/go-odp
url = https://github.com/weaveworks/go-odp.git
[submodule "vendor/github.com/opencontainers/runc"]
path = vendor/github.com/opencontainers/runc
url = https://github.com/opencontainers/runc.git
[submodule "vendor/github.com/fsouza/go-dockerclient"]
path = vendor/github.com/fsouza/go-dockerclient
url = https://github.com/fsouza/go-dockerclient.git
[submodule "vendor/github.com/docker/libnetwork"]
path = vendor/github.com/docker/libnetwork
url = https://github.com/docker/libnetwork.git
[submodule "vendor/github.com/docker/docker"]
path = vendor/github.com/docker/docker
url = https://github.com/docker/docker.git
[submodule "vendor/github.com/Sirupsen/logrus"]
path = vendor/github.com/Sirupsen/logrus
url = https://github.com/Sirupsen/logrus.git
[submodule "vendor/github.com/andybalholm/go-bit"]
path = vendor/github.com/andybalholm/go-bit
url = https://github.com/andybalholm/go-bit.git
[submodule "vendor/github.com/miekg/dns"]
path = vendor/github.com/miekg/dns
url = https://github.com/miekg/dns.git
[submodule "vendor/github.com/stretchr/testify"]
path = vendor/github.com/stretchr/testify
url = https://github.com/stretchr/testify.git
[submodule "vendor/golang.org/x/crypto"]
path = vendor/golang.org/x/crypto
url = https://github.com/golang/crypto.git
[submodule "vendor/github.com/docker/machine"]
path = vendor/github.com/docker/machine
url = https://github.com/docker/machine.git
[submodule "vendor/github.com/weaveworks/mesh"]
path = vendor/github.com/weaveworks/mesh
url = https://github.com/weaveworks/mesh
[submodule "vendor/github.com/vishvananda/netns"]
path = vendor/github.com/vishvananda/netns
url = https://github.com/vishvananda/netns.git
[submodule "vendor/github.com/boltdb/bolt"]
path = vendor/github.com/boltdb/bolt
url = https://github.com/boltdb/bolt
[submodule "vendor/github.com/weaveworks/go-checkpoint"]
path = vendor/github.com/weaveworks/go-checkpoint
url = https://github.com/weaveworks/go-checkpoint
[submodule "vendor/github.com/hashicorp/go-cleanhttp"]
path = vendor/github.com/hashicorp/go-cleanhttp
url = http://github.com/hashicorp/go-cleanhttp
[submodule "vendor/github.com/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
[submodule "vendor/github.com/containernetworking/cni"]
path = vendor/github.com/containernetworking/cni
url = https://github.com/containernetworking/cni
[submodule "vendor/google.golang.org/grpc"]
path = vendor/google.golang.org/grpc
url = https://github.com/grpc/grpc-go
[submodule "vendor/github.com/docker/go-units"]
path = vendor/github.com/docker/go-units
url = https://github.com/docker/go-units
[submodule "vendor/golang.org/x/net"]
path = vendor/golang.org/x/net
url = https://github.com/golang/net
+200
View File
@@ -1,3 +1,203 @@
## Release 2.4.0
This release introduces a support for Kubernetes Egress Network Policy (#2624, #3313)
and adds a mechanism for preserving the client source IP address to enable
`externalTrafficPolicy: Local` on Kubernetes (#2924, #3298).
### Bug fixes
* Increase the ipset list size which prevents weave-npc from crashing on older
kernels when more than eight Kubernetes Namespaces are used (#3289, #3305).
* Avoid a possible livelock when reclaiming IP address space in weave-kube (#3317).
* Ensure `xtables.lock` is mounted as a file so that kube-proxy can take the lock
if it has started after Weave Net (#3351, #3353).
* Upgrade the CNI plugin symlinks only if the plugin has changed (#3337, #3345).
### Other improvements
* Manipulate the Kubernetes node status `NetworkUnavailable` so that Pods can be
scheduled on nodes when the GCE cloud provider is in use (#3249, #3307, #3332, #3334).
* Refrain from creating a subprocess for configuring a network interface in
a container network namespace (#3291).
* Protect against handling the CNI plugin request with the host namespace which
prevents Weave Net from misconfiguring the host network (#3206, #3346).
* Weave Net can be run on minikube VM (#3124).
* Add `org.opencontainers.image.*` labels to Dockerfiles to improve association
of the container images with git revisions (#3299).
* Improve the error message when running `weave reset` on Kubernetes (#3319).
### Build and Testing
* Use `dep` instead of `git submodules` for managing external packages (#3268).
* Fix usage of `manifest-tool` in Makefile (#3320).
* Update Kubernetes to 1.11 for the integration tests (#3340).
### External Contributors
Thanks to the following contributors:
* @kitt1987
* @louismunro
* @Nodraak
* @stevenjohnstone
[Full list of changes](https://github.com/weaveworks/weave/milestone/73?closed=1)
## Release 2.3.0
### Security fixes
* By default, do not expose Weave "/status" and "/report" to all (0.0.0.0) when
running on Kubernetes #3271
### Other improvements
* Increase the default connection limit for Weave peers (from 30 to 100) when
running on Kubernetes, so that more peers could directly connect #3265
## Build and test
* Build Weave Net with Go 1.10.1 #3273
* Run integration tests against Kubernetes 1.10.0 #3266
[Full list of changes](https://github.com/weaveworks/weave/milestone/70?closed=1)
## Release 2.2.1
### Bug fixes
* Fix a bug in weave-npc which would allow ingress traffic to Kubernetes Pods selected
by a NetworkPolicy in which source and destination selectors were the same #3222,#3237
* Fix a bug in weave-npc which would crash if a previously deleted Kubernetes Namespace
has been created again #3247,#3250
### Other improvements
* Increase the default connection limit for Weave peers (from 30 to 100), so that
more peers could directly connect #3234
* When doing a rolling update of Weave Net on Kubernetes, allow each node five seconds
to initialize before rolling next Weave Net Pod, so that issues at startup will halt
the rollout and not spread across the whole cluster #3235
* Install common CA certificates from Alpine Linux package instead of copying
them manually #3236
### External contributors
Thanks to the following contributors:
* @alok87
[Full list of changes](https://github.com/weaveworks/weave/milestone/71?closed=1)
## Release 2.2.0
This release improves the way Weave Net configures Linux network
devices and network filter rules, so that it is more robust in the face
of unexpected changes in its environment. #3204,#3224
As a consequence of these changes, the `weave attach` command will now
fail unless the Weave Net daemon is up and running - previously it was
possible to run independently as long as you managed all IP addresses
yourself.
## Other improvements
* Update library miekg/dns for CVE-2017-15133 (details under embargo) #3223,#3227
* Reduce the volume of logging from weave-npc #3183
* Add ability to set log level for Docker "v2" plugin, and change
default log level from DEBUG to INFO #3197
* Downgrade log messages about Discovery and Expiration to DEBUG level #3202,#3203
* Use command-line parameter for WeaveDNS address in Docker proxy #3196
## Bug fixes
* Ensure that rules to block traffic for NetworkPolicy are placed
ahead of rules that Kubernetes has added to allow other traffic #3209,#3210
## Build and test
* Update CI tests to use Kubernetes 1.9.2 #3229
* Remove "daily update" from test VMs that only run for a few minutes #3224
## External Contributors
Thanks to the following contributors:
@vetal4444
[Full list of changes](https://github.com/weaveworks/weave/milestone/67?closed=1)
## Release 2.1.3
This release fixes a race-condition in the IP reclaim code for weave-kube
where two nodes could end up fighting over the same space and break
connectivity #3190, #3192
## Release 2.1.2
This release fixes a couple of bugs discovered since the release of Weave Net 2.1.0
##Bug fixes
* Fix crash seen when starting 10-15 nodes simultaneously #3184,#3186
* Fix NetworkPolicy blocking traffic if updates come out of order from Kubernetes #3177,#3181
Thanks to the following contributors:
@zignig
[Full list of changes](https://github.com/weaveworks/weave/milestone/66?closed=1)
## Release 2.1.1
As 2.1.0, but fixing a couple of installation glitches. #3175,#3176
## Release 2.1.0
##New Features
Improved Kubernetes Network Policy - Weave Net now supports the
'v1' policies introduced in Kubernetes 1.7 as well as the 'beta'
policies supported previously. See [Kubernetes 1.7 changelog](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.7.md#network)
for differences. To use old policies, `--use-legacy-netpol` argument
should be passed to `weave-npc`. #3105,#3141,#3151,#3169
Weave Net now reclaims IP addresses owned by Kubernetes nodes which
have been deleted from the cluster - this avoids running out of IP
addresses when many nodes are added and deleted over a long period.
#2797,#3149,#3170,#3172
##Other improvements
* Export a Prometheus-style metric giving count of unreachable peers #3119
* Update 'gopacket' library to reduce memory use by approx 15MB #3160
* Replace bundling the 'docker' binary with our own code to avoid
security vulnerability alerts and save space #2957,#3110
##Bug fixes
* When `weave expose` is used, allow traffic into the Weave network -
up till version 1.12 Docker would do this for us, but in 1.13 they
stopped so now we do it. This change makes `weave expose` require
Weave Net to be running. #2758,#3122
* Arm64 build now works on non-kubernetes installs #2832,#3110
* TX offload was being disabled in 'awsvpc' mode, which slows down packet sending #3089
* Removed spurious 'nil' in logs from CNI DEL operation #3143
##Build and test
* Images are now also built for the ppc64le platform #3129
* Tweak build scripts to run on OSX as well as Linux #3135
##External Contributors
Thanks to the following contributors:
@caarlos0
@dtshepherd
[Full list of changes](https://github.com/weaveworks/weave/milestone/59?closed=1)
## Release 2.0.5
Bug fixes
+19
View File
@@ -24,6 +24,25 @@ taking the time to read this guide.
* 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.
## Managing Vendored Dependencies
We copy all Go dependencies into the `vendor` subdirectory and use
[`dep`](https://github.com/golang/dep) to manage them.
If you add a dependency in the code, run `dep ensure` to include it in
the config and vendor dir. Same if you remove a dependency from the code.
To update a single dependency run `dep ensure -update github.com/foo/bar`
To override `dep`'s choice of library version, you can add
[rules](https://golang.github.io/dep/docs/daily-dep.html#rule-changes-in-gopkgtoml).
Please add a comment saying why the override is necessary and when it can be
removed.
These operations result in staged but uncommitted changes to your
branch; you will need to commit them as normal. Execute them in the
root of your checkout.
## Workflow
See [WorkingOnWeave](https://github.com/weaveworks/weave/wiki/WorkingOnWeave)
+2 -2
View File
@@ -1,3 +1,3 @@
DOCKER_VERSION=17.06
KUBERNETES_VERSION=1.6.2
KUBERNETES_CNI_VERSION=0.5.1
KUBERNETES_VERSION=1.11.0
KUBERNETES_CNI_VERSION=0.6.0
Generated
+782
View File
@@ -0,0 +1,782 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/Azure/go-ansiterm"
packages = [
".",
"winterm"
]
revision = "d6e3b3328b783f23731bc4d058875b0371ff8109"
[[projects]]
name = "github.com/Microsoft/go-winio"
packages = ["."]
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
version = "v0.4.7"
[[projects]]
branch = "master"
name = "github.com/Nvveen/Gotty"
packages = ["."]
revision = "cd527374f1e5bff4938207604a14f2e38a9cf512"
[[projects]]
branch = "master"
name = "github.com/andybalholm/go-bit"
packages = ["."]
revision = "34813fe0e46a87398d88d0315e0f22615592b242"
[[projects]]
branch = "master"
name = "github.com/armon/go-socks5"
packages = ["."]
revision = "e75332964ef517daa070d7c38a9466a0d687e0a5"
[[projects]]
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
"aws/awserr",
"aws/awsutil",
"aws/client",
"aws/client/metadata",
"aws/corehandlers",
"aws/credentials",
"aws/credentials/ec2rolecreds",
"aws/credentials/endpointcreds",
"aws/credentials/stscreds",
"aws/defaults",
"aws/ec2metadata",
"aws/endpoints",
"aws/request",
"aws/session",
"aws/signer/v4",
"internal/sdkio",
"internal/sdkrand",
"internal/shareddefaults",
"private/protocol",
"private/protocol/ec2query",
"private/protocol/query",
"private/protocol/query/queryutil",
"private/protocol/rest",
"private/protocol/xml/xmlutil",
"service/ec2",
"service/sts"
]
revision = "851c8ce700ee981b0ce28634721c2a925c6f3d0b"
version = "v1.13.22"
[[projects]]
branch = "master"
name = "github.com/beorn7/perks"
packages = ["quantile"]
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]]
name = "github.com/boltdb/bolt"
packages = ["."]
revision = "2f1ce7a837dcb8da3ec595b1dac9d0632f0f99e8"
version = "v1.3.1"
[[projects]]
branch = "master"
name = "github.com/containerd/continuity"
packages = ["pathdriver"]
revision = "3e8f2ea4b190484acb976a5b378d373429639a1a"
[[projects]]
name = "github.com/containernetworking/cni"
packages = [
"pkg/invoke",
"pkg/ip",
"pkg/ipam",
"pkg/ns",
"pkg/skel",
"pkg/types",
"pkg/types/020",
"pkg/types/current",
"pkg/utils/hwaddr",
"pkg/version"
]
revision = "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e"
version = "v0.5.2"
[[projects]]
name = "github.com/coreos/go-iptables"
packages = ["iptables"]
revision = "b5b1876b170881a8259f036445ee89c8669db386"
version = "v0.3.0"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/docker/distribution"
packages = [
"digestset",
"reference"
]
revision = "83389a148052d74ac602f5f1d62f86ff2f3c4aa5"
[[projects]]
branch = "master"
name = "github.com/docker/docker"
packages = [
"api",
"api/types",
"api/types/blkiodev",
"api/types/container",
"api/types/events",
"api/types/filters",
"api/types/image",
"api/types/mount",
"api/types/network",
"api/types/registry",
"api/types/strslice",
"api/types/swarm",
"api/types/swarm/runtime",
"api/types/time",
"api/types/versions",
"api/types/volume",
"client",
"opts",
"pkg/archive",
"pkg/fileutils",
"pkg/homedir",
"pkg/idtools",
"pkg/ioutils",
"pkg/jsonmessage",
"pkg/longpath",
"pkg/mount",
"pkg/plugingetter",
"pkg/plugins",
"pkg/plugins/transport",
"pkg/pools",
"pkg/stdcopy",
"pkg/system",
"pkg/term",
"pkg/term/windows"
]
revision = "38588656727d19f4a36d14c3620ecaff73160315"
[[projects]]
name = "github.com/docker/go-connections"
packages = [
"nat",
"sockets",
"tlsconfig"
]
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
version = "v0.3.0"
[[projects]]
name = "github.com/docker/go-units"
packages = ["."]
revision = "0dadbb0345b35ec7ef35e228dabb8de89a65bf52"
version = "v0.3.2"
[[projects]]
name = "github.com/docker/libnetwork"
packages = [
"discoverapi",
"driverapi",
"drivers/remote/api",
"ipamapi",
"ipams/remote/api",
"netlabel",
"types"
]
revision = "119badbd"
[[projects]]
name = "github.com/docker/machine"
packages = [
"libmachine/auth",
"libmachine/cert",
"libmachine/log",
"libmachine/mcnutils",
"version"
]
revision = "89b833253d9412716a0291cbdccc94454c33d1b5"
version = "v0.14.0"
[[projects]]
name = "github.com/fsouza/go-dockerclient"
packages = ["."]
revision = "ca33ff277b527ce11b793e62f9ba244129b01caf"
version = "v1.2.0"
[[projects]]
name = "github.com/ghodss/yaml"
packages = ["."]
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
name = "github.com/go-ini/ini"
packages = ["."]
revision = "6333e38ac20b8949a8dd68baa3650f4dee8f39f0"
version = "v1.33.0"
[[projects]]
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys"
]
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/golang/glog"
packages = ["."]
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
name = "github.com/golang/protobuf"
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp"
]
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/google/btree"
packages = ["."]
revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4"
[[projects]]
branch = "master"
name = "github.com/google/gofuzz"
packages = ["."]
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]]
name = "github.com/google/gopacket"
packages = [
".",
"layers",
"pcap",
"pcapgo"
]
revision = "11c65f1ca9081dfea43b4f9643f5c155583b73ba"
version = "v1.1.14"
[[projects]]
name = "github.com/googleapis/gnostic"
packages = [
"OpenAPIv2",
"compiler",
"extensions"
]
revision = "ee43cbb60db7bd22502942cccbc39059117352ab"
version = "v0.1.0"
[[projects]]
name = "github.com/gorilla/context"
packages = ["."]
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
version = "v1.1"
[[projects]]
name = "github.com/gorilla/mux"
packages = ["."]
revision = "53c1911da2b537f792e7cafcb446b05ffe33b996"
version = "v1.6.1"
[[projects]]
branch = "master"
name = "github.com/gregjones/httpcache"
packages = [
".",
"diskcache"
]
revision = "9cad4c3443a7200dd6400aef47183728de563a38"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-cleanhttp"
packages = ["."]
revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d"
[[projects]]
branch = "master"
name = "github.com/hashicorp/golang-lru"
packages = [
".",
"simplelru"
]
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
[[projects]]
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
branch = "master"
name = "github.com/j-keck/arping"
packages = ["."]
revision = "2cf9dc699c5640a7e2c81403a44127bf28033600"
[[projects]]
name = "github.com/jmespath/go-jmespath"
packages = ["."]
revision = "0b12d6b5"
[[projects]]
name = "github.com/json-iterator/go"
packages = ["."]
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
version = "1.1.3"
[[projects]]
name = "github.com/juju/ratelimit"
packages = ["."]
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
version = "1.0.1"
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
revision = "3247c84500bff8d9fb6d579d800f20b3e091582c"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/mgutz/ansi"
packages = ["."]
revision = "9520e82c474b0a04dd04f8a40959027271bab992"
[[projects]]
name = "github.com/miekg/dns"
packages = ["."]
revision = "5364553f1ee9cddc7ac8b62dce148309c386695b"
version = "v1.0.4"
[[projects]]
name = "github.com/modern-go/concurrent"
packages = ["."]
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
version = "1.0.3"
[[projects]]
name = "github.com/modern-go/reflect2"
packages = ["."]
revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f"
version = "1.0.0"
[[projects]]
name = "github.com/opencontainers/go-digest"
packages = ["."]
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
version = "v1.0.0-rc1"
[[projects]]
name = "github.com/opencontainers/image-spec"
packages = [
"specs-go",
"specs-go/v1"
]
revision = "d60099175f88c47cd379c4738d158884749ed235"
version = "v1.0.1"
[[projects]]
name = "github.com/opencontainers/runc"
packages = [
"libcontainer/system",
"libcontainer/user"
]
revision = "baf6536d6259209c3edfa2b22237af82942d3dfa"
version = "v0.1.1"
[[projects]]
name = "github.com/pborman/uuid"
packages = ["."]
revision = "e790cca94e6cc75c7064b1332e63811d4aae1a53"
version = "v1.1"
[[projects]]
branch = "master"
name = "github.com/petar/GoLLRB"
packages = ["llrb"]
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
[[projects]]
name = "github.com/peterbourgon/diskv"
packages = ["."]
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
version = "v2.0.1"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/pkg/profile"
packages = ["."]
revision = "5b67d428864e92711fcbd2f8629456121a56d91f"
version = "v1.2.1"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/promhttp"
]
revision = "f504d69affe11ec1ccb2e5948127f86878c9fd57"
[[projects]]
branch = "master"
name = "github.com/prometheus/client_model"
packages = ["go"]
revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
[[projects]]
branch = "master"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model"
]
revision = "38c53a9f4bfcd932d1b00bfc65e256a7fba6b37a"
[[projects]]
branch = "master"
name = "github.com/prometheus/procfs"
packages = [
".",
"internal/util",
"nfs",
"xfs"
]
revision = "780932d4fbbe0e69b84c34c20f5c8d0981e109ea"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = ["."]
revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba"
version = "v1.0.4"
[[projects]]
name = "github.com/spf13/cobra"
packages = ["."]
revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b"
version = "v0.0.1"
[[projects]]
name = "github.com/spf13/pflag"
packages = ["."]
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
version = "v1.0.0"
[[projects]]
name = "github.com/stretchr/testify"
packages = [
"assert",
"require"
]
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
[[projects]]
name = "github.com/vishvananda/netlink"
packages = [
".",
"nl"
]
revision = "a2ad57a690f3caf3015351d2d6e1c0b95c349752"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/vishvananda/netns"
packages = ["."]
revision = "be1fbeda19366dea804f00efff2dd73a1642fdcc"
[[projects]]
branch = "master"
name = "github.com/weaveworks/common"
packages = [
"mflag",
"mflagext",
"signals"
]
revision = "ebab3a78900a09cebce8d0b37f2a69d474796bf4"
[[projects]]
branch = "master"
name = "github.com/weaveworks/go-checkpoint"
packages = ["."]
revision = "ebbb8b0518ab326368631225cabc9435fe580dcc"
[[projects]]
branch = "master"
name = "github.com/weaveworks/go-odp"
packages = ["odp"]
revision = "eec09c2fbfb96be47bfe11165ce300ad9a60bef5"
[[projects]]
name = "github.com/weaveworks/mesh"
packages = ["."]
revision = "38e8100dfbc7b28ae8ffde5a2bbeceec57ffa52a"
version = "v0.1"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"curve25519",
"ed25519",
"ed25519/internal/edwards25519",
"hkdf",
"nacl/box",
"nacl/secretbox",
"pbkdf2",
"poly1305",
"salsa20/salsa",
"scrypt",
"ssh/terminal"
]
revision = "88942b9c40a4c9d203b82b3731787b672d6e809b"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"bpf",
"context",
"context/ctxhttp",
"http2",
"http2/hpack",
"idna",
"internal/iana",
"internal/socket",
"ipv4",
"ipv6",
"lex/httplex",
"proxy"
]
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "13d03a9a82fba647c21a0ef8fba44a795d0f0835"
[[projects]]
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "golang.org/x/tools"
packages = ["cover"]
revision = "77106db15f689a60e7d4e085d967ac557b918fb2"
[[projects]]
name = "gopkg.in/inf.v0"
packages = ["."]
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1"
[[projects]]
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "86f5ed62f8a0ee96bd888d2efdfd6d4fb100a4eb"
version = "v2.2.0"
[[projects]]
branch = "master"
name = "k8s.io/api"
packages = [
"admissionregistration/v1alpha1",
"admissionregistration/v1beta1",
"apps/v1",
"apps/v1beta1",
"apps/v1beta2",
"authentication/v1",
"authentication/v1beta1",
"authorization/v1",
"authorization/v1beta1",
"autoscaling/v1",
"autoscaling/v2beta1",
"batch/v1",
"batch/v1beta1",
"batch/v2alpha1",
"certificates/v1beta1",
"core/v1",
"events/v1beta1",
"extensions/v1beta1",
"networking/v1",
"policy/v1beta1",
"rbac/v1",
"rbac/v1alpha1",
"rbac/v1beta1",
"scheduling/v1alpha1",
"settings/v1alpha1",
"storage/v1",
"storage/v1alpha1",
"storage/v1beta1"
]
revision = "055879e38033d1526b0fe169089a055c33fa3990"
[[projects]]
branch = "master"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/errors",
"pkg/api/meta",
"pkg/api/resource",
"pkg/apis/meta/internalversion",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
"pkg/apis/meta/v1beta1",
"pkg/conversion",
"pkg/conversion/queryparams",
"pkg/fields",
"pkg/labels",
"pkg/runtime",
"pkg/runtime/schema",
"pkg/runtime/serializer",
"pkg/runtime/serializer/json",
"pkg/runtime/serializer/protobuf",
"pkg/runtime/serializer/recognizer",
"pkg/runtime/serializer/streaming",
"pkg/runtime/serializer/versioning",
"pkg/selection",
"pkg/types",
"pkg/util/cache",
"pkg/util/clock",
"pkg/util/diff",
"pkg/util/errors",
"pkg/util/framer",
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/net",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/uuid",
"pkg/util/validation",
"pkg/util/validation/field",
"pkg/util/wait",
"pkg/util/yaml",
"pkg/version",
"pkg/watch",
"third_party/forked/golang/reflect"
]
revision = "210bcde8e5a7715fe776460ca1df1a3f2738725e"
[[projects]]
name = "k8s.io/client-go"
packages = [
"discovery",
"kubernetes",
"kubernetes/scheme",
"kubernetes/typed/admissionregistration/v1alpha1",
"kubernetes/typed/admissionregistration/v1beta1",
"kubernetes/typed/apps/v1",
"kubernetes/typed/apps/v1beta1",
"kubernetes/typed/apps/v1beta2",
"kubernetes/typed/authentication/v1",
"kubernetes/typed/authentication/v1beta1",
"kubernetes/typed/authorization/v1",
"kubernetes/typed/authorization/v1beta1",
"kubernetes/typed/autoscaling/v1",
"kubernetes/typed/autoscaling/v2beta1",
"kubernetes/typed/batch/v1",
"kubernetes/typed/batch/v1beta1",
"kubernetes/typed/batch/v2alpha1",
"kubernetes/typed/certificates/v1beta1",
"kubernetes/typed/core/v1",
"kubernetes/typed/events/v1beta1",
"kubernetes/typed/extensions/v1beta1",
"kubernetes/typed/networking/v1",
"kubernetes/typed/policy/v1beta1",
"kubernetes/typed/rbac/v1",
"kubernetes/typed/rbac/v1alpha1",
"kubernetes/typed/rbac/v1beta1",
"kubernetes/typed/scheduling/v1alpha1",
"kubernetes/typed/settings/v1alpha1",
"kubernetes/typed/storage/v1",
"kubernetes/typed/storage/v1alpha1",
"kubernetes/typed/storage/v1beta1",
"pkg/version",
"rest",
"rest/watch",
"tools/cache",
"tools/clientcmd/api",
"tools/metrics",
"tools/pager",
"tools/reference",
"transport",
"util/buffer",
"util/cert",
"util/flowcontrol",
"util/integer"
]
revision = "78700dec6369ba22221b72770783300f143df150"
version = "v6.0.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "4797cbcb2a3e44dbdfcb6f7a7aba5a86079a150d9cf4d782eb7f69be973c48db"
solver-name = "gps-cdcl"
solver-version = 1
+29
View File
@@ -0,0 +1,29 @@
# Pin to version before sctp was added, because latest libnetwork is
# incompatible with latest sctp
[[constraint]]
name = "github.com/docker/libnetwork"
revision = "119badbd"
# Encourage dep not to use the docker-1.9 version
[[constraint]]
name = "github.com/fsouza/go-dockerclient"
version = "1"
# Use recent version: last tagged version is years old
[[constraint]]
branch = "master"
name = "github.com/prometheus/client_golang"
# For compatibility with fsouza/go-dockerclient
[[constraint]]
branch = "master"
name = "github.com/docker/docker"
# Most recent release tag is incompatible with docker/docker; see https://github.com/docker/distribution/issues/2503
[[override]]
branch = "master"
name = "github.com/docker/distribution"
[prune]
go-tests = true
unused-packages = true
+1 -1
View File
@@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS
Copyright 2014-2016 Weaveworks Ltd.
Copyright 2014-2017 Weaveworks Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+51 -43
View File
@@ -17,15 +17,15 @@ 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
ALL_ARCHITECTURES=amd64 arm arm64 ppc64le
ML_PLATFORMS=linux/amd64,linux/arm,linux/arm64,linux/ppc64le
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
ALPINE_BASEIMAGE?=alpine:3.6
# The extension for the made images
# Specifying none means for example weaveworks/weave:latest
@@ -42,7 +42,7 @@ ifeq ($(ARCH),arm)
WEAVEEXEC_DOCKER_ARCH?=armel
# Using the (semi-)official alpine image
ALPINE_BASEIMAGE?=armhf/alpine:3.4
ALPINE_BASEIMAGE?=arm32v6/alpine:3.6
# arm images have the -arm suffix, for instance weaveworks/weave-arm:latest
ARCH_EXT?=-arm
@@ -62,7 +62,7 @@ ifeq ($(ARCH),arm64)
WEAVEEXEC_DOCKER_ARCH?=armel
# Using the (semi-)official alpine image
ALPINE_BASEIMAGE?=aarch64/alpine:3.5
ALPINE_BASEIMAGE?=arm64v8/alpine:3.6
# arm64 images have the -arm64 suffix, for instance weaveworks/weave-arm64:latest
ARCH_EXT?=-arm64
@@ -77,10 +77,31 @@ ifeq ($(ARCH),arm64)
# Tell the gcc linker to search for libpcap here
CGO_LDFLAGS="-L/usr/local/lib/$(CC)"
endif
ifeq ($(ARCH),ppc64le)
# The architecture to use when downloading the docker binary
WEAVEEXEC_DOCKER_ARCH?=ppc64le
# Using the (semi-)official alpine image
ALPINE_BASEIMAGE?=ppc64le/alpine:3.6
# ppc64le images have the -ppc64le suffix, for instance weaveworks/weave-ppc64le:latest
ARCH_EXT?=-ppc64le
# The name of the gcc binary
CC=powerpc64le-linux-gnu-gcc
# The architecture name to use when downloading a prebuilt QEMU binary
QEMUARCH=ppc64le
# In the weaveworks/build image; libpcap libraries for ppc64le 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
GIT_REVISION=$(shell git rev-parse HEAD)
WEAVE_VERSION?=git-$(shell git rev-parse --short=12 HEAD)
# Docker Store does not allow the "latest" tag.
NET_PLUGIN_LATEST=latest_release
@@ -88,20 +109,20 @@ NET_PLUGIN_LATEST=latest_release
# Paths to all relevant binaries that should be compiled
WEAVER_EXE=prog/weaver/weaver
SIGPROXY_EXE=prog/sigproxy/sigproxy
KUBEPEERS_EXE=prog/kube-peers/kube-peers
KUBEUTILS_EXE=prog/kube-utils/kube-utils
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
RUNNER_EXE=tools/runner/runner
MANIFEST_TOOL_DIR=vendor/github.com/estesp/manifest-tool
MANIFEST_TOOL_EXE=$(MANIFEST_TOOL_DIR)/manifest-tool
# manifest-tool needs registry credentials; we assume here that the active user has logged in
MANIFEST_TOOL_CMD=docker run --rm -v $(HOME)/.docker:/.docker weshigbee/manifest-tool --docker-cfg=/.docker
TEST_TLS_EXE=test/tls/tls
NETWORKTESTER_EXE=test/images/network-tester/webserver
# All binaries together in a list
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE) $(RUNNER_EXE) $(TEST_TLS_EXE) $(MANIFEST_TOOL_EXE) $(NETWORKTESTER_EXE)
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(KUBEUTILS_EXE) $(WEAVENPC_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE) $(RUNNER_EXE) $(TEST_TLS_EXE) $(NETWORKTESTER_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
@@ -135,9 +156,6 @@ PUSH_ML=push_ml_weave push_ml_weaveexec push_ml_weave-kube push_ml_weave-npc
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."; \
@@ -162,11 +180,10 @@ $(WEAVER_EXE): api/*.go plugin/*.go plugin/*/*
$(WEAVER_EXE): proxy/*.go
$(WEAVEUTIL_EXE): prog/weaveutil/*.go net/*.go plugin/net/*.go plugin/ipam/*.go db/*.go
$(SIGPROXY_EXE): prog/sigproxy/*.go
$(KUBEPEERS_EXE): prog/kube-peers/*.go
$(KUBEUTILS_EXE): prog/kube-utils/*.go
$(WEAVENPC_EXE): prog/weave-npc/*.go npc/*.go npc/*/*.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
@@ -179,9 +196,6 @@ ifeq ($(BUILD_IN_CONTAINER),true)
# 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
# Containernetworking has another copy of vishvananda/netlink which leads to duplicate definitions
-@rm -r vendor/github.com/containernetworking/cni/vendor
@mkdir -p $(shell pwd)/.pkg
$(SUDO) docker run $(RM) $(RUN_FLAGS) \
-v $(shell pwd):/go/src/github.com/weaveworks/weave \
@@ -203,7 +217,7 @@ else
endif
$(NETGO_CHECK)
$(WEAVEUTIL_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE) $(NETWORKTESTER_EXE):
$(WEAVEUTIL_EXE) $(KUBEUTILS_EXE) $(WEAVENPC_EXE) $(NETWORKTESTER_EXE):
go build $(BUILD_FLAGS) -o $@ ./$(@D)
$(NETGO_CHECK)
@@ -217,7 +231,7 @@ $(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) $(RUNNER_EXE) $(MANIFEST_TOOL_EXE):
$(SIGPROXY_EXE) $(TEST_TLS_EXE) $(WEAVEWAIT_NOOP_EXE) $(RUNNER_EXE):
go build $(BUILD_FLAGS) -o $@ ./$(@D)
tests:
@@ -244,30 +258,28 @@ $(BUILD_UPTODATE): build/*
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" $@
sed -i.bak "/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
# Register /usr/bin/qemu-ARCH-static as the handler for ARM and ppc64le 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" $@
sed -i.bak "s/CROSS_BUILD_//g" $@
endif
# The targets below builds the weave images
$(WEAVER_UPTODATE): prog/weaver/Dockerfile.$(DOCKERHUB_USER) $(WEAVER_EXE) weave $(WEAVEUTIL_EXE)
cp $(WEAVEUTIL_EXE) prog/weaver/weaveutil
cp weave prog/weaver/weave
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -f prog/weaver/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVER_IMAGE) prog/weaver
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build --build-arg=revision=$(GIT_REVISION) -f prog/weaver/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVER_IMAGE) prog/weaver
touch $@
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexec/symlink $(DOCKER_DISTRIB) $(SIGPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVER_UPTODATE)
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexec/symlink $(SIGPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVER_UPTODATE)
cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy
cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
cp $(WEAVEWAIT_NOMCAST_EXE) prog/weaveexec/weavewait_nomcast
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
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build --build-arg=revision=$(GIT_REVISION) -f prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVEEXEC_IMAGE) prog/weaveexec
touch $@
# Builds Docker plugin.
@@ -287,17 +299,17 @@ $(PLUGIN_UPTODATE): prog/net-plugin/launch.sh prog/net-plugin/config.json $(WEAV
$(SUDO) docker plugin create $(PLUGIN_IMAGE):$(NET_PLUGIN_LATEST) prog/net-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
$(WEAVEKUBE_UPTODATE): prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) prog/weave-kube/launch.sh $(KUBEUTILS_EXE) $(WEAVER_UPTODATE)
cp $(KUBEUTILS_EXE) prog/weave-kube/
$(SUDO) docker build --build-arg=revision=$(GIT_REVISION) -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
$(SUDO) docker build --build-arg=revision=$(GIT_REVISION) -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
$(SUDO) docker build --build-arg=revision=$(GIT_REVISION) -t $(WEAVEDB_IMAGE) prog/weavedb
touch $@
$(NETWORKTESTER_UPTODATE): test/images/network-tester/Dockerfile $(NETWORKTESTER_EXE)
@@ -307,11 +319,7 @@ $(NETWORKTESTER_UPTODATE): test/images/network-tester/Dockerfile $(NETWORKTESTER
$(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 $(MANIFEST_TOOL_DIR)/.git:
tools/.git:
git submodule update --init
# CODE FOR PUBLISHING THE IMAGES
@@ -343,7 +351,7 @@ publish-one-arch: $(PUBLISH)
$(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
# Push the image with the arch suffix for arm, arm64 and ppc64le, 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)
@@ -367,13 +375,13 @@ 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)
$(PUSH_ML): push_ml_%:
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)
$(MANIFEST_TOOL_CMD) 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
$(MANIFEST_TOOL_CMD) push from-args --platforms $(ML_PLATFORMS) --template $(DOCKERHUB_USER)/$*-ARCH:latest --target $(DOCKERHUB_USER)/$*:latest
endif
clean-work-dir:
@@ -383,11 +391,11 @@ clean-bin:
-$(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
rm -rf $(EXES) $(IMAGES_UPTODATE) $(WEAVEDB_UPTODATE) weave*.tar.gz .pkg
clean: clean-bin clean-work-dir
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(BUILD_IMAGE)
rm -rf test/tls/*.pem test/coverage.* test/coverage $(BUILD_UPTODATE) $(MANIFEST_TOOL_EXE)
rm -rf test/tls/*.pem test/coverage.* test/coverage $(BUILD_UPTODATE)
build:
$(SUDO) go clean -i net
+6
View File
@@ -62,6 +62,12 @@ func (client *Client) ReleaseIPsFor(ID string) error {
return err
}
// release all IP space owned by a peer
func (client *Client) RmPeer(peerName string) (string, error) {
result, err := client.httpVerb("DELETE", fmt.Sprintf("/peer/%s", peerName), nil)
return result, err
}
func (client *Client) DefaultSubnet() (*net.IPNet, error) {
cidr, err := client.httpVerb("GET", fmt.Sprintf("/ipinfo/defaultsubnet"), nil)
if err != nil {
+12
View File
@@ -0,0 +1,12 @@
package api
import (
"fmt"
"net"
)
// Expose calls the router to assign the given IP addr to the weave bridge.
func (client *Client) Expose(ipAddr *net.IPNet) error {
_, err := client.httpVerb("POST", fmt.Sprintf("/expose/%s", ipAddr), nil)
return err
}
+3 -1
View File
@@ -17,7 +17,9 @@ function install_terraform() {
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
sudo apt-get install -qq -y python-pip python-dev libffi-dev libssl-dev \
&& pip install --user -U setuptools cffi \
&& pip install --user ansible
export PATH="$PATH:$HOME/.local/bin"
}
+21 -6
View File
@@ -88,10 +88,11 @@ 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
sed -i -e "s/:latest/:$VERSION/" -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset-k8s-1.6.yaml
sed -i -e "s/:latest/:$VERSION/" -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset-k8s-1.7.yaml
sed -i.bak "/SCRIPT_VERSION=/ c\SCRIPT_VERSION=\"$VERSION\"" ./weave
sed -i.bak -e "s/:latest/:$VERSION/" -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset.yaml
sed -i.bak -e "s/:latest/:$VERSION/" -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset-k8s-1.6.yaml
sed -i.bak -e "s/:latest/:$VERSION/" -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset-k8s-1.7.yaml
sed -i.bak -e "s/:latest/:$VERSION/" -e "/imagePullPolicy: Always/d" ./prog/weave-kube/weave-daemonset-k8s-1.8.yaml
make SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER
if make tests; then
@@ -181,6 +182,13 @@ draft() {
--name "weave-daemonset-k8s-1.7.yaml" \
--file "./prog/weave-kube/weave-daemonset-k8s-1.7.yaml"
github-release upload \
--user $GITHUB_USER \
--repo weave \
--tag $LATEST_TAG \
--name "weave-daemonset-k8s-1.8.yaml" \
--file "./prog/weave-kube/weave-daemonset-k8s-1.8.yaml"
echo "** Draft $TYPE $RELEASE_NAME $VERSION created at"
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG"
}
@@ -196,7 +204,7 @@ publish() {
if [ "$RELEASE_TYPE" = 'PRERELEASE' ] ; then
echo "== Building and pushing plugin"
make UPDATE_LATEST=$IS_MAINLINE SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
make UPDATE_LATEST=false SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
echo "** Plugin built and pushed"
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
@@ -232,7 +240,7 @@ publish() {
echo '** Sanity checks OK for publishing tag' $LATEST_TAG as $DOCKERHUB_USER/weave:$VERSION
echo "== Building and pushing plugin"
make UPDATE_LATEST=$IS_MAINLINE SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
make UPDATE_LATEST=true SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
echo "** Plugin built and pushed"
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
@@ -289,6 +297,13 @@ publish() {
--name "weave-daemonset-k8s-1.7.yaml" \
--file "./prog/weave-kube/weave-daemonset-k8s-1.7.yaml"
github-release upload \
--user $GITHUB_USER \
--repo weave \
--tag latest_release \
--name "weave-daemonset-k8s-1.8.yaml" \
--file "./prog/weave-kube/weave-daemonset-k8s-1.8.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"
+7 -4
View File
@@ -1,4 +1,4 @@
FROM golang:1.8.1
FROM golang:1.10.1-stretch
# Support Raspberry Pi 2 and newer
ENV GOARM 7
@@ -6,17 +6,20 @@ ENV GOARM 7
# The names of the architectures that we're fetching cross-compilers for from the Debian packages
ENV DEB_CROSSPLATFORMS \
armhf \
arm64
arm64 \
ppc64el
# The go platforms we are supporting to cross-compile
ENV GO_CROSSPLATFORMS \
linux/arm \
linux/arm64
linux/arm64 \
linux/ppc64le
# The names of the gcc cross-compilers we have installed
ENV GCC_CROSSCOMPILERS \
arm-linux-gnueabihf \
aarch64-linux-gnu
aarch64-linux-gnu \
powerpc64le-linux-gnu
# Temporarily add the Debian repositories, because we're going to install gcc cross-compilers from there
# Install the build-essential and crossbuild-essential-ARCH packages
-1
View File
@@ -1 +0,0 @@
8f313a9df867c207ae9ceac6e0935d1d2a0360aafce780dd5d1e0687ee98e0c3 docker-1.10.3.tgz
@@ -1 +0,0 @@
7541b5490cee1183d911f909c0e91d3d9d57b2b775e40f14a1a7a6de216ca4a8 docker-1.10.3.tgz
@@ -0,0 +1 @@
926f7f265332076ea4abf6e9586288376dbed2322c155b8d0cafbee614aaa7f2 qemu-ppc64le-static
+1 -1
View File
@@ -44,7 +44,7 @@ test:
parallel: true
- "$SRCDIR/bin/circle-test-smoke":
parallel: true
timeout: 300
timeout: 360
post:
- "$SRCDIR/bin/circle-test-teardown":
parallel: true
+1 -1
View File
@@ -231,7 +231,7 @@ func (c *Client) EnsureNetwork(networkName, driver, subnet string, options map[s
Name: networkName,
CheckDuplicate: true,
Driver: driver,
IPAM: docker.IPAMOptions{
IPAM: &docker.IPAMOptions{
Driver: driver,
Config: []docker.IPAMConfig{{Subnet: subnet}},
},
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"log"
"strings"
"github.com/Sirupsen/logrus"
"github.com/sirupsen/logrus"
)
type textFormatter struct {
+12
View File
@@ -75,6 +75,14 @@ func DeleteDatapath(dpname string) error {
}
func AddDatapathInterface(dpname string, ifname string) error {
return addDatapathInterface(dpname, ifname, false)
}
func AddDatapathInterfaceIfNotExist(dpname string, ifname string) error {
return addDatapathInterface(dpname, ifname, true)
}
func addDatapathInterface(dpname, ifname string, ignoreIfExist bool) error {
dpif, err := odp.NewDpif()
if err != nil {
return err
@@ -87,5 +95,9 @@ func AddDatapathInterface(dpname string, ifname string) error {
}
_, err = dp.CreateVport(odp.NewNetdevVportSpec(ifname))
if ignoreIfExist && err == odp.NetlinkError(syscall.EEXIST) {
return nil
}
return err
}
+33
View File
@@ -0,0 +1,33 @@
# Source IP addr of packet sent to k8s Service
## Setup
* Weave Net: v2.2.1.
* Kubernetes: v1.10.0.
* kube-proxy: iptables mode (default kubeadm options).
* Hosts: `h1` and `h2`.
## Source IP
\# | Src | Target | Dst | Src IP | `-j WEAVE-NPC`
---|-------------|-------------------|--------|------------------|--------------
1 | Pod_h1 | ip(Pod_h2) | Pod_h2 | ip(Pod_h1) | OK
2 | h1 | ClusterIP | Pod_h1 | ip(weave_h1) | **NOK**
3 | h1 | ClusterIP | Pod_h2 | ip(weave_h1) | OK
4 | Pod_h1 | ClusterIP | Pod_h1 | ip(weave_h1) | **NOK**
5 | Pod_h1 | ClusterIP | Pod_h2 | ip(weave_h1) | OK
6 | h1 | ip(h1):NodePort | Pod_h1 | ip(weave_h1) | **NOK**
7 | h1 | ip(h1):NodePort | Pod_h2 | ip(weave_h1) | OK
8 | h1 | ip(h2):NodePort | Pod_h1 | ip(weave_h2) | OK
9 | h1 | ip(h2):NodePort | Pod_h2 | ip(weave_h2) | ??? Can't reproduce
10 | Pod_h1 | ip(h1):NodePort | Pod_h1 | ip(weave_h1) | **NOK**
11 | Pod_h1 | ip(h1):NodePort | Pod_h2 | ip(weave_h1) | OK
12 | Pod_h1 | ip(h2):NodePort | Pod_h1 | ip(weave_h2) | OK
13 | Pod_h1 | ip(h2):NodePort | Pod_h2 | ip(weave_h2) | OK
Remarks:
* **Src IP** is of a packet which is captured on the weave bridge.
* **-j WEAVE-NPC** - whether a packet enters the `filter/WEAVE-NPC` iptables chain (OK = NetworkPolicy is enforced as required).
* **Pod_h1** - a Pod running on the `h1` host.
* **ip(weave_h1)** - IP addr of the weave bridge on the `h1` host.
+40 -2
View File
@@ -127,14 +127,52 @@ Finally, for **Mainline** releases only:
* Images tagged `latest` are updated on DockerHub
Now, you can validate whether images were published for all platforms:
# Required platforms for each image:
grep '^ML_PLATFORMS=' Makefile
# Published platforms per image:
for img in $(grep '^PUBLISH=' Makefile); do
img="weaveworks/$(echo $img | cut -d_ -f2):${TAG#v}"
platforms=$(vendor/github.com/estesp/manifest-tool/manifest-tool \
inspect --raw "$img" | \
jq '.[].Platform | .os + "/" +.architecture' | \
tr '\n' ' ')
echo "$img: $platforms"
done
### Docker Store
Weave Net is [available in Docker Store](https://store.docker.com/plugins/weave-net-plugin) and should also be released there.
* Go to https://store.docker.com/ and log in.
* Go to "[_Publish_](https://store.docker.com/publisher/center)".
* Under "_My Products_", select "_owners (weaveworks)_". Weave Net should be listed among our products.
* Click "_Actions_" > "_Edit Product_".
* Go to "_Plans & Pricing_" > "_Free Tier_".
* Under "_Source Repositories & Tags_", click on "_Add Source_", select "_net-plugin_" under "_Repository_" and the version to release under "_Tag_".
* Under "_Resources_" > "_Installation Instructions_", update the lines containing `export NET_VERSION=<version>`.
* Click "_Submit For Review_". You should see a message like: "_Your product has been submitted for approval. [...] We'll be in touch with next steps soon!_".
* You should receive an email saying:
> This email confirms that we received your submission on \<date\> of Weave Net to the Docker Store.
>
> We're reviewing your submission to ensure that it meets our [security guidelines](https://success.docker.com/Store#Security_and_Audit_Policies) and complies with our [best practices](https://success.docker.com/Store#Create_Great_Content). Don't worry! We'll let you know if there's anything you need to change before we publish your submission. You should hear back from us within the next 14 days.
>
> Thanks for submitting your content to the Docker Store!
* Hope Docker eventually performs the release or contacts us. If nothing happens within 14 days, contact their support team: publisher-support@docker.com.
### Finish up
* If not on master, merge branch into master and push to GitHub.
* Close the [milestone](https://github.com/weaveworks/weave/milestones) in GitHub and create the next milestone
* Update the `#weavenetwork` topic heading on freenode (requires 'chanops' permission)
* For a mainline release vX.Y.0, create a release branch X.Y from the
tag and push to GitHub - this will result in X.Y.0 site docs being
published to https://www.weave.works
tag, push to GitHub and set [WEAVE_NET_REV](https://github.com/weaveworks/website-next/blob/master/Makefile)
to X.Y via a PR - 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
* File a PR to update the version of the daemonset at
+2
View File
@@ -74,6 +74,7 @@ type Allocator struct {
isKnownPeer func(mesh.PeerName) bool
quorum func() uint
now func() time.Time
tracker tracker.LocalRangeTracker
}
// PreClaims are IP addresses discovered before we could initialize IPAM
@@ -130,6 +131,7 @@ func NewAllocator(config Config) *Allocator {
quorum: config.Quorum,
dead: make(map[string]time.Time),
now: time.Now,
tracker: config.Tracker,
}
alloc.pendingClaims = make([]operation, len(config.PreClaims))
+2 -2
View File
@@ -88,7 +88,7 @@ func (alloc *Allocator) handleHTTPClaim(dockerCli *docker.Client, w http.Respons
}
// HandleHTTP wires up ipams HTTP endpoints to the provided mux.
func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CIDR, tracker string, dockerCli *docker.Client) {
func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CIDR, dockerCli *docker.Client) {
router.Methods("GET").Path("/ipinfo/defaultsubnet").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s", defaultSubnet)
})
@@ -199,6 +199,6 @@ func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CID
})
router.Methods("GET").Path("/ipinfo/tracker").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, tracker)
fmt.Fprintf(w, alloc.tracker.String())
})
}
+2 -2
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 {
@@ -132,7 +132,7 @@ func TestBadHttp(t *testing.T) {
// Verb that's not handled
resp, err := doHTTP("HEAD", fmt.Sprintf("http://localhost:%d/ip/%s/%s", port, containerID, testAddr1))
require.NoError(t, err)
require.Equal(t, http.StatusNotFound, resp.StatusCode, "http response")
require.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode, "http response")
// Mis-spelled URL
resp, err = doHTTP("POST", fmt.Sprintf("http://localhost:%d/xip/%s/", port, containerID))
require.NoError(t, err)
+1 -1
View File
@@ -117,7 +117,7 @@ func CheckAllExpectedMessagesSent(allocs ...*Allocator) {
m := alloc.gossip.(*mockGossipComms)
m.RLock()
if len(m.messages) > 0 {
require.FailNow(m, fmt.Sprintf("%s: Gossip message(s) not sent as expected: \n%x", m.name, m.messages))
require.FailNow(m, fmt.Sprintf("%s: Gossip message(s) not sent as expected: \n%v", m.name, m.messages))
}
m.RUnlock()
}
+5 -42
View File
@@ -84,7 +84,7 @@ func NewAWSVPCTracker(bridgeName string) (*AWSVPCTracker, error) {
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)))
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
@@ -123,6 +123,10 @@ func (t *AWSVPCTracker) HandleUpdate(prevRanges, currRanges []address.Range, loc
return nil
}
func (t *AWSVPCTracker) String() string {
return "awsvpc"
}
func (t *AWSVPCTracker) createVPCRoute(cidr string) (*ec2.CreateRouteOutput, error) {
route := &ec2.CreateRouteInput{
RouteTableId: &t.routeTableID,
@@ -232,47 +236,6 @@ func (t *AWSVPCTracker) infof(fmt string, args ...interface{}) {
// 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 {
+46
View File
@@ -0,0 +1,46 @@
package tracker
import (
"github.com/weaveworks/weave/net/address"
)
// 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
}
@@ -19,7 +19,7 @@ var (
func TestRemoveCommon(t *testing.T) {
a := []address.CIDR{r0to127, r1dot0to255}
b := []address.CIDR{r1dot0to255, r2dot0to255}
newA, newB := removeCommon(a, b)
newA, newB := RemoveCommon(a, b)
require.Equal(t, []address.CIDR{r0to127}, newA)
require.Equal(t, []address.CIDR{r2dot0to255}, newB)
}
@@ -30,7 +30,7 @@ func TestMerge(t *testing.T) {
r128to255.Range(),
r2dot0to255.Range(),
}
require.Equal(t, []address.Range{r0to255.Range(), r2dot0to255.Range()}, merge(ranges))
require.Equal(t, []address.Range{r0to255.Range(), r2dot0to255.Range()}, Merge(ranges))
}
// Helper
+3
View File
@@ -17,4 +17,7 @@ type LocalRangeTracker interface {
// 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
// String returns the tracker name
String() string
}
+1 -1
View File
@@ -10,7 +10,7 @@ import (
// Configure the ARP cache parameters for the given interface. This
// makes containers react more quickly to a change in the MAC address
// associated with an IP address.
func ConfigureARPCache(procPath, name string) error {
func configureARPCache(procPath, name string) error {
if err := sysctl(procPath, fmt.Sprintf("net/ipv4/neigh/%s/base_reachable_time", name), "5"); err != nil {
return err
}
+163 -65
View File
@@ -6,13 +6,18 @@ import (
"net"
"path/filepath"
"github.com/Sirupsen/logrus"
"github.com/coreos/go-iptables/iptables"
"github.com/j-keck/arping"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"k8s.io/apimachinery/pkg/types"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/common/odp"
"github.com/weaveworks/weave/ipam/tracker"
"github.com/weaveworks/weave/net/address"
"github.com/weaveworks/weave/net/ipset"
"github.com/weaveworks/weave/npc"
)
/* This code implements three possible configurations to connect
@@ -48,11 +53,12 @@ datapath of old kernel versions (https://github.com/weaveworks/weave/issues/1577
*/
const (
WeaveBridgeName = "weave"
DatapathName = "datapath"
DatapathIfName = "vethwe-datapath"
BridgeIfName = "vethwe-bridge"
PcapIfName = "vethwe-pcap"
WeaveBridgeName = "weave"
DatapathName = "datapath"
DatapathIfName = "vethwe-datapath"
BridgeIfName = "vethwe-bridge"
PcapIfName = "vethwe-pcap"
NoMasqLocalIpset = ipset.Name("weaver-no-masq-local")
)
type Bridge interface {
@@ -214,6 +220,7 @@ type BridgeConfig struct {
MTU int
Mac string
Port int
NoMasqLocal bool
}
func (config *BridgeConfig) configuredBridgeType() Bridge {
@@ -227,13 +234,20 @@ func (config *BridgeConfig) configuredBridgeType() Bridge {
}
}
func EnsureBridge(procPath string, config *BridgeConfig, log *logrus.Logger) (Bridge, error) {
bridgeType, err := ExistingBridgeType(config.WeaveBridgeName, config.DatapathName)
if bridgeType != nil || err != nil {
return bridgeType, err
func EnsureBridge(procPath string, config *BridgeConfig, log *logrus.Logger, ips ipset.Interface) (Bridge, error) {
existingBridgeType, err := ExistingBridgeType(config.WeaveBridgeName, config.DatapathName)
if err != nil {
return nil, err
}
bridgeType := config.configuredBridgeType()
if existingBridgeType != nil && bridgeType.String() != existingBridgeType.String() {
return nil,
fmt.Errorf("Existing bridge type %q is different than requested %q. Please do 'weave reset' and try again",
existingBridgeType, bridgeType)
}
bridgeType = config.configuredBridgeType()
for {
if err := bridgeType.init(config); err != nil {
if errors.Cause(err) == errBridgeNotSupported {
@@ -246,7 +260,7 @@ func EnsureBridge(procPath string, config *BridgeConfig, log *logrus.Logger) (Br
break
}
if err := configureIPTables(config); err != nil {
if err := configureIPTables(config, ips); err != nil {
return bridgeType, errors.Wrap(err, "configuring iptables")
}
@@ -269,10 +283,16 @@ func EnsureBridge(procPath string, config *BridgeConfig, log *logrus.Logger) (Br
return bridgeType, err
}
if err := ConfigureARPCache(procPath, config.WeaveBridgeName); err != nil {
if err := configureARPCache(procPath, config.WeaveBridgeName); err != nil {
return bridgeType, errors.Wrapf(err, "configuring ARP cache on bridge %q", config.WeaveBridgeName)
}
// NB: No concurrent call to Expose is possible, as EnsureBridge is called
// before any service has been started.
if err := reexpose(config, log); err != nil {
return bridgeType, err
}
return bridgeType, nil
}
@@ -289,7 +309,7 @@ func (b bridgeImpl) initPrep(config *BridgeConfig) error {
config.MTU = 65535
}
b.bridge = &netlink.Bridge{LinkAttrs: linkAttrs}
if err = netlink.LinkAdd(b.bridge); err != nil {
if err := LinkAddIfNotExist(b.bridge); err != nil {
return errors.Wrapf(err, "creating bridge %q", config.WeaveBridgeName)
}
if err := netlink.LinkSetHardwareAddr(b.bridge, mac); err != nil {
@@ -321,7 +341,7 @@ func (b bridgeImpl) init(config *BridgeConfig) error {
if err := b.initPrep(config); err != nil {
return err
}
if _, err := CreateAndAttachVeth(BridgeIfName, PcapIfName, config.WeaveBridgeName, config.MTU, true, func(veth netlink.Link) error {
if _, err := CreateAndAttachVeth(BridgeIfName, PcapIfName, config.WeaveBridgeName, config.MTU, true, false, func(veth netlink.Link) error {
return netlink.LinkSetUp(veth)
}); err != nil {
return errors.Wrap(err, "creating pcap veth pair")
@@ -371,11 +391,11 @@ func (bf bridgedFastdpImpl) init(config *BridgeConfig) error {
if err := bf.bridgeImpl.initPrep(config); err != nil {
return err
}
if _, err := CreateAndAttachVeth(BridgeIfName, DatapathIfName, config.WeaveBridgeName, config.MTU, true, func(veth netlink.Link) error {
if _, err := CreateAndAttachVeth(BridgeIfName, DatapathIfName, config.WeaveBridgeName, config.MTU, true, false, func(veth netlink.Link) error {
if err := netlink.LinkSetUp(veth); err != nil {
return errors.Wrapf(err, "setting link up on %q", veth.Attrs().Name)
}
if err := odp.AddDatapathInterface(bf.datapathName, veth.Attrs().Name); err != nil {
if err := odp.AddDatapathInterfaceIfNotExist(bf.datapathName, veth.Attrs().Name); err != nil {
return errors.Wrapf(err, "adding interface %q to datapath %q", veth.Attrs().Name, bf.datapathName)
}
return nil
@@ -395,20 +415,21 @@ func (bf bridgedFastdpImpl) attach(veth *netlink.Veth) error {
}
func (f fastdpImpl) attach(veth *netlink.Veth) error {
return odp.AddDatapathInterface(f.datapathName, veth.Attrs().Name)
return odp.AddDatapathInterfaceIfNotExist(f.datapathName, veth.Attrs().Name)
}
func configureIPTables(config *BridgeConfig) error {
func configureIPTables(config *BridgeConfig, ips ipset.Interface) error {
ipt, err := iptables.New()
if err != nil {
return errors.Wrap(err, "creating iptables object")
}
// The order among weave filter/FORWARD rules is important!
fwdRules := make([][]string, 0)
if config.DockerBridgeName != "" {
if config.WeaveBridgeName != config.DockerBridgeName {
err := ipt.Insert("filter", "FORWARD", 1, "-i", config.DockerBridgeName, "-o", config.WeaveBridgeName, "-j", "DROP")
if err != nil {
return err
}
fwdRules = append(fwdRules, []string{"-i", config.DockerBridgeName, "-o", config.WeaveBridgeName, "-j", "DROP"})
}
dockerBridgeIP, err := FindBridgeIP(config.DockerBridgeName, nil)
@@ -437,39 +458,122 @@ func configureIPTables(config *BridgeConfig) error {
}
if config.NPC {
// Steer traffic via the NPC
_ = ipt.NewChain("filter", "WEAVE-NPC") // ignore error because it might already exist
// If WEAVE-NPC chain doesn't exist then next line will fail
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-j", "WEAVE-NPC"); err != nil {
// Steer traffic via the NPC.
if err = ensureChains(ipt, "filter", npc.MainChain, npc.EgressChain); err != nil {
return err
}
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-m", "state", "--state", "NEW", "-j", "NFLOG", "--nflog-group", "86"); err != nil {
return err
}
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-j", "DROP"); err != nil {
// Steer egress traffic destined to local node.
if err = ipt.AppendUnique("filter", "INPUT", "-i", config.WeaveBridgeName, "-j", npc.EgressChain); err != nil {
return err
}
fwdRules = append(fwdRules,
[][]string{
// Might include ingress traffic which is fine as long as we do not
// ACCEPT in WEAVE-NPC-EGRESS chain
{"-i", config.WeaveBridgeName,
"-m", "comment", "--comment", "NOTE: this must go before '-j KUBE-FORWARD'",
"-j", npc.EgressChain},
// The following rules are for ingress NPC processing
{"-o", config.WeaveBridgeName,
"-m", "comment", "--comment", "NOTE: this must go before '-j KUBE-FORWARD'",
"-j", npc.MainChain},
{"-o", config.WeaveBridgeName, "-m", "state", "--state", "NEW", "-j", "NFLOG", "--nflog-group", "86"},
{"-o", config.WeaveBridgeName, "-j", "DROP"},
}...)
} else {
// Work around the situation where there are no rules allowing traffic
// across our bridge. E.g. ufw
if err = ipt.AppendUnique("filter", "FORWARD", "-i", config.WeaveBridgeName, "-o", config.WeaveBridgeName, "-j", "ACCEPT"); err != nil {
return err
fwdRules = append(fwdRules, []string{"-i", config.WeaveBridgeName, "-o", config.WeaveBridgeName, "-j", "ACCEPT"})
}
if !config.NPC {
// Create/Flush a chain for allowing ingress traffic when the bridge is exposed
if err := ipt.ClearChain("filter", "WEAVE-EXPOSE"); err != nil {
return errors.Wrap(err, "failed to clear/create filter/WEAVE-EXPOSE chain")
}
fwdRules = append(fwdRules, []string{"-o", config.WeaveBridgeName, "-j", "WEAVE-EXPOSE"})
}
// Forward from weave to the rest of the world
if err = ipt.AppendUnique("filter", "FORWARD", "-i", config.WeaveBridgeName, "!", "-o", config.WeaveBridgeName, "-j", "ACCEPT"); err != nil {
return err
}
fwdRules = append(fwdRules, []string{"-i", config.WeaveBridgeName, "!", "-o", config.WeaveBridgeName, "-j", "ACCEPT"})
// and allow replies back
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"); err != nil {
fwdRules = append(fwdRules, []string{"-o", config.WeaveBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"})
if err := ensureRulesAtTop("filter", "FORWARD", fwdRules, ipt); err != nil {
return err
}
// create a chain for masquerading
if err = ipt.ClearChain("nat", "WEAVE"); err != nil {
return errors.Wrap(err, "clearing WEAVE chain")
// Create a chain for masquerading
if err := ipt.ClearChain("nat", "WEAVE"); err != nil {
return errors.Wrap(err, "failed to clear/create nat/WEAVE chain")
}
return ipt.AppendUnique("nat", "POSTROUTING", "-j", "WEAVE")
if err := ipt.AppendUnique("nat", "POSTROUTING", "-j", "WEAVE"); err != nil {
return err
}
// For the cases where the weave bridge is the default gateway for
// containers (e.g. Kubernetes): create the ipset to store CIDRs allocated
// by IPAM for local containers. In the case of Kubernetes, external traffic
// sent to these CIDRs avoids SNAT'ing so that NodePort with
// `"externalTrafficPolicy":"Local"` would receive packets with correct
// src IP addr.
if config.NoMasqLocal {
ips := ipset.New(common.LogLogger(), 0)
_ = ips.Destroy(NoMasqLocalIpset)
if err := ips.Create(NoMasqLocalIpset, ipset.HashNet); err != nil {
return err
}
if err := ipt.Insert("nat", "WEAVE", 1,
"-m", "set", "--match-set", string(NoMasqLocalIpset), "dst",
"-m", "comment", "--comment", "Prevent SNAT to locally running containers",
"-j", "RETURN"); err != nil {
return err
}
}
return nil
}
type NoMasqLocalTracker struct {
ips ipset.Interface
owner types.UID
}
func NewNoMasqLocalTracker(ips ipset.Interface) *NoMasqLocalTracker {
return &NoMasqLocalTracker{
ips: ips,
owner: types.UID(0), // dummy ipset owner
}
}
func (t *NoMasqLocalTracker) String() string {
return "no-masq-local"
}
func (t *NoMasqLocalTracker) HandleUpdate(prevRanges, currRanges []address.Range, local bool) error {
if !local {
return nil
}
prev, curr := tracker.RemoveCommon(
address.NewCIDRs(tracker.Merge(prevRanges)),
address.NewCIDRs(tracker.Merge(currRanges)))
for _, cidr := range curr {
if err := t.ips.AddEntry(t.owner, NoMasqLocalIpset, cidr.String(), ""); err != nil {
return err
}
}
for _, cidr := range prev {
if err := t.ips.DelEntry(t.owner, NoMasqLocalIpset, cidr.String()); err != nil {
return err
}
}
return nil
}
func linkSetUpByName(linkName string) error {
@@ -480,34 +584,28 @@ func linkSetUpByName(linkName string) error {
return netlink.LinkSetUp(link)
}
func AddBridgeAddr(bridgeName string, addr *net.IPNet, removeDefaultRoute bool) error {
link, err := netlink.LinkByName(bridgeName)
func reexpose(config *BridgeConfig, log *logrus.Logger) error {
// Get existing IP addrs of the weave bridge.
// If the bridge hasn't been exposed, then this functions does nothing.
//
// Ideally, we should consult IPAM for IP addrs allocated to "weave:expose",
// but we don't want to introduce dependency on IPAM, as weave should be able
// to run w/o IPAM.
link, err := netlink.LinkByName(config.WeaveBridgeName)
if err != nil {
return errors.Wrapf(err, "AddBridgeAddr finding bridge %q", bridgeName)
return errors.Wrapf(err, "cannot find bridge %q", config.WeaveBridgeName)
}
newAddresses, err := AddAddresses(link, []*net.IPNet{addr})
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return errors.Wrapf(err, "adding address %v to %q", addr, bridgeName)
return errors.Wrapf(err, "cannot list IPv4 addrs of bridge %q", config.WeaveBridgeName)
}
for _, ipnet := range newAddresses {
arping.GratuitousArpOverIfaceByName(ipnet.IP, bridgeName)
}
if removeDefaultRoute {
routeFilter := &netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{IP: addr.IP.Mask(addr.Mask), Mask: addr.Mask},
Protocol: 2, // RTPROT_KERNEL
}
filterMask := netlink.RT_FILTER_OIF | netlink.RT_FILTER_DST | netlink.RT_FILTER_PROTOCOL
routes, err := netlink.RouteListFiltered(netlink.FAMILY_V4, routeFilter, filterMask)
if err != nil {
return errors.Wrapf(err, "failed to get route list for bridge %q", bridgeName)
}
for _, r := range routes {
if err = netlink.RouteDel(&r); err != nil {
return errors.Wrapf(err, "failed to delete default route %+v", r)
}
for _, addr := range addrs {
log.Infof("Re-exposing %s on bridge %q", addr.IPNet, config.WeaveBridgeName)
if err := Expose(config.WeaveBridgeName, addr.IPNet, config.AWSVPC, config.NPC); err != nil {
return errors.Wrapf(err, "unable to re-expose %s on bridge: %q", addr.IPNet, config.WeaveBridgeName)
}
}
return nil
}
+115
View File
@@ -0,0 +1,115 @@
package net
import (
"net"
"syscall"
"github.com/coreos/go-iptables/iptables"
"github.com/j-keck/arping"
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
)
// Expose makes the network accessible from a host by assigning a given IP address
// to the weave bridge.
//
// List of params:
// * "bridgeName" - a name of the weave bridge.
// * "ipAddr" - IP addr to be assigned to the bridge.
// * "removeDefaultRoute" - whether to remove a default route installed by the kernel (used only in the AWSVPC mode).
// * "npc" - whether is Weave NPC running.
func Expose(bridgeName string, ipAddr *net.IPNet, removeDefaultRoute, npc bool) error {
ipt, err := iptables.New()
if err != nil {
return errors.Wrap(err, "iptables.New")
}
cidr := ipAddr.String()
if err := addBridgeIPAddr(bridgeName, ipAddr, removeDefaultRoute); err != nil {
return errors.Wrap(err, "addBridgeIPAddr")
}
if err := exposeNAT(ipt, cidr); err != nil {
return errors.Wrap(err, "exposeNAT")
}
if !npc {
// Docker 1.13 has changed a default policy of FORWARD chain to DROP
// (https://github.com/moby/moby/pull/28257) which makes containers
// inaccessible from a remote host when the bridge is exposed.
//
// The change breaks e.g. the AWSVPC mode. To overcome this we install
// an explicit rule for accepting forwarded ingress traffic to an
// exposed subnet.
if err := ipt.AppendUnique("filter", "WEAVE-EXPOSE", "-d", cidr, "-j", "ACCEPT"); err != nil {
return errors.Wrap(err, "ipt.AppendUnique")
}
}
return nil
}
func addBridgeIPAddr(bridgeName string, addr *net.IPNet, removeDefaultRoute bool) error {
link, err := netlink.LinkByName(bridgeName)
if err != nil {
return errors.Wrapf(err, "addBridgeIPAddr finding bridge %q", bridgeName)
}
err = netlink.AddrAdd(link, &netlink.Addr{IPNet: addr})
// The IP addr might have been already set by a concurrent request, just ignore then
if err != nil && err != syscall.Errno(syscall.EEXIST) {
return errors.Wrapf(err, "adding address %v to %q", addr, bridgeName)
}
// Sending multiple ARP REQUESTs in the case of EEXIST above does not hurt
arping.GratuitousArpOverIfaceByName(addr.IP, bridgeName)
// Remove a default route installed by the kernel. Required by the AWSVPC mode.
if removeDefaultRoute {
routeFilter := &netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{IP: addr.IP.Mask(addr.Mask), Mask: addr.Mask},
Protocol: 2, // RTPROT_KERNEL
}
filterMask := netlink.RT_FILTER_OIF | netlink.RT_FILTER_DST | netlink.RT_FILTER_PROTOCOL
routes, err := netlink.RouteListFiltered(netlink.FAMILY_V4, routeFilter, filterMask)
if err != nil {
return errors.Wrapf(err, "failed to get route list for bridge %q", bridgeName)
}
for _, r := range routes {
err = netlink.RouteDel(&r)
// Again, there might be a concurrent request for removing routes
if err != nil && err != syscall.Errno(syscall.ESRCH) {
return errors.Wrapf(err, "failed to delete default route %+v", r)
}
}
}
return nil
}
func exposeNAT(ipt *iptables.IPTables, cidr string) error {
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
}
return addNatRule(ipt, "-s", cidr, "!", "-d", cidr, "-j", "MASQUERADE")
}
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
}
}
+1 -1
View File
@@ -12,9 +12,9 @@ import (
"sync"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/coreos/go-iptables/iptables"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"golang.org/x/crypto/hkdf"
+214
View File
@@ -0,0 +1,214 @@
package ipset
import (
"crypto/rand"
"encoding/hex"
"fmt"
"log"
"os/exec"
"strings"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/types"
)
type Name string
type Type string
const (
ListSet = Type("list:set")
HashIP = Type("hash:ip")
HashNet = Type("hash:net")
)
type Interface interface {
Create(ipsetName Name, ipsetType Type) error
AddEntry(user types.UID, ipsetName Name, entry string, comment string) error
DelEntry(user types.UID, ipsetName Name, entry string) error
Exist(user types.UID, ipsetName Name, entry string) bool
Flush(ipsetName Name) error
Destroy(ipsetName Name) error
List(prefix string) ([]Name, error)
FlushAll() error
DestroyAll() error
}
type entryKey struct {
ipsetName Name
entry string
}
type ipset struct {
*log.Logger
enableComments bool
maxListSize int
// List of users per ipset entry. User is either a namespace or a pod.
// There might be multiple users for the same ipset & entry pair because
// events from k8s API server might be out of order causing duplicate IPs:
// https://github.com/weaveworks/weave/issues/2792.
users map[entryKey]map[types.UID]struct{}
}
func New(logger *log.Logger, maxListSize int) Interface {
ips := &ipset{
Logger: logger,
enableComments: true,
maxListSize: maxListSize,
users: make(map[entryKey]map[types.UID]struct{}),
}
// Check for comment support
// To prevent from a race when more than one process check for the support
// we append a random nonce to the test ipset name. The final name is
// shorter than 31 chars (max ipset name).
nonce := make([]byte, 4)
rand.Read(nonce)
testIpsetName := Name("weave-test-comment" + hex.EncodeToString(nonce))
// Clear it out if it already exists
_ = ips.Destroy(testIpsetName)
// Test for comment support
if err := ips.Create(testIpsetName, HashIP); err != nil {
ips.Logger.Printf("failed to create %s; disabling comment support", testIpsetName)
ips.enableComments = false
}
// If it was created, destroy it
_ = ips.Destroy(testIpsetName)
return ips
}
func (i *ipset) Create(ipsetName Name, ipsetType Type) error {
args := []string{"create", string(ipsetName), string(ipsetType)}
if ipsetType == ListSet && i.maxListSize > 0 {
args = append(args, "size", fmt.Sprintf("%d", i.maxListSize))
}
if i.enableComments {
args = append(args, "comment")
}
return doExec(args...)
}
func (i *ipset) AddEntry(user types.UID, ipsetName Name, entry string, comment string) error {
i.Logger.Printf("adding entry %s to %s of %s", entry, ipsetName, user)
if !i.addUser(user, ipsetName, entry) { // already in the set
return nil
}
i.Logger.Printf("added entry %s to %s of %s", entry, ipsetName, user)
args := []string{"add", string(ipsetName), entry}
if i.enableComments {
args = append(args, "comment", comment)
}
return doExec(args...)
}
func (i *ipset) DelEntry(user types.UID, ipsetName Name, entry string) error {
i.Logger.Printf("deleting entry %s from %s of %s", entry, ipsetName, user)
if !i.delUser(user, ipsetName, entry) { // still needed
return nil
}
i.Logger.Printf("deleted entry %s from %s of %s", entry, ipsetName, user)
return doExec("del", string(ipsetName), entry)
}
func (i *ipset) Exist(user types.UID, ipsetName Name, entry string) bool {
return i.existUser(user, ipsetName, entry)
}
func (i *ipset) Flush(ipsetName Name) error {
i.removeSetFromUsers(ipsetName)
return doExec("flush", string(ipsetName))
}
func (i *ipset) FlushAll() error {
i.users = make(map[entryKey]map[types.UID]struct{})
return doExec("flush")
}
func (i *ipset) Destroy(ipsetName Name) error {
i.removeSetFromUsers(ipsetName)
return doExec("destroy", string(ipsetName))
}
func (i *ipset) DestroyAll() error {
i.users = make(map[entryKey]map[types.UID]struct{})
return doExec("destroy")
}
// Fetch a list of all existing sets with a given prefix
func (i *ipset) List(prefix string) ([]Name, error) {
output, err := exec.Command("ipset", "list", "-name", "-output", "plain").Output()
if err != nil {
return nil, err
}
var selected []Name
sets := strings.Split(string(output), "\n")
for _, v := range sets {
if strings.HasPrefix(v, prefix) {
selected = append(selected, Name(v))
}
}
return selected, err
}
// Returns true if entry does not exist in ipset (entry has to be inserted into ipset).
func (i *ipset) addUser(user types.UID, ipsetName Name, entry string) bool {
k := entryKey{ipsetName, entry}
add := false
if i.users[k] == nil {
i.users[k] = make(map[types.UID]struct{})
}
if len(i.users[k]) == 0 {
add = true
}
i.users[k][user] = struct{}{}
return add
}
// Returns true if user is the last owner of entry (entry has to be removed from ipset).
func (i *ipset) delUser(user types.UID, ipsetName Name, entry string) bool {
k := entryKey{ipsetName, entry}
oneLeft := len(i.users[k]) == 1
delete(i.users[k], user)
if len(i.users[k]) == 0 {
delete(i.users, k)
}
return oneLeft && (len(i.users[k]) == 0)
}
func (i *ipset) existUser(user types.UID, ipsetName Name, entry string) bool {
_, ok := i.users[entryKey{ipsetName, entry}][user]
return ok
}
func (i *ipset) removeSetFromUsers(ipsetName Name) {
for k := range i.users {
if k.ipsetName == ipsetName {
delete(i.users, k)
}
}
}
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
}
+106
View File
@@ -0,0 +1,106 @@
package net
import (
"strings"
"github.com/coreos/go-iptables/iptables"
"github.com/pkg/errors"
)
// AddChainWithRules creates a chain and appends given rules to it.
//
// If the chain exists, but its rules are not the same as the given ones, the
// function will flush the chain and then will append the rules.
func AddChainWithRules(ipt *iptables.IPTables, table, chain string, rulespecs [][]string) error {
if err := ensureChains(ipt, table, chain); err != nil {
return err
}
currRuleSpecs, err := ipt.List(table, chain)
if err != nil {
return errors.Wrapf(err, "iptables -S. table: %q, chain: %q", table, chain)
}
// First returned rule is "-N $(chain)", so ignore it
currRules := strings.Join(currRuleSpecs[1:], "\n")
rules := make([]string, 0)
for _, r := range rulespecs {
rules = append(rules, strings.Join(r, " "))
}
reqRules := strings.Join(rules, "\n")
if currRules == reqRules {
return nil
}
if err := ipt.ClearChain(table, chain); err != nil {
return err
}
for _, r := range rulespecs {
if err := ipt.Append(table, chain, r...); err != nil {
return errors.Wrapf(err, "iptables -A. table: %q, chain: %q, rule: %s", table, chain, r)
}
}
return nil
}
// ensureChains creates given chains if they do not exist.
func ensureChains(ipt *iptables.IPTables, table string, chains ...string) error {
existingChains, err := ipt.ListChains(table)
if err != nil {
return errors.Wrapf(err, "ipt.ListChains(%s)", table)
}
chainMap := make(map[string]struct{})
for _, c := range existingChains {
chainMap[c] = struct{}{}
}
for _, c := range chains {
if _, found := chainMap[c]; !found {
if err := ipt.NewChain(table, c); err != nil {
return errors.Wrapf(err, "ipt.NewChain(%s, %s)", table, c)
}
}
}
return nil
}
// ensureRulesAtTop ensures the presence of given iptables rules.
//
// If any rule from the list is missing, the function deletes all given
// rules and re-inserts them at the top of the chain to ensure the order of the rules.
func ensureRulesAtTop(table, chain string, rulespecs [][]string, ipt *iptables.IPTables) error {
allFound := true
for _, rs := range rulespecs {
found, err := ipt.Exists(table, chain, rs...)
if err != nil {
return errors.Wrapf(err, "ipt.Exists(%s, %s, %s)", table, chain, rs)
}
if !found {
allFound = false
break
}
}
// All rules exist, do nothing.
if allFound {
return nil
}
for pos, rs := range rulespecs {
// If any is missing, then delete all, as we need to preserve the order of
// given rules. Ignore errors, as rule might not exist.
if !allFound {
ipt.Delete(table, chain, rs...)
}
if err := ipt.Insert(table, chain, pos+1, rs...); err != nil {
return errors.Wrapf(err, "ipt.Append(%s, %s, %s)", table, chain, rs)
}
}
return nil
}
+25 -13
View File
@@ -1,11 +1,9 @@
package net
import (
"encoding/json"
"fmt"
"net"
"os"
"strconv"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
@@ -17,7 +15,7 @@ type Dev struct {
CIDRs []*net.IPNet `json:"CIDRs,omitempty"`
}
func LinkToNetDev(link netlink.Link) (Dev, error) {
func linkToNetDev(link netlink.Link) (Dev, error) {
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return Dev{}, err
@@ -90,16 +88,30 @@ func GetNetDevsByVethPeerIds(processID int, peerIDs []int) ([]Dev, error) {
return nil, nil
}
// convert list of peerIDs into a map for faster lookup
indexes := make(map[int]struct{})
for _, id := range peerIDs {
indexes[id] = struct{}{}
}
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)
err = WithNetNS(netnsContainer, func() error {
links, err := netlink.LinkList()
if err != nil {
return err
}
for _, link := range links {
if _, found := indexes[link.Attrs().Index]; found {
netdev, err := linkToNetDev(link)
if err != nil {
return err
}
netdevs = append(netdevs, netdev)
}
}
return nil
})
return netdevs, err
}
@@ -112,5 +124,5 @@ func GetBridgeNetDev(bridgeName string) (Dev, error) {
return Dev{}, err
}
return LinkToNetDev(link)
return linkToNetDev(link)
}
+16
View File
@@ -0,0 +1,16 @@
package net
import (
"syscall"
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
)
func LinkAddIfNotExist(link netlink.Link) error {
err := netlink.LinkAdd(link)
if err != nil && err == syscall.EEXIST {
return nil
}
return errors.Wrapf(err, "creating link %q", link)
}
+10 -36
View File
@@ -1,10 +1,10 @@
// +build go1.10
package net
import (
"bytes"
"errors"
"fmt"
"os/exec"
"path/filepath"
"runtime"
@@ -14,19 +14,7 @@ import (
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 {
func WithNetNS(ns netns.NsHandle, work func() error) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -45,8 +33,8 @@ func WithNetNSUnsafe(ns netns.NsHandle, work func() error) error {
return err
}
func WithNetNSLinkUnsafe(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error {
return WithNetNSUnsafe(ns, func() error {
func WithNetNSLink(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error {
return WithNetNS(ns, func() error {
link, err := netlink.LinkByName(ifName)
if err != nil {
if err.Error() == errors.New("Link not found").Error() {
@@ -58,26 +46,12 @@ func WithNetNSLinkUnsafe(ns netns.NsHandle, ifName string, work func(link netlin
})
}
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)
func WithNetNSByPath(path string, work func() error) error {
ns, err := netns.GetFromPath(path)
if err != nil {
return err
}
return stdout.Bytes(), nil
}
func WithNetNSByPid(pid int, cmd string, args ...string) ([]byte, error) {
return WithNetNS(NSPathByPid(pid), cmd, args...)
return WithNetNS(ns, work)
}
func NSPathByPid(pid int) string {
+44 -54
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"net"
"strings"
"syscall"
"time"
"github.com/coreos/go-iptables/iptables"
@@ -14,7 +13,7 @@ import (
)
// 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) {
func CreateAndAttachVeth(name, peerName, bridgeName string, mtu int, keepTXOn bool, errIfLinkExist 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)
@@ -29,7 +28,12 @@ func CreateAndAttachVeth(name, peerName, bridgeName string, mtu int, keepTXOn bo
MTU: mtu},
PeerName: peerName,
}
if err := netlink.LinkAdd(veth); err != nil {
linkAdd := LinkAddIfNotExist
if errIfLinkExist {
linkAdd = netlink.LinkAdd
}
if err := linkAdd(veth); err != nil {
return nil, fmt.Errorf(`could not create veth pair %s-%s: %s`, name, peerName, err)
}
@@ -100,7 +104,10 @@ const (
)
func interfaceExistsInNamespace(netNSPath string, ifName string) bool {
_, err := WithNetNS(netNSPath, "check-iface", ifName)
err := WithNetNSByPath(netNSPath, func() error {
_, err := netlink.LinkByName(ifName)
return err
})
return err == nil
}
@@ -117,11 +124,13 @@ func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMult
id = id[:maxIDLen] // trim passed ID if too long
}
name, peerName := vethPrefix+"pl"+id, vethPrefix+"pg"+id
veth, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, keepTXOn, func(veth netlink.Link) error {
veth, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, keepTXOn, true, 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 {
if err := WithNetNS(ns, func() error {
return setupIface(peerName, ifName)
}); err != nil {
return fmt.Errorf("error setting up interface: %s", err)
}
return nil
@@ -135,19 +144,16 @@ func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMult
}
args := []string{ifName, fmt.Sprintf("%t", withMulticastRoute)}
for _, cidr := range cidrs {
args = append(args, cidr.String())
}
if _, err := WithNetNS(netNSPath, "setup-iface-addrs", args...); err != nil {
if err := WithNetNSLink(ns, ifName, func(veth netlink.Link) error {
return setupIfaceAddrs(veth, withMulticastRoute, cidrs)
}); err != nil {
return fmt.Errorf("error setting up interface addresses: %s", err)
}
return nil
}
// SetupIfaceAddrs is the implementation of the 'setup-iface-addrs' call above,
// running in another process in the container's netns
func SetupIfaceAddrs(veth netlink.Link, withMulticastRoute bool, cidrs []*net.IPNet) error {
// setupIfaceAddrs expects to be called in the container's netns
func setupIfaceAddrs(veth netlink.Link, withMulticastRoute bool, cidrs []*net.IPNet) error {
newAddresses, err := AddAddresses(veth, cidrs)
if err != nil {
return err
@@ -199,9 +205,8 @@ func SetupIfaceAddrs(veth netlink.Link, withMulticastRoute bool, cidrs []*net.IP
return nil
}
// SetupIface is the implementation of the 'setup-iface' call above,
// running in another process in the container's netns
func SetupIface(ifaceName, newIfName string) error {
// setupIface expects to be called in the container's netns
func setupIface(ifaceName, newIfName string) error {
ipt, err := iptables.New()
if err != nil {
return err
@@ -215,14 +220,32 @@ func SetupIface(ifaceName, newIfName string) error {
return err
}
// This is only called by AttachContainer which is only called in host pid namespace
if err := ConfigureARPCache("/proc", newIfName); err != nil {
if err := configureARPCache("/proc", newIfName); err != nil {
return err
}
return ipt.Append("filter", "INPUT", "-i", newIfName, "-d", "224.0.0.0/4", "-j", "DROP")
}
// NB: This function can be used only by a process that terminates immediately
// after calling the function as it changes netns via WithNetNSLinkUnsafe.
// configureARP is a helper for the Docker plugin which doesn't set the addresses itself
func ConfigureARP(prefix, rootPath string) error {
links, err := netlink.LinkList()
if err != nil {
return err
}
for _, link := range links {
ifName := link.Attrs().Name
if strings.HasPrefix(ifName, prefix) {
configureARPCache(rootPath+"/proc", ifName)
if addrs, err := netlink.AddrList(link, netlink.FAMILY_V4); err == nil {
for _, addr := range addrs {
arping.GratuitousArpOverIfaceByName(addr.IPNet.IP, ifName)
}
}
}
}
return nil
}
func DetachContainer(netNSPath, id, ifName string, cidrs []*net.IPNet) error {
ns, err := netns.GetFromPath(netNSPath)
if err != nil {
@@ -235,7 +258,7 @@ func DetachContainer(netNSPath, id, ifName string, cidrs []*net.IPNet) error {
return err
}
return WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error {
return WithNetNSLink(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)
@@ -297,36 +320,3 @@ func subnets(addrs []netlink.Addr) map[string]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
}
return addNatRule(ipt, "-s", cidr, "!", "-d", cidr, "-j", "MASQUERADE")
}
+161 -78
View File
@@ -3,112 +3,195 @@ 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"
apiv1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"github.com/weaveworks/weave/npc/ipset"
"github.com/weaveworks/weave/net/ipset"
)
func (ns *ns) analysePolicy(policy *extnapi.NetworkPolicy) (
func (ns *ns) analysePolicy(policy *networkingv1.NetworkPolicy) (
rules map[string]*ruleSpec,
nsSelectors, podSelectors map[string]*selectorSpec,
ipBlocks map[string]*ipBlockSpec,
err error) {
nsSelectors = make(map[string]*selectorSpec)
podSelectors = make(map[string]*selectorSpec)
ipBlocks = make(map[string]*ipBlockSpec)
rules = make(map[string]*ruleSpec)
policyTypes := make([]policyType, 0)
dstSelector, err := newSelectorSpec(&policy.Spec.PodSelector, ns.name, ipset.HashIP)
for _, pt := range policy.Spec.PolicyTypes {
if pt == networkingv1.PolicyTypeIngress {
policyTypes = append(policyTypes, policyTypeIngress)
}
if pt == networkingv1.PolicyTypeEgress {
policyTypes = append(policyTypes, policyTypeEgress)
}
}
// If empty, matches all pods in a namespace
targetSelector, err := newSelectorSpec(&policy.Spec.PodSelector, policyTypes, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, err
return nil, 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
}
// To prevent targetSelector being overwritten by a subsequent selector with
// the same key, addIfNotExist MUST be used when adding to podSelectors.
// Otherwise, policyTypes of the selector might be lost resulting in
// an invalid content in any "default-allow" ipset.
addIfNotExist(targetSelector, podSelectors)
if ingressRule.From != nil && len(ingressRule.From) == 0 {
// From is empty, this rule matches no sources (no traffic matches).
continue
}
// If ingress is empty then this NetworkPolicy does not allow any ingress traffic
if policy.Spec.Ingress != nil && len(policy.Spec.Ingress) != 0 {
for _, ingressRule := range policy.Spec.Ingress {
// If Ports is empty or missing, this rule matches all ports
allPorts := ingressRule.Ports == nil || len(ingressRule.Ports) == 0
// If From is empty or missing, this rule matches all sources
allSources := ingressRule.From == nil || len(ingressRule.From) == 0
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)
if allSources {
if allPorts {
rule := newRuleSpec(policyTypeIngress, nil, nil, targetSelector, 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)
rule := newRuleSpec(policyTypeIngress, &proto, nil, targetSelector, &port)
rules[rule.key] = rule
})
}
} else {
for _, peer := range ingressRule.From {
var srcSelector *selectorSpec
// NetworkPolicyPeer describes a peer to allow traffic from.
// Exactly one of its fields must be specified.
if peer.PodSelector != nil {
srcSelector, err = newSelectorSpec(peer.PodSelector, nil, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, nil, err
}
addIfNotExist(srcSelector, podSelectors)
} else if peer.NamespaceSelector != nil {
srcSelector, err = newSelectorSpec(peer.NamespaceSelector, nil, "", ipset.ListSet)
if err != nil {
return nil, nil, nil, nil, err
}
nsSelectors[srcSelector.key] = srcSelector
}
if allPorts {
rule := newRuleSpec(policyTypeIngress, nil, srcSelector, targetSelector, nil)
rules[rule.key] = rule
} else {
withNormalisedProtoAndPort(ingressRule.Ports, func(proto, port string) {
rule := newRuleSpec(policyTypeIngress, &proto, srcSelector, targetSelector, &port)
rules[rule.key] = rule
})
}
}
}
}
}
return rules, nsSelectors, podSelectors, nil
// If egress is empty then this NetworkPolicy does not allow any egress traffic
if policy.Spec.Egress != nil && len(policy.Spec.Egress) != 0 {
for _, egressRule := range policy.Spec.Egress {
// If Ports is empty or missing, this rule matches all ports
allPorts := egressRule.Ports == nil || len(egressRule.Ports) == 0
// If To is empty or missing, this rule matches all destinations
allDestinations := egressRule.To == nil || len(egressRule.To) == 0
if allDestinations {
if allPorts {
rule := newRuleSpec(policyTypeEgress, nil, targetSelector, nil, nil)
rules[rule.key] = rule
} else {
withNormalisedProtoAndPort(egressRule.Ports, func(proto, port string) {
rule := newRuleSpec(policyTypeEgress, &proto, targetSelector, nil, &port)
rules[rule.key] = rule
})
}
} else {
for _, peer := range egressRule.To {
var dstSelector *selectorSpec
var dstRuleHost ruleHost
// NetworkPolicyPeer describes a peer to allow traffic to.
// Exactly one of its fields must be specified.
if peer.PodSelector != nil {
dstSelector, err = newSelectorSpec(peer.PodSelector, nil, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, nil, err
}
addIfNotExist(dstSelector, podSelectors)
dstRuleHost = dstSelector
} else if peer.NamespaceSelector != nil {
dstSelector, err = newSelectorSpec(peer.NamespaceSelector, nil, "", ipset.ListSet)
if err != nil {
return nil, nil, nil, nil, err
}
nsSelectors[dstSelector.key] = dstSelector
dstRuleHost = dstSelector
} else if peer.IPBlock != nil {
ipBlock := newIPBlockSpec(peer.IPBlock, ns.name)
ipBlocks[ipBlock.key] = ipBlock
dstRuleHost = ipBlock
}
if allPorts {
rule := newRuleSpec(policyTypeEgress, nil, targetSelector, dstRuleHost, nil)
rules[rule.key] = rule
} else {
withNormalisedProtoAndPort(egressRule.Ports, func(proto, port string) {
rule := newRuleSpec(policyTypeEgress, &proto, targetSelector, dstRuleHost, &port)
rules[rule.key] = rule
})
}
}
}
}
}
return rules, nsSelectors, podSelectors, ipBlocks, nil
}
func withNormalisedProtoAndPort(npps []extnapi.NetworkPolicyPort, f func(proto, port string)) {
func addIfNotExist(s *selectorSpec, ss map[string]*selectorSpec) {
if _, ok := ss[s.key]; !ok {
ss[s.key] = s
}
}
func withNormalisedProtoAndPort(npps []networkingv1.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)
f(proto(npp.Protocol), port(npp.Port))
}
}
func proto(p *apiv1.Protocol) string {
// If no proto is specified, default to TCP
proto := string(apiv1.ProtocolTCP)
if p != nil {
proto = string(*p)
}
return proto
}
func port(p *intstr.IntOrString) string {
// If no port is specified, match any port. Let iptables executable handle
// service name resolution
port := "0:65535"
if p != nil {
switch p.Type {
case intstr.Int:
port = fmt.Sprintf("%d", p.IntVal)
case intstr.String:
port = p.StrVal
}
}
return port
}
+6
View File
@@ -7,6 +7,12 @@ const (
DefaultChain = "WEAVE-NPC-DEFAULT"
IngressChain = "WEAVE-NPC-INGRESS"
EgressChain = "WEAVE-NPC-EGRESS"
EgressDefaultChain = "WEAVE-NPC-EGRESS-DEFAULT"
EgressCustomChain = "WEAVE-NPC-EGRESS-CUSTOM"
EgressMarkChain = "WEAVE-NPC-EGRESS-ACCEPT"
EgressMark = "0x40000/0x40000"
IpsetNamePrefix = "weave-"
LocalIpset = IpsetNamePrefix + "local-pods"
+42 -14
View File
@@ -4,11 +4,12 @@ import (
"sync"
"github.com/pkg/errors"
coreapi "k8s.io/client-go/pkg/api/v1"
extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
coreapi "k8s.io/api/core/v1"
extnapi "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/ipset"
"github.com/weaveworks/weave/net/ipset"
"github.com/weaveworks/weave/npc/iptables"
)
@@ -21,9 +22,9 @@ type NetworkPolicyController interface {
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
AddNetworkPolicy(obj interface{}) error
UpdateNetworkPolicy(oldObj, newObj interface{}) error
DeleteNetworkPolicy(obj interface{}) error
}
type controller struct {
@@ -45,7 +46,8 @@ func New(nodeName string, ipt iptables.Interface, ips ipset.Interface) NetworkPo
ips: ips,
nss: make(map[string]*ns)}
c.nsSelectors = newSelectorSet(ips, c.onNewNsSelector)
doNothing := func(*selector, policyType) error { return nil }
c.nsSelectors = newSelectorSet(ips, c.onNewNsSelector, doNothing, doNothing)
return c
}
@@ -54,7 +56,7 @@ 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 := selector.addEntry(string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
if err := selector.addEntry(ns.namespace.ObjectMeta.UID, string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
return err
}
}
@@ -115,32 +117,47 @@ func (npc *controller) DeletePod(obj *coreapi.Pod) error {
})
}
func (npc *controller) AddNetworkPolicy(obj *extnapi.NetworkPolicy) error {
func (npc *controller) AddNetworkPolicy(obj interface{}) error {
npc.Lock()
defer npc.Unlock()
nsName, err := nsName(obj)
if err != nil {
return err
}
common.Log.Infof("EVENT AddNetworkPolicy %s", js(obj))
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
return npc.withNS(nsName, func(ns *ns) error {
return errors.Wrap(ns.addNetworkPolicy(obj), "add network policy")
})
}
func (npc *controller) UpdateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error {
func (npc *controller) UpdateNetworkPolicy(oldObj, newObj interface{}) error {
npc.Lock()
defer npc.Unlock()
nsName, err := nsName(oldObj)
if err != nil {
return err
}
common.Log.Infof("EVENT UpdateNetworkPolicy %s %s", js(oldObj), js(newObj))
return npc.withNS(oldObj.ObjectMeta.Namespace, func(ns *ns) error {
return npc.withNS(nsName, func(ns *ns) error {
return errors.Wrap(ns.updateNetworkPolicy(oldObj, newObj), "update network policy")
})
}
func (npc *controller) DeleteNetworkPolicy(obj *extnapi.NetworkPolicy) error {
func (npc *controller) DeleteNetworkPolicy(obj interface{}) error {
npc.Lock()
defer npc.Unlock()
nsName, err := nsName(obj)
if err != nil {
return err
}
common.Log.Infof("EVENT DeleteNetworkPolicy %s", js(obj))
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
return npc.withNS(nsName, func(ns *ns) error {
return errors.Wrap(ns.deleteNetworkPolicy(obj), "delete network policy")
})
}
@@ -174,3 +191,14 @@ func (npc *controller) DeleteNamespace(obj *coreapi.Namespace) error {
return errors.Wrap(ns.deleteNamespace(obj), "delete namespace")
})
}
func nsName(obj interface{}) (string, error) {
switch obj := obj.(type) {
case *networkingv1.NetworkPolicy:
return obj.ObjectMeta.Namespace, nil
case *extnapi.NetworkPolicy:
return obj.ObjectMeta.Namespace, nil
}
return "", errInvalidNetworkPolicyObjType
}
+450 -38
View File
@@ -1,22 +1,25 @@
package npc
import (
"fmt"
"log"
"strings"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/weaveworks/weave/npc/ipset"
unversionedapi "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/util/intstr"
"github.com/weaveworks/weave/net/ipset"
coreapi "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
)
type mockSet struct {
name ipset.Name
setType ipset.Type
subSets map[string]bool
subSets map[string]map[types.UID]bool
}
type mockIPSet struct {
@@ -24,47 +27,59 @@ type mockIPSet struct {
}
func newMockIPSet() mockIPSet {
i := mockIPSet{
sets: make(map[string]mockSet),
}
return i
return mockIPSet{sets: make(map[string]mockSet)}
}
func (i *mockIPSet) Create(ipsetName ipset.Name, ipsetType ipset.Type) error {
if _, ok := i.sets[string(ipsetName)]; ok {
return errors.Errorf("ipset %s already exists", ipsetName)
}
i.sets[string(ipsetName)] = mockSet{name: ipsetName, setType: ipsetType, subSets: make(map[string]bool)}
i.sets[string(ipsetName)] = mockSet{name: ipsetName, setType: ipsetType, subSets: make(map[string]map[types.UID]bool)}
return nil
}
func (i *mockIPSet) AddEntry(ipsetName ipset.Name, entry string, comment string) error {
log.Printf("adding entry %s to %s", entry, ipsetName)
if _, ok := i.sets[entry]; !ok {
return errors.Errorf("ipset %s does not exist", entry)
func (i *mockIPSet) AddEntry(user types.UID, ipsetName ipset.Name, entry string, comment string) error {
log.Printf("adding entry %s to %s for %s", entry, ipsetName, user)
if _, ok := i.sets[string(ipsetName)]; !ok {
return errors.Errorf("%s does not exist", entry)
}
if _, ok := i.sets[string(ipsetName)].subSets[entry]; ok {
return errors.Errorf("ipset %s is already a member of %s", entry, ipsetName)
if i.sets[string(ipsetName)].subSets[entry] == nil {
i.sets[string(ipsetName)].subSets[entry] = make(map[types.UID]bool)
}
i.sets[string(ipsetName)].subSets[entry] = true
if _, ok := i.sets[string(ipsetName)].subSets[entry][user]; ok {
return errors.Errorf("user %s already owns entry %s", user, entry)
}
i.sets[string(ipsetName)].subSets[entry][user] = true
return nil
}
func (i *mockIPSet) DelEntry(ipsetName ipset.Name, entry string) error {
log.Printf("deleting entry %s from %s", entry, ipsetName)
func (i *mockIPSet) DelEntry(user types.UID, ipsetName ipset.Name, entry string) error {
log.Printf("deleting entry %s from %s for %s", entry, ipsetName, user)
if _, ok := i.sets[string(ipsetName)]; !ok {
return errors.Errorf("ipset %s does not exist", ipsetName)
}
if _, ok := i.sets[string(ipsetName)].subSets[entry]; !ok {
return errors.Errorf("ipset %s is not a member of %s", entry, ipsetName)
if _, ok := i.sets[string(ipsetName)].subSets[entry][user]; !ok {
return errors.Errorf("user %s does not own entry %s", user, entry)
}
delete(i.sets[string(ipsetName)].subSets[entry], user)
if len(i.sets[string(ipsetName)].subSets[entry]) == 0 {
delete(i.sets[string(ipsetName)].subSets, entry)
}
delete(i.sets[string(ipsetName)].subSets, entry)
return nil
}
func (i *mockIPSet) Exist(user types.UID, ipsetName ipset.Name, entry string) bool {
_, ok := i.sets[string(ipsetName)].subSets[entry][user]
return ok
}
func (i *mockIPSet) entryExists(ipsetName ipset.Name, entry string) bool {
return len(i.sets[string(ipsetName)].subSets[entry]) > 0
}
func (i *mockIPSet) Flush(ipsetName ipset.Name) error {
return errors.New("Not Implemented")
}
@@ -90,18 +105,46 @@ func (i *mockIPSet) List(prefix string) ([]ipset.Name, error) {
}
type mockIPTables struct {
rules map[string]map[string]struct{} // chain -> rulespec -> struct{}
}
func newMockIPTables() *mockIPTables {
return &mockIPTables{rules: make(map[string]map[string]struct{})}
}
func (ipt *mockIPTables) Append(table, chain string, rulespec ...string) error {
if table != TableFilter {
return fmt.Errorf("invalid table: %q", table)
}
if _, found := ipt.rules[chain]; !found {
ipt.rules[chain] = make(map[string]struct{})
}
rule := strings.Join(rulespec, " ")
if _, found := ipt.rules[chain][rule]; found {
return fmt.Errorf("rule already exists. chain: %q, rule: %q", chain, rule)
}
ipt.rules[chain][rule] = struct{}{}
return nil
}
func (ipt *mockIPTables) Delete(table, chain string, rulespec ...string) error {
rule := strings.Join(rulespec, " ")
if _, found := ipt.rules[chain][rule]; !found {
return fmt.Errorf("rule does not exist. chain: %q rule: %q", chain, rule)
}
delete(ipt.rules[chain], rule)
return nil
}
func (ipt *mockIPTables) Insert(table, chain string, pos int, rulespec ...string) error {
return nil
return errors.New("Not Implemented")
}
func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
@@ -109,7 +152,7 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
// https://github.com/weaveworks/weave/issues/3059
sourceNamespace := &coreapi.Namespace{
ObjectMeta: coreapi.ObjectMeta{
ObjectMeta: metav1.ObjectMeta{
Name: "source",
Labels: map[string]string{
"app": "source",
@@ -118,31 +161,32 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
}
destinationNamespace := &coreapi.Namespace{
ObjectMeta: coreapi.ObjectMeta{
ObjectMeta: metav1.ObjectMeta{
Name: "destination",
},
}
port := intstr.FromInt(12345)
networkPolicy := &extnapi.NetworkPolicy{
ObjectMeta: coreapi.ObjectMeta{
networkPolicy := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "network-policy",
Namespace: "destination",
},
Spec: extnapi.NetworkPolicySpec{
Ingress: []extnapi.NetworkPolicyIngressRule{
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
Ingress: []networkingv1.NetworkPolicyIngressRule{
{
From: []extnapi.NetworkPolicyPeer{
From: []networkingv1.NetworkPolicyPeer{
{
NamespaceSelector: &unversionedapi.LabelSelector{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "source",
},
},
},
},
Ports: []extnapi.NetworkPolicyPort{
Ports: []networkingv1.NetworkPolicyPort{
{
Port: &port,
},
@@ -154,7 +198,7 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
// Namespaces first
m := newMockIPSet()
controller := New("foo", &mockIPTables{}, &m)
controller := New("foo", newMockIPTables(), &m)
const (
selectorIPSetName = "weave-I239Zp%sCvoVt*D6u=A!2]YEk"
@@ -166,17 +210,385 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
controller.AddNetworkPolicy(networkPolicy)
require.Equal(t, true, m.sets[selectorIPSetName].subSets[sourceIPSetName])
require.Equal(t, true, len(m.sets[selectorIPSetName].subSets[sourceIPSetName]) > 0)
// NetworkPolicy first
m = newMockIPSet()
controller = New("foo", &mockIPTables{}, &m)
controller = New("foo", newMockIPTables(), &m)
controller.AddNetworkPolicy(networkPolicy)
controller.AddNamespace(sourceNamespace)
controller.AddNamespace(destinationNamespace)
require.Equal(t, true, m.sets[selectorIPSetName].subSets[sourceIPSetName])
require.Equal(t, true, len(m.sets[selectorIPSetName].subSets[sourceIPSetName]) > 0)
}
// Tests default-allow ipset behavior
func TestDefaultAllow(t *testing.T) {
const (
ingressDefaultAllowIPSetName = "weave-;rGqyMIl1HN^cfDki~Z$3]6!N"
egressDefaultAllowIPSetName = "weave-s_+ChJId4Uy_$}G;WdH|~TK)I"
fooPodIP = "10.32.0.10"
barPodIP = "10.32.0.11"
barPodNewIP = "10.32.0.12"
)
m := newMockIPSet()
controller := New("bar", newMockIPTables(), &m)
defaultNamespace := &coreapi.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
}
controller.AddNamespace(defaultNamespace)
// Should create an ipset for default-allow
require.Contains(t, m.sets, ingressDefaultAllowIPSetName)
require.Contains(t, m.sets, egressDefaultAllowIPSetName)
podFoo := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: "foo",
Namespace: "default",
Name: "foo",
Labels: map[string]string{"run": "foo"}},
Status: coreapi.PodStatus{PodIP: fooPodIP}}
controller.AddPod(podFoo)
// Should add the foo pod to default-allow
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
require.True(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
podBar := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: "bar",
Namespace: "default",
Name: "bar",
Labels: map[string]string{"run": "bar"}},
Status: coreapi.PodStatus{PodIP: barPodIP}}
podBarNoIP := &coreapi.Pod{ObjectMeta: podBar.ObjectMeta}
controller.AddPod(podBarNoIP)
controller.UpdatePod(podBarNoIP, podBar)
// Should add the bar pod to default-allow
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, barPodIP))
require.True(t, m.entryExists(egressDefaultAllowIPSetName, barPodIP))
// Allow access from the bar pod to the foo pod
netpol := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "allow-from-bar-to-foo",
Namespace: "default",
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{
networkingv1.PolicyTypeIngress,
networkingv1.PolicyTypeEgress,
},
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "foo"}},
Ingress: []networkingv1.NetworkPolicyIngressRule{{
From: []networkingv1.NetworkPolicyPeer{{
PodSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"run": "bar"},
},
}},
}},
Egress: []networkingv1.NetworkPolicyEgressRule{{
To: []networkingv1.NetworkPolicyPeer{{
IPBlock: &networkingv1.IPBlock{CIDR: "192.168.48.0/24"},
}},
}},
},
}
controller.AddNetworkPolicy(netpol)
// Should remove the foo pod from default-allow as the netpol selects it
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
require.False(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, barPodIP))
require.True(t, m.entryExists(egressDefaultAllowIPSetName, barPodIP))
podBarWithNewIP := *podBar
podBarWithNewIP.Status.PodIP = barPodNewIP
controller.UpdatePod(podBar, &podBarWithNewIP)
// Should update IP addr of the bar pod in default-allow
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, barPodIP))
require.False(t, m.entryExists(egressDefaultAllowIPSetName, barPodIP))
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, barPodNewIP))
require.True(t, m.entryExists(egressDefaultAllowIPSetName, barPodNewIP))
controller.UpdatePod(&podBarWithNewIP, podBarNoIP)
// Should remove the bar pod from default-allow as it does not have any IP addr
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, barPodNewIP))
require.False(t, m.entryExists(egressDefaultAllowIPSetName, barPodNewIP))
podFooWithNewLabel := *podFoo
podFooWithNewLabel.ObjectMeta.Labels = map[string]string{"run": "new-foo"}
controller.UpdatePod(podFoo, &podFooWithNewLabel)
// Should bring back the foo pod to default-allow as it does not match dst of any netpol
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
require.True(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
controller.UpdatePod(&podFooWithNewLabel, podFoo)
// Should remove from default-allow as it matches the netpol after the update
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
require.False(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
controller.DeleteNetworkPolicy(netpol)
// Should bring back the foo pod to default-allow as no netpol selects it
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
require.True(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
controller.DeletePod(podFoo)
// Should remove foo pod from default-allow
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
require.False(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
controller.DeleteNamespace(defaultNamespace)
// Should remove default ipset
require.NotContains(t, m.sets, ingressDefaultAllowIPSetName)
require.NotContains(t, m.sets, egressDefaultAllowIPSetName)
}
func TestOutOfOrderPodEvents(t *testing.T) {
const (
ingressDefaultAllowIPSetName = "weave-;rGqyMIl1HN^cfDki~Z$3]6!N"
runBarIPSetName = "weave-bZ~x=yBgzH)Ht()K*Uv3z{M]Y"
podIP = "10.32.0.10"
)
m := newMockIPSet()
controller := New("qux", newMockIPTables(), &m)
defaultNamespace := &coreapi.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
}
controller.AddNamespace(defaultNamespace)
podFoo := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: "foo",
Namespace: "default",
Name: "foo",
Labels: map[string]string{"run": "foo"}},
Status: coreapi.PodStatus{PodIP: podIP}}
controller.AddPod(podFoo)
// Should be in default-allow as no netpol selects podFoo
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
netpol := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "allow-from-bar-to-foo",
Namespace: "default",
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "foo"}},
Ingress: []networkingv1.NetworkPolicyIngressRule{{
From: []networkingv1.NetworkPolicyPeer{{
PodSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"run": "bar"},
},
}},
}},
},
}
controller.AddNetworkPolicy(netpol)
// Shouldn't be in default-allow as netpol above selects podFoo
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
podBar := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: "bar",
Namespace: "default",
Name: "bar",
Labels: map[string]string{"run": "bar"}},
Status: coreapi.PodStatus{PodIP: podIP}}
controller.AddPod(podBar)
// Should be in default-allow as no netpol selects podBar
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
require.True(t, m.Exist(podBar.ObjectMeta.UID, ingressDefaultAllowIPSetName, podIP))
// Should be in run=bar ipset
require.True(t, m.entryExists(runBarIPSetName, podIP))
controller.DeletePod(podFoo)
// Multiple duplicate events should not affect npc state
controller.DeletePod(podFoo)
controller.DeletePod(podFoo)
// Should be in default-allow as no netpol selects podBar and podFoo removal
// should not affect podBar in default-allow
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
controller.DeletePod(podBar)
// Should remove from default-allow and run=bar ipsets
require.Equal(t, 0, len(m.sets[ingressDefaultAllowIPSetName].subSets))
require.False(t, m.entryExists(runBarIPSetName, podIP))
}
// Test case for https://github.com/weaveworks/weave/issues/3222
func TestNewTargetSelector(t *testing.T) {
const (
ingressDefaultAllowIPSetName = "weave-;rGqyMIl1HN^cfDki~Z$3]6!N"
podIP = "10.32.0.10"
)
m := newMockIPSet()
controller := New("baz", newMockIPTables(), &m)
defaultNamespace := &coreapi.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
},
}
controller.AddNamespace(defaultNamespace)
podFoo := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: "foo",
Namespace: "default",
Name: "foo",
Labels: map[string]string{"run": "foo"}},
Status: coreapi.PodStatus{PodIP: podIP}}
controller.AddPod(podFoo)
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
netpolBar := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
UID: "netpol-bar",
Name: "allow-from-default-1",
Namespace: "default",
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
PodSelector: metav1.LabelSelector{},
Ingress: []networkingv1.NetworkPolicyIngressRule{{
From: []networkingv1.NetworkPolicyPeer{{
PodSelector: &metav1.LabelSelector{},
}},
}},
},
}
controller.AddNetworkPolicy(netpolBar)
// netpolBar target selector selects podFoo
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
netpolFoo := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
UID: "netpol-foo",
Name: "allow-from-default-2",
Namespace: "default",
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
PodSelector: metav1.LabelSelector{},
Ingress: []networkingv1.NetworkPolicyIngressRule{{
From: []networkingv1.NetworkPolicyPeer{{
PodSelector: &metav1.LabelSelector{},
}},
}},
},
}
controller.AddNetworkPolicy(netpolFoo)
controller.DeleteNetworkPolicy(netpolBar)
// netpolFoo target-selects podFoo
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
controller.DeleteNetworkPolicy(netpolFoo)
// No netpol target-selects podFoo
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
}
func TestEgressPolicyWithIPBlock(t *testing.T) {
const (
fooPodIP = "10.32.0.10"
exceptIPSetName = "weave-j:W$5om!$8JS})buYAD7q^#sX"
exceptIPSetNameInNonDefault = "weave-|*P{aL2C@#N/1IZ!IvQItv_pt"
)
m := newMockIPSet()
ipt := newMockIPTables()
controller := New("foo", ipt, &m)
netpolFoo := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
UID: "netpol-foo",
Name: "allow-from-bar-to-foo",
Namespace: "default",
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{
networkingv1.PolicyTypeEgress,
},
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "bar"}},
Egress: []networkingv1.NetworkPolicyEgressRule{{
To: []networkingv1.NetworkPolicyPeer{{
IPBlock: &networkingv1.IPBlock{
CIDR: "192.168.48.0/24",
Except: []string{
"192.168.48.1/32",
"192.168.48.2/32",
},
},
}},
}},
},
}
err := controller.AddNetworkPolicy(netpolFoo)
require.NoError(t, err)
require.Equal(t, 2, len(m.sets[exceptIPSetName].subSets))
require.True(t, m.entryExists(exceptIPSetName, "192.168.48.1/32"))
require.True(t, m.entryExists(exceptIPSetName, "192.168.48.2/32"))
// Each egress rule is represented as two iptables rules (-J MARK and -J RETURN).
require.Equal(t, 2, len(ipt.rules[EgressCustomChain]))
for rule := range ipt.rules[EgressCustomChain] {
require.Contains(t, rule, "-d 192.168.48.0/24 -m set ! --match-set "+exceptIPSetName+" dst")
}
// Check that we create a new ipset for the ipBlock bellow. An ipset with the
// same content already exists (created by netpolFoo), but we need to create
// a new one, as netpolBar is in a different namespace and weave-npc does
// object refcounting only within namespace boundaries.
netpolBar := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
UID: "netpol-foo-bar",
Name: "allow-from-bar-to-foo-in-non-default",
Namespace: "non-default",
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{
networkingv1.PolicyTypeEgress,
},
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "bar"}},
Egress: []networkingv1.NetworkPolicyEgressRule{{
To: []networkingv1.NetworkPolicyPeer{{
IPBlock: &networkingv1.IPBlock{
CIDR: "192.168.48.0/24",
Except: []string{
"192.168.48.1/32",
"192.168.48.2/32",
},
},
}},
}},
},
}
err = controller.AddNetworkPolicy(netpolBar)
require.NoError(t, err)
require.Equal(t, 2, len(m.sets[exceptIPSetNameInNonDefault].subSets))
}
+116
View File
@@ -0,0 +1,116 @@
package npc
import (
"fmt"
"sort"
"strings"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/net/ipset"
)
type ipBlockSpec struct {
key string
ipsetName ipset.Name // ipset for storing excepted CIDRs
ipBlock *networkingv1.IPBlock
nsName string // Namespace name
}
func newIPBlockSpec(ipb *networkingv1.IPBlock, nsName string) *ipBlockSpec {
spec := &ipBlockSpec{ipBlock: ipb, nsName: nsName}
if len(ipb.Except) > 0 {
sort.Strings(ipb.Except)
spec.key = strings.Join(ipb.Except, " ")
spec.ipsetName = ipset.Name(IpsetNamePrefix + shortName(nsName+":"+"ipblock-except:"+spec.key))
}
return spec
}
func (spec *ipBlockSpec) getRuleSpec(src bool) ([]string, string) {
dir, dirOpt := "dst", "-d"
if src {
dir, dirOpt = "src", "-s"
}
if spec.key == "" {
rule := []string{dirOpt, spec.ipBlock.CIDR}
comment := fmt.Sprintf("cidr: %s", spec.ipBlock.CIDR)
return rule, comment
}
rule := []string{dirOpt, spec.ipBlock.CIDR,
"-m", "set", "!", "--match-set", string(spec.ipsetName), dir}
comment := fmt.Sprintf("cidr: %s except [%s]", spec.ipBlock.CIDR, spec.key)
return rule, comment
}
type ipBlockSet struct {
ips ipset.Interface
users map[string]map[types.UID]struct{}
}
func newIPBlockSet(ips ipset.Interface) *ipBlockSet {
return &ipBlockSet{
ips: ips,
users: make(map[string]map[types.UID]struct{}),
}
}
func (s *ipBlockSet) deprovision(user types.UID, current, desired map[string]*ipBlockSpec) error {
for key, spec := range current {
if key == "" {
continue
}
if _, found := desired[key]; !found {
delete(s.users[key], user)
if len(s.users[key]) == 0 {
common.Log.Infof("destroying ipset: %#v", spec)
if err := s.ips.Destroy(spec.ipsetName); err != nil {
return err
}
delete(s.users, key)
}
}
}
return nil
}
func (s *ipBlockSet) provision(user types.UID, current, desired map[string]*ipBlockSpec) (err error) {
for key, spec := range desired {
if key == "" {
// No need to provision an ipBlock with empty list of excepted CIDRs
// (i.e. no ipset is needed for the related iptables rule).
continue
}
if _, found := current[key]; !found {
if _, found := s.users[key]; !found {
common.Log.Infof("creating ipset: %#v", spec)
if err := s.ips.Create(spec.ipsetName, ipset.HashNet); err != nil {
return err
}
// TODO(brb) Pass comment to ips.Create instead.
comment := "excepted from " + spec.ipBlock.CIDR
for _, cidr := range spec.ipBlock.Except {
if err = s.ips.AddEntry(user, spec.ipsetName, cidr, comment); err != nil {
return err
}
}
s.users[key] = make(map[types.UID]struct{})
}
s.users[key][user] = struct{}{}
}
}
return nil
}
-163
View File
@@ -1,163 +0,0 @@
package ipset
import (
"log"
"os/exec"
"strings"
"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, comment string) error
DelEntry(ipsetName Name, entry string) error
Flush(ipsetName Name) error
Destroy(ipsetName Name) error
List(prefix string) ([]Name, error)
FlushAll() error
DestroyAll() error
}
type ipset struct {
refCount
*log.Logger
enableComments bool
}
func New(logger *log.Logger) Interface {
ips := &ipset{refCount: newRefCount(), Logger: logger, enableComments: true}
// Check for comment support
testIpsetName := Name("weave-test-comment")
// Clear it out if it already exists
_ = ips.Destroy(testIpsetName)
// Test for comment support
if err := ips.Create(testIpsetName, HashIP); err != nil {
ips.Logger.Printf("failed to create %s; disabling comment support", testIpsetName)
ips.enableComments = false
}
// If it was created, destroy it
_ = ips.Destroy(testIpsetName)
return ips
}
func (i *ipset) Create(ipsetName Name, ipsetType Type) error {
args := []string{"create", string(ipsetName), string(ipsetType)}
if i.enableComments {
args = append(args, "comment")
}
return doExec(args...)
}
func (i *ipset) AddEntry(ipsetName Name, entry string, comment string) error {
i.Logger.Printf("adding entry %s to %s", entry, ipsetName)
if i.inc(ipsetName, entry) > 1 { // already in the set
return nil
}
args := []string{"add", string(ipsetName), entry}
if i.enableComments {
args = append(args, "comment", comment)
}
return doExec(args...)
}
func (i *ipset) DelEntry(ipsetName Name, entry string) error {
i.Logger.Printf("deleting entry %s from %s", entry, ipsetName)
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")
}
// Fetch a list of all existing sets with a given prefix
func (i *ipset) List(prefix string) ([]Name, error) {
output, err := exec.Command("ipset", "list", "-name", "-output", "plain").Output()
if err != nil {
return nil, err
}
var selected []Name
sets := strings.Split(string(output), "\n")
for _, v := range sets {
if strings.HasPrefix(v, prefix) {
selected = append(selected, Name(v))
}
}
return selected, err
}
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)
}
}
}
+49
View File
@@ -4,7 +4,56 @@ import (
"encoding/json"
)
// Return JSON suitable for logging an API object.
func js(v interface{}) string {
// Get the raw JSON
a, _ := json.Marshal(v)
// Convert this back into a tree of key-value maps
var m map[string]interface{}
if err := json.Unmarshal(a, &m); err != nil {
// If that didn't work, just return the raw version
return string(a)
}
// Trim some bulk, and potentially sensitive areas
withMap(m["metadata"], func(status map[string]interface{}) {
delete(status, "ownerReferences")
})
withMap(m["spec"], func(spec map[string]interface{}) {
delete(spec, "tolerations")
delete(spec, "volumes")
rangeSlice(spec["containers"], func(container map[string]interface{}) {
delete(container, "args")
delete(container, "command")
delete(container, "env")
delete(container, "livenessProbe")
delete(container, "resources")
delete(container, "securityContext")
delete(container, "volumeMounts")
})
})
withMap(m["status"], func(status map[string]interface{}) {
delete(status, "containerStatuses")
})
// Now marshall what's left to JSON
a, _ = json.Marshal(m)
return string(a)
}
// Helper function: operate on a map node from a tree of key-value maps
func withMap(m interface{}, f func(map[string]interface{})) {
if v, ok := m.(map[string]interface{}); ok {
f(v)
}
}
// Helper function: operate on all nodes under i which is a slice in a
// tree of key-value maps
func rangeSlice(i interface{}, f func(map[string]interface{})) {
if s, ok := i.([]interface{}); ok {
for _, v := range s {
if m, ok := v.(map[string]interface{}); ok {
f(m)
}
}
}
}
+332 -110
View File
@@ -1,40 +1,50 @@
package npc
import (
"encoding/json"
"errors"
"fmt"
"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"
coreapi "k8s.io/api/core/v1"
extnapi "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/uuid"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/ipset"
"github.com/weaveworks/weave/net/ipset"
"github.com/weaveworks/weave/npc/iptables"
)
var errInvalidNetworkPolicyObjType = errors.New("invalid NetworkPolicy object type")
type ns struct {
ipt iptables.Interface // interface to iptables
ips ipset.Interface // interface to ipset
name string // k8s Namespace name
nodeName string // my node 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
name string // k8s Namespace name
nodeName string // my node name
namespace *coreapi.Namespace // k8s Namespace object
pods map[types.UID]*coreapi.Pod // k8s Pod objects by UID
policies map[types.UID]interface{} // 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
// stores IP addrs of pods which are not selected by any target podSelector of
// any netpol; used as a target in the WEAVE-NPC-{INGRESS,EGRESS}-DEFAULT
// iptables chains.
ingressDefaultAllowIPSet ipset.Name
egressDefaultAllowIPSet ipset.Name
nsSelectors *selectorSet
podSelectors *selectorSet
ipBlocks *ipBlockSet
rules *ruleSet
}
func newNS(name, nodeName string, ipt iptables.Interface, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
allPods, err := newSelectorSpec(&unversioned.LabelSelector{}, name, ipset.HashIP)
allPods, err := newSelectorSpec(&metav1.LabelSelector{}, nil, name, ipset.HashIP)
if err != nil {
return nil, err
}
@@ -45,13 +55,27 @@ func newNS(name, nodeName string, ipt iptables.Interface, ips ipset.Interface, n
name: name,
nodeName: nodeName,
pods: make(map[types.UID]*coreapi.Pod),
policies: make(map[types.UID]*extnapi.NetworkPolicy),
policies: make(map[types.UID]interface{}),
uid: uuid.NewUUID(),
allPods: allPods,
nsSelectors: nsSelectors,
rules: newRuleSet(ipt)}
ipBlocks: newIPBlockSet(ips),
rules: newRuleSet(ipt),
}
ns.podSelectors = newSelectorSet(ips, ns.onNewPodSelector)
ns.podSelectors = newSelectorSet(ips, ns.onNewPodSelector, ns.onNewTargetPodSelector, ns.onDestroyTargetPodSelector)
ingressDefaultAllowIPSet := ipset.Name(IpsetNamePrefix + shortName("ingress-default-allow:"+name))
if err := ips.Create(ingressDefaultAllowIPSet, ipset.HashIP); err != nil {
return nil, err
}
ns.ingressDefaultAllowIPSet = ingressDefaultAllowIPSet
egressDefaultAllowIPSet := ipset.Name(IpsetNamePrefix + shortName("egress-default-allow:"+name))
if err := ips.Create(egressDefaultAllowIPSet, ipset.HashIP); err != nil {
return nil, err
}
ns.egressDefaultAllowIPSet = egressDefaultAllowIPSet
if err := ns.podSelectors.provision(ns.uid, nil, map[string]*selectorSpec{ns.allPods.key: ns.allPods}); err != nil {
return nil, err
@@ -72,12 +96,62 @@ 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, podComment(pod)); err != nil {
if err := selector.addEntry(pod.ObjectMeta.UID, pod.Status.PodIP, podComment(pod)); err != nil {
return err
}
}
}
}
return nil
}
func (ns *ns) onNewTargetPodSelector(selector *selector, policyType policyType) error {
for _, pod := range ns.pods {
if hasIP(pod) {
// Remove the pod from default-allow if dst podselector matches the pod
ipset := ns.defaultAllowIPSetName(policyType)
if selector.matches(pod.ObjectMeta.Labels) {
if err := ns.ips.DelEntry(pod.ObjectMeta.UID, ipset, pod.Status.PodIP); err != nil {
return err
}
}
}
}
return nil
}
func (ns *ns) onDestroyTargetPodSelector(selector *selector, policyType policyType) error {
for _, pod := range ns.pods {
if hasIP(pod) {
if selector.matches(pod.ObjectMeta.Labels) {
if err := ns.addToDefaultAllowIfNoMatching(pod, policyType); err != nil {
return err
}
}
}
}
return nil
}
// Add pod IP addr to default-allow ipset if there are no matching target selectors
func (ns *ns) addToDefaultAllowIfNoMatching(pod *coreapi.Pod, policyType policyType) error {
found := false
// TODO(mp) optimize (avoid iterating over selectors) by ref counting IP addrs.
for _, s := range ns.podSelectors.entries {
if ns.podSelectors.targetSelectorExist(s, policyType) && s.matches(pod.ObjectMeta.Labels) {
found = true
break
}
}
if !found {
ipset := ns.defaultAllowIPSetName(policyType)
if err := ns.ips.AddEntry(pod.ObjectMeta.UID, ipset, pod.Status.PodIP, podComment(pod)); err != nil {
return err
}
}
return nil
}
@@ -96,9 +170,26 @@ func (ns *ns) addPod(obj *coreapi.Pod) error {
}
if ns.checkLocalPod(obj) {
ns.ips.AddEntry(LocalIpset, obj.Status.PodIP, podComment(obj))
ns.ips.AddEntry(obj.ObjectMeta.UID, LocalIpset, obj.Status.PodIP, podComment(obj))
}
return ns.podSelectors.addToMatching(obj.ObjectMeta.Labels, obj.Status.PodIP, podComment(obj))
foundIngress, foundEgress, err := ns.podSelectors.addToMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, obj.Status.PodIP, podComment(obj))
if err != nil {
return err
}
// If there are no matching target selectors, add the pod to default-allow
if !foundIngress {
if err := ns.ips.AddEntry(obj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, obj.Status.PodIP, podComment(obj)); err != nil {
return err
}
}
if !foundEgress {
if err := ns.ips.AddEntry(obj.ObjectMeta.UID, ns.egressDefaultAllowIPSet, obj.Status.PodIP, podComment(obj)); err != nil {
return err
}
}
return nil
}
func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
@@ -111,16 +202,49 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
if hasIP(oldObj) && !hasIP(newObj) {
if ns.checkLocalPod(oldObj) {
ns.ips.DelEntry(LocalIpset, oldObj.Status.PodIP)
ns.ips.DelEntry(oldObj.ObjectMeta.UID, LocalIpset, oldObj.Status.PodIP)
}
return ns.podSelectors.delFromMatching(oldObj.ObjectMeta.Labels, oldObj.Status.PodIP)
if err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, oldObj.Status.PodIP); err != nil {
return err
}
if err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ns.egressDefaultAllowIPSet, oldObj.Status.PodIP); err != nil {
return err
}
return ns.podSelectors.delFromMatching(oldObj.ObjectMeta.UID, oldObj.ObjectMeta.Labels, oldObj.Status.PodIP)
}
if !hasIP(oldObj) && hasIP(newObj) {
if ns.checkLocalPod(newObj) {
ns.ips.AddEntry(LocalIpset, newObj.Status.PodIP, podComment(newObj))
ns.ips.AddEntry(newObj.ObjectMeta.UID, LocalIpset, newObj.Status.PodIP, podComment(newObj))
}
foundIngress, foundEgress, err := ns.podSelectors.addToMatching(newObj.ObjectMeta.UID, newObj.ObjectMeta.Labels, newObj.Status.PodIP, podComment(newObj))
if err != nil {
return err
}
if !foundIngress {
if err := ns.ips.AddEntry(newObj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
return err
}
}
if !foundEgress {
if err := ns.ips.AddEntry(newObj.ObjectMeta.UID, ns.egressDefaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
return err
}
}
return nil
}
if oldObj.Status.PodIP != newObj.Status.PodIP {
if err := ns.updateDefaultAllowIPSetEntry(oldObj, newObj, ns.ingressDefaultAllowIPSet); err != nil {
return err
}
if err := ns.updateDefaultAllowIPSetEntry(oldObj, newObj, ns.egressDefaultAllowIPSet); err != nil {
return err
}
return ns.podSelectors.addToMatching(newObj.ObjectMeta.Labels, newObj.Status.PodIP, podComment(newObj))
}
if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) ||
@@ -133,21 +257,45 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
continue
}
if oldMatch {
if err := ps.delEntry(oldObj.Status.PodIP); err != nil {
if err := ps.delEntry(oldObj.ObjectMeta.UID, oldObj.Status.PodIP); err != nil {
return err
}
}
if newMatch {
if err := ps.addEntry(newObj.Status.PodIP, podComment(newObj)); err != nil {
if err := ps.addEntry(newObj.ObjectMeta.UID, newObj.Status.PodIP, podComment(newObj)); err != nil {
return err
}
}
if err := ns.addOrRemoveToDefaultAllowIPSet(ps, oldObj, newObj, oldMatch, newMatch, policyTypeIngress); err != nil {
return err
}
if err := ns.addOrRemoveToDefaultAllowIPSet(ps, oldObj, newObj, oldMatch, newMatch, policyTypeEgress); err != nil {
return err
}
}
}
return nil
}
func (ns *ns) addOrRemoveToDefaultAllowIPSet(ps *selector, oldObj, newObj *coreapi.Pod, oldMatch, newMatch bool, policyType policyType) error {
ipset := ns.defaultAllowIPSetName(policyType)
if ns.podSelectors.targetSelectorExist(ps, policyType) {
switch {
case !oldMatch && newMatch:
if err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ipset, oldObj.Status.PodIP); err != nil {
return err
}
case oldMatch && !newMatch:
if err := ns.addToDefaultAllowIfNoMatching(newObj, policyType); err != nil {
return err
}
}
}
return nil
}
func (ns *ns) deletePod(obj *coreapi.Pod) error {
delete(ns.pods, obj.ObjectMeta.UID)
@@ -156,131 +304,178 @@ func (ns *ns) deletePod(obj *coreapi.Pod) error {
}
if ns.checkLocalPod(obj) {
ns.ips.DelEntry(LocalIpset, obj.Status.PodIP)
ns.ips.DelEntry(obj.ObjectMeta.UID, LocalIpset, obj.Status.PodIP)
}
return ns.podSelectors.delFromMatching(obj.ObjectMeta.Labels, obj.Status.PodIP)
if err := ns.ips.DelEntry(obj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, obj.Status.PodIP); err != nil {
return err
}
if err := ns.ips.DelEntry(obj.ObjectMeta.UID, ns.egressDefaultAllowIPSet, obj.Status.PodIP); err != nil {
return err
}
return ns.podSelectors.delFromMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, obj.Status.PodIP)
}
func (ns *ns) addNetworkPolicy(obj *extnapi.NetworkPolicy) error {
ns.policies[obj.ObjectMeta.UID] = obj
func (ns *ns) addNetworkPolicy(obj interface{}) error {
// Analyse policy, determine which rules and ipsets are required
rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
uid, rules, nsSelectors, podSelectors, ipBlocks, err := ns.analyse(obj)
if err != nil {
return err
}
// Provision required resources in dependency order
if err := ns.nsSelectors.provision(obj.ObjectMeta.UID, nil, nsSelectors); err != nil {
if err := ns.nsSelectors.provision(uid, nil, nsSelectors); err != nil {
return err
}
if err := ns.podSelectors.provision(obj.ObjectMeta.UID, nil, podSelectors); err != nil {
if err := ns.podSelectors.provision(uid, nil, podSelectors); err != nil {
return err
}
return ns.rules.provision(obj.ObjectMeta.UID, nil, rules)
if err := ns.ipBlocks.provision(uid, nil, ipBlocks); err != nil {
return err
}
return ns.rules.provision(uid, nil, rules)
}
func (ns *ns) updateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error {
delete(ns.policies, oldObj.ObjectMeta.UID)
ns.policies[newObj.ObjectMeta.UID] = newObj
func (ns *ns) updateNetworkPolicy(oldObj, newObj interface{}) error {
// Analyse the old and the new policy so we can determine differences
oldRules, oldNsSelectors, oldPodSelectors, err := ns.analysePolicy(oldObj)
oldUID, oldRules, oldNsSelectors, oldPodSelectors, oldIPBlocks, err := ns.analyse(oldObj)
if err != nil {
return err
}
newRules, newNsSelectors, newPodSelectors, err := ns.analysePolicy(newObj)
newUID, newRules, newNsSelectors, newPodSelectors, newIPBlocks, err := ns.analyse(newObj)
if err != nil {
return err
}
delete(ns.policies, oldUID)
ns.policies[newUID] = newObj
// Deprovision unused and provision newly required resources in dependency order
if err := ns.rules.deprovision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
if err := ns.rules.deprovision(oldUID, oldRules, newRules); err != nil {
return err
}
if err := ns.nsSelectors.deprovision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
if err := ns.nsSelectors.deprovision(oldUID, oldNsSelectors, newNsSelectors); err != nil {
return err
}
if err := ns.podSelectors.deprovision(oldObj.ObjectMeta.UID, oldPodSelectors, newPodSelectors); err != nil {
if err := ns.podSelectors.deprovision(oldUID, oldPodSelectors, newPodSelectors); err != nil {
return err
}
if err := ns.nsSelectors.provision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
if err := ns.ipBlocks.deprovision(oldUID, oldIPBlocks, newIPBlocks); err != nil {
return err
}
if err := ns.podSelectors.provision(oldObj.ObjectMeta.UID, oldPodSelectors, newPodSelectors); err != nil {
if err := ns.nsSelectors.provision(oldUID, oldNsSelectors, newNsSelectors); err != nil {
return err
}
return ns.rules.provision(oldObj.ObjectMeta.UID, oldRules, newRules)
if err := ns.podSelectors.provision(oldUID, oldPodSelectors, newPodSelectors); err != nil {
return err
}
if err := ns.ipBlocks.provision(oldUID, oldIPBlocks, newIPBlocks); err != nil {
return err
}
return ns.rules.provision(oldUID, oldRules, newRules)
}
func (ns *ns) deleteNetworkPolicy(obj *extnapi.NetworkPolicy) error {
delete(ns.policies, obj.ObjectMeta.UID)
func (ns *ns) deleteNetworkPolicy(obj interface{}) error {
// Analyse network policy to free resources
rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
uid, rules, nsSelectors, podSelectors, ipBlocks, err := ns.analyse(obj)
if err != nil {
return err
}
delete(ns.policies, uid)
// Deprovision unused resources in dependency order
if err := ns.rules.deprovision(obj.ObjectMeta.UID, rules, nil); err != nil {
if err := ns.rules.deprovision(uid, rules, nil); err != nil {
return err
}
if err := ns.nsSelectors.deprovision(obj.ObjectMeta.UID, nsSelectors, nil); err != nil {
if err := ns.nsSelectors.deprovision(uid, nsSelectors, nil); err != nil {
return err
}
return ns.podSelectors.deprovision(obj.ObjectMeta.UID, podSelectors, nil)
if err := ns.podSelectors.deprovision(uid, podSelectors, nil); err != nil {
return err
}
if err := ns.ipBlocks.deprovision(uid, ipBlocks, nil); err != nil {
return err
}
return nil
}
func bypassRule(nsIpsetName ipset.Name, namespace string) []string {
return []string{"-m", "set", "--match-set", string(nsIpsetName), "dst", "-j", "ACCEPT", "-m", "comment", "--comment", "DefaultAllow isolation for namespace: " + namespace}
func (ns *ns) updateDefaultAllowIPSetEntry(oldObj, newObj *coreapi.Pod, ipsetName ipset.Name) error {
// Instead of iterating over all selectors we check whether old pod IP
// has been inserted into default-allow ipset to decide whether the IP
// in the ipset has to be updated.
if ns.ips.Exist(oldObj.ObjectMeta.UID, ipsetName, oldObj.Status.PodIP) {
if err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ipsetName, oldObj.Status.PodIP); err != nil {
return err
}
if err := ns.ips.AddEntry(newObj.ObjectMeta.UID, ipsetName, newObj.Status.PodIP, podComment(newObj)); err != nil {
return err
}
}
return nil
}
func (ns *ns) ensureBypassRule(nsIpsetName ipset.Name) error {
common.Log.Debugf("ensuring rule for DefaultAllow in namespace: %s, set %s", ns.name, nsIpsetName)
return ns.ipt.Append(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName, ns.name)...)
func bypassRules(namespace string, ingress, egress ipset.Name) map[string][][]string {
return map[string][][]string{
DefaultChain: {
{"-m", "set", "--match-set", string(ingress), "dst", "-j", "ACCEPT",
"-m", "comment", "--comment", "DefaultAllow ingress isolation for namespace: " + namespace},
},
EgressDefaultChain: {
{"-m", "set", "--match-set", string(egress), "src", "-j", EgressMarkChain,
"-m", "comment", "--comment", "DefaultAllow egress isolation for namespace: " + namespace},
{"-m", "set", "--match-set", string(egress), "src", "-j", "RETURN",
"-m", "comment", "--comment", "DefaultAllow egress isolation for namespace: " + namespace},
},
}
}
func (ns *ns) deleteBypassRule(nsIpsetName ipset.Name) error {
common.Log.Debugf("removing default rule in namespace: %s, set %s", ns.name, nsIpsetName)
return ns.ipt.Delete(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName, ns.name)...)
func (ns *ns) ensureBypassRules() error {
for chain, rules := range bypassRules(ns.name, ns.ingressDefaultAllowIPSet, ns.egressDefaultAllowIPSet) {
for _, rule := range rules {
common.Log.Debugf("adding rule for DefaultAllow in namespace: %s, chain: %s, %s", ns.name, chain, rule)
if err := ns.ipt.Append(TableFilter, chain, rule...); err != nil {
return err
}
}
}
return nil
}
func (ns *ns) deleteBypassRules() error {
for chain, rules := range bypassRules(ns.name, ns.ingressDefaultAllowIPSet, ns.egressDefaultAllowIPSet) {
for _, rule := range rules {
common.Log.Debugf("removing rule for DefaultAllow in namespace: %s, chain: %s, %s", ns.name, chain, rule)
if err := ns.ipt.Delete(TableFilter, chain, rule...); err != nil {
return err
}
}
}
return nil
}
func (ns *ns) addNamespace(obj *coreapi.Namespace) error {
ns.namespace = obj
// Insert a rule to bypass policies if namespace is DefaultAllow
if !isDefaultDeny(obj) {
if err := ns.ensureBypassRule(ns.allPods.ipsetName); err != nil {
return err
}
// Insert a rule to bypass policies
if err := ns.ensureBypassRules(); err != nil {
return err
}
// Add namespace ipset to matching namespace selectors
return ns.nsSelectors.addToMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName), namespaceComment(ns))
_, _, err := ns.nsSelectors.addToMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, string(ns.allPods.ipsetName), namespaceComment(ns))
return err
}
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 {
common.Log.Infof("namespace DefaultDeny changed from %t to %t", oldDefaultDeny, newDefaultDeny)
if oldDefaultDeny {
if err := ns.ensureBypassRule(ns.allPods.ipsetName); err != nil {
return err
}
}
if newDefaultDeny {
if err := ns.deleteBypassRule(ns.allPods.ipsetName); err != nil {
return err
}
}
}
// Re-evaluate namespace selector membership if labels have changed
if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) {
for _, selector := range ns.nsSelectors.entries {
@@ -290,12 +485,12 @@ func (ns *ns) updateNamespace(oldObj, newObj *coreapi.Namespace) error {
continue
}
if oldMatch {
if err := selector.delEntry(string(ns.allPods.ipsetName)); err != nil {
if err := selector.delEntry(ns.namespace.ObjectMeta.UID, string(ns.allPods.ipsetName)); err != nil {
return err
}
}
if newMatch {
if err := selector.addEntry(string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
if err := selector.addEntry(ns.namespace.ObjectMeta.UID, string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
return err
}
}
@@ -309,14 +504,24 @@ func (ns *ns) deleteNamespace(obj *coreapi.Namespace) error {
ns.namespace = nil
// Remove bypass rule
if !isDefaultDeny(obj) {
if err := ns.deleteBypassRule(ns.allPods.ipsetName); err != nil {
return err
}
if err := ns.deleteBypassRules(); err != nil {
return err
}
// Remove namespace ipset from any matching namespace selectors
return ns.nsSelectors.delFromMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
err := ns.nsSelectors.delFromMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
if err != nil {
return err
}
if err := ns.ips.Destroy(ns.ingressDefaultAllowIPSet); err != nil {
return err
}
if err := ns.ips.Destroy(ns.egressDefaultAllowIPSet); err != nil {
return err
}
return nil
}
func hasIP(pod *coreapi.Pod) bool {
@@ -337,24 +542,6 @@ func equals(a, b map[string]string) bool {
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
}
func namespaceComment(namespace *ns) string {
return "namespace: " + namespace.name
}
@@ -362,3 +549,38 @@ func namespaceComment(namespace *ns) string {
func podComment(pod *coreapi.Pod) string {
return fmt.Sprintf("namespace: %s, pod: %s", pod.ObjectMeta.Namespace, pod.ObjectMeta.Name)
}
func (ns *ns) defaultAllowIPSetName(pt policyType) ipset.Name {
ipset := ns.ingressDefaultAllowIPSet
if pt == policyTypeEgress {
ipset = ns.egressDefaultAllowIPSet
}
return ipset
}
func (ns *ns) analyse(obj interface{}) (
uid types.UID,
rules map[string]*ruleSpec,
nsSelectors, podSelectors map[string]*selectorSpec,
ipBlocks map[string]*ipBlockSpec,
err error) {
switch p := obj.(type) {
case *extnapi.NetworkPolicy:
uid = p.ObjectMeta.UID
case *networkingv1.NetworkPolicy:
uid = p.ObjectMeta.UID
default:
err = errInvalidNetworkPolicyObjType
return
}
ns.policies[uid] = obj
// Analyse policy, determine which rules and ipsets are required
rules, nsSelectors, podSelectors, ipBlocks, err = ns.analysePolicy(obj.(*networkingv1.NetworkPolicy))
if err != nil {
return
}
return
}
+65 -24
View File
@@ -2,46 +2,80 @@ package npc
import (
"fmt"
"reflect"
"strings"
"k8s.io/client-go/pkg/types"
"k8s.io/apimachinery/pkg/types"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/iptables"
)
type ruleSpec struct {
key string
args []string
type ruleHost interface {
// getRuleSpec returns source or destination specification and comment which
// are used in an iptables rule.
//
// If src=true then the rulespec is for source, otherwise - for destination.
getRuleSpec(src bool) ([]string, string)
}
func newRuleSpec(proto *string, srcHost *selectorSpec, dstHost *selectorSpec, dstPort *string) *ruleSpec {
type ruleSpec struct {
key string
args []string
policyType policyType
}
func newRuleSpec(policyType policyType, proto *string, srcHost, dstHost ruleHost, dstPort *string) *ruleSpec {
args := []string{}
if proto != nil {
args = append(args, "-p", *proto)
}
srcComment := "anywhere"
if srcHost != nil {
args = append(args, "-m", "set", "--match-set", string(srcHost.ipsetName), "src")
if srcHost.nsName != "" {
srcComment = fmt.Sprintf("pods: namespace: %s, selector: %s", srcHost.nsName, srcHost.key)
} else {
srcComment = fmt.Sprintf("namespaces: selector: %s", srcHost.key)
}
if srcHost != nil && !reflect.ValueOf(srcHost).IsNil() {
rule, comment := srcHost.getRuleSpec(true)
args = append(args, rule...)
srcComment = comment
}
dstComment := "anywhere"
if dstHost != nil {
args = append(args, "-m", "set", "--match-set", string(dstHost.ipsetName), "dst")
dstComment = fmt.Sprintf("pods: namespace: %s, selector: %s", dstHost.nsName, dstHost.key)
if dstHost != nil && !reflect.ValueOf(dstHost).IsNil() {
rule, comment := dstHost.getRuleSpec(false)
args = append(args, rule...)
dstComment = comment
}
if dstPort != nil {
args = append(args, "--dport", *dstPort)
}
args = append(args, "-j", "ACCEPT")
args = append(args, "-m", "comment", "--comment", fmt.Sprintf("%s -> %s", srcComment, dstComment))
// NOTE: if you remove the comment bellow, then embed `policyType` into `key`.
// Otherwise, the rule won't be provisioned if it exists for other policy type.
args = append(args, "-m", "comment", "--comment", fmt.Sprintf("%s -> %s (%s)", srcComment, dstComment, policyTypeStr(policyType)))
key := strings.Join(args, " ")
return &ruleSpec{key, args}
return &ruleSpec{key, args, policyType}
}
func (spec *ruleSpec) iptChain() string {
if spec.policyType == policyTypeEgress {
return EgressCustomChain
}
return IngressChain
}
func (spec *ruleSpec) iptRuleSpecs() [][]string {
if spec.policyType == policyTypeIngress {
rule := make([]string, len(spec.args))
copy(rule, spec.args)
rule = append(rule, "-j", "ACCEPT")
return [][]string{rule}
}
// policyTypeEgress
ruleMark := make([]string, len(spec.args))
copy(ruleMark, spec.args)
ruleMark = append(ruleMark, "-j", EgressMarkChain)
ruleReturn := make([]string, len(spec.args))
copy(ruleReturn, spec.args)
ruleReturn = append(ruleReturn, "-j", "RETURN")
return [][]string{ruleMark, ruleReturn}
}
type ruleSet struct {
@@ -58,10 +92,14 @@ func (rs *ruleSet) deprovision(user types.UID, current, desired map[string]*rule
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
chain := spec.iptChain()
for _, rule := range spec.iptRuleSpecs() {
common.Log.Infof("deleting rule %v from %q chain", rule, chain)
if err := rs.ipt.Delete(TableFilter, chain, rule...); err != nil {
return err
}
}
delete(rs.users, key)
}
}
@@ -74,9 +112,12 @@ func (rs *ruleSet) provision(user types.UID, current, desired map[string]*ruleSp
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
chain := spec.iptChain()
for _, rule := range spec.iptRuleSpecs() {
common.Log.Infof("adding rule %v to %q chain", rule, chain)
if err := rs.ipt.Append(TableFilter, chain, rule...); err != nil {
return err
}
}
rs.users[key] = make(map[types.UID]struct{})
}
+1 -1
View File
@@ -9,7 +9,7 @@ func TestRegressionHandleNil3095(t *testing.T) {
// Test for handling nil values
// https://github.com/weaveworks/weave/issues/3095
rs := newRuleSpec(nil, nil, nil, nil)
rs := newRuleSpec(policyTypeIngress, nil, nil, nil, nil)
require.NotEqual(t, rs.key, "")
+105 -33
View File
@@ -1,32 +1,36 @@
package npc
import (
"k8s.io/client-go/pkg/api/unversioned"
"k8s.io/client-go/pkg/labels"
"k8s.io/client-go/pkg/types"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/ipset"
"github.com/weaveworks/weave/net/ipset"
)
type selectorSpec struct {
key string // string representation (for hash keying/equality comparison)
selector labels.Selector // k8s Selector object (for matching)
key string // string representation (for hash keying/equality comparison)
selector labels.Selector // k8s Selector object (for matching)
policyTypes []policyType // If non-empty, then selectorSpec is a target selector for given policyTypes.
ipsetType ipset.Type // type of ipset to provision
ipsetName ipset.Name // generated ipset name
nsName string // Namespace name
}
func newSelectorSpec(json *unversioned.LabelSelector, nsName string, ipsetType ipset.Type) (*selectorSpec, error) {
selector, err := unversioned.LabelSelectorAsSelector(json)
func newSelectorSpec(json *metav1.LabelSelector, policyType []policyType, nsName string, ipsetType ipset.Type) (*selectorSpec, error) {
selector, err := metav1.LabelSelectorAsSelector(json)
if err != nil {
return nil, err
}
key := selector.String()
return &selectorSpec{
key: key,
selector: selector,
key: key,
selector: selector,
policyTypes: policyType,
// 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
@@ -35,6 +39,23 @@ func newSelectorSpec(json *unversioned.LabelSelector, nsName string, ipsetType i
nsName: nsName}, nil
}
func (spec *selectorSpec) getRuleSpec(src bool) ([]string, string) {
dir := "dst"
if src {
dir = "src"
}
rule := []string{"-m", "set", "--match-set", string(spec.ipsetName), dir}
comment := "anywhere"
if spec.nsName != "" {
comment = fmt.Sprintf("pods: namespace: %s, selector: %s", spec.nsName, spec.key)
} else {
comment = fmt.Sprintf("namespaces: selector: %s", spec.key)
}
return rule, comment
}
type selector struct {
ips ipset.Interface
spec *selectorSpec
@@ -44,35 +65,69 @@ func (s *selector) matches(labelMap map[string]string) bool {
return s.spec.selector.Matches(labels.Set(labelMap))
}
func (s *selector) addEntry(entry string, comment string) error {
return s.ips.AddEntry(s.spec.ipsetName, entry, comment)
func (s *selector) addEntry(user types.UID, entry string, comment string) error {
return s.ips.AddEntry(user, s.spec.ipsetName, entry, comment)
}
func (s *selector) delEntry(entry string) error {
return s.ips.DelEntry(s.spec.ipsetName, entry)
func (s *selector) delEntry(user types.UID, entry string) error {
return s.ips.DelEntry(user, s.spec.ipsetName, entry)
}
type selectorFn func(selector *selector) error
type selectorWithPolicyTypeFn func(selector *selector, policyType policyType) 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
// invoked after target selector has been provisioned for the first time
onNewTargetSelector selectorWithPolicyTypeFn
// invoked after the last instance of target selector has been deprovisioned
onDestroyTargetSelector selectorWithPolicyTypeFn
users map[string]map[types.UID]struct{} // list of users per selector
entries map[string]*selector
// We need to keep track of target selector instances to be able to invoke
// onNewTargetSelector and onDestroyTargetSelector callbacks at the right time;
// selectorSpec.Key -> policyType -> count
targetSelectorsCount map[string]map[policyType]int
}
func newSelectorSet(ips ipset.Interface, onNewSelector selectorFn) *selectorSet {
func newSelectorSet(ips ipset.Interface, onNewSelector selectorFn, onNewTargetSelector, onDestroyTargetSelector selectorWithPolicyTypeFn) *selectorSet {
return &selectorSet{
ips: ips,
onNewSelector: onNewSelector,
users: make(map[string]map[types.UID]struct{}),
entries: make(map[string]*selector)}
ips: ips,
onNewSelector: onNewSelector,
onNewTargetSelector: onNewTargetSelector,
onDestroyTargetSelector: onDestroyTargetSelector,
users: make(map[string]map[types.UID]struct{}),
entries: make(map[string]*selector),
targetSelectorsCount: make(map[string]map[policyType]int)}
}
func (ss *selectorSet) addToMatching(labelMap map[string]string, entry string, comment string) error {
func (ss *selectorSet) addToMatching(user types.UID, labelMap map[string]string, entry string, comment string) (bool, bool, error) {
foundIngress := false
foundEgress := false
for _, s := range ss.entries {
if s.matches(labelMap) {
if err := s.addEntry(entry, comment); err != nil {
if ss.targetSelectorExist(s, policyTypeIngress) {
foundIngress = true
}
if ss.targetSelectorExist(s, policyTypeEgress) {
foundEgress = true
}
if err := s.addEntry(user, entry, comment); err != nil {
return foundIngress, foundEgress, err
}
}
}
return foundIngress, foundEgress, nil
}
func (ss *selectorSet) delFromMatching(user types.UID, labelMap map[string]string, entry string) error {
for _, s := range ss.entries {
if s.matches(labelMap) {
if err := s.delEntry(user, entry); err != nil {
return err
}
}
@@ -80,15 +135,8 @@ func (ss *selectorSet) addToMatching(labelMap map[string]string, entry string, c
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) targetSelectorExist(s *selector, policyType policyType) bool {
return ss.targetSelectorsCount[s.spec.key][policyType] > 0
}
func (ss *selectorSet) deprovision(user types.UID, current, desired map[string]*selectorSpec) error {
@@ -100,9 +148,20 @@ func (ss *selectorSet) deprovision(user types.UID, current, desired map[string]*
if err := ss.ips.Destroy(spec.ipsetName); err != nil {
return err
}
delete(ss.entries, key)
delete(ss.users, key)
}
for _, policyType := range spec.policyTypes {
ss.targetSelectorsCount[key][policyType]--
if ss.targetSelectorsCount[key][policyType] == 0 {
if err := ss.onDestroyTargetSelector(&selector{ss.ips, spec}, policyType); err != nil {
return err
}
}
// TODO(brb) delete(...)
}
}
}
return nil
@@ -111,12 +170,13 @@ func (ss *selectorSet) deprovision(user types.UID, current, desired map[string]*
func (ss *selectorSet) provision(user types.UID, current, desired map[string]*selectorSpec) error {
for key, spec := range desired {
if _, found := current[key]; !found {
selector := &selector{ss.ips, spec}
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
}
@@ -124,6 +184,18 @@ func (ss *selectorSet) provision(user types.UID, current, desired map[string]*se
ss.entries[key] = selector
}
ss.users[key][user] = struct{}{}
for _, pt := range spec.policyTypes {
if _, found := ss.targetSelectorsCount[key]; !found {
ss.targetSelectorsCount[key] = make(map[policyType]int)
}
ss.targetSelectorsCount[key][pt]++
if ss.targetSelectorsCount[key][pt] == 1 {
if err := ss.onNewTargetSelector(selector, pt); err != nil {
return err
}
}
}
}
}
return nil
+15
View File
@@ -0,0 +1,15 @@
package npc
type policyType byte
const (
policyTypeIngress policyType = iota
policyTypeEgress
)
func policyTypeStr(policyType policyType) string {
if policyType == policyTypeEgress {
return "egress"
}
return "ingress"
}
+4
View File
@@ -110,6 +110,10 @@ func (i *Ipam) ReleaseAddress(poolID string, address net.IP) error {
return i.weave.ReleaseIPsFor(address.String())
}
func (i *Ipam) IsBuiltIn() bool {
return false
}
// Functions required by ipamapi "contract" but not actually used.
func (i *Ipam) DiscoverNew(discoverapi.DiscoveryType, interface{}) error {
+25 -25
View File
@@ -6,7 +6,6 @@ import (
"fmt"
"net"
"os"
"syscall"
"github.com/containernetworking/cni/pkg/ipam"
"github.com/containernetworking/cni/pkg/skel"
@@ -100,12 +99,11 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
return fmt.Errorf("unable to allocate IP address for bridge: %s", err)
}
bridgeCIDR := bridgeIPResult.IPs[0].Address
if err := assignBridgeIP(conf.BrName, bridgeCIDR); err != nil {
return fmt.Errorf("unable to assign IP address to bridge: %s", err)
}
if err := weavenet.ExposeNAT(bridgeCIDR); err != nil {
return fmt.Errorf("unable to create NAT rules: %s", err)
if err := c.weave.Expose(&bridgeCIDR); err != nil {
return fmt.Errorf("unable to expose bridge %q: %s", conf.BrName, err)
}
bridgeIP = bridgeCIDR.IP
} else if err != nil {
return err
@@ -119,6 +117,16 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
}
defer ns.Close()
hostNs, err := netns.Get()
if err != nil {
return fmt.Errorf("error accessing host network namespace: %s", err)
}
defer hostNs.Close()
if ns.Equal(hostNs) {
return fmt.Errorf("can not specify host network namespace as network namespace to which container should be added")
}
id := args.ContainerID
if len(id) < 5 {
data := make([]byte, 5)
@@ -132,7 +140,7 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
if err := weavenet.AttachContainer(args.Netns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&ip.Address}, false, conf.HairpinMode); err != nil {
return err
}
if err := weavenet.WithNetNSLinkUnsafe(ns, args.IfName, func(link netlink.Link) error {
if err := weavenet.WithNetNSLink(ns, args.IfName, func(link netlink.Link) error {
return setupRoutes(link, args.IfName, ip.Address, ip.Gateway, result.Routes)
}); err != nil {
return fmt.Errorf("error setting up routes: %s", err)
@@ -167,22 +175,6 @@ func setupRoutes(link netlink.Link, name string, ipnet net.IPNet, gw net.IP, rou
return nil
}
func assignBridgeIP(bridgeName string, ipnet net.IPNet) error {
link, err := netlink.LinkByName(bridgeName)
if err != nil {
return err
}
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)
}
return nil
}
// As of CNI 0.5 spec:
// "Plugins should generally complete a DEL action without error even if some resources are missing"
// this method should therefore return nil in most, if not all, cases.
@@ -195,7 +187,13 @@ func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
// As of CNI 0.3 spec, runtimes can send blank if they just want the address deallocated
if args.Netns != "" {
if _, err = weavenet.WithNetNS(args.Netns, "del-iface", args.IfName); err != nil {
if err = weavenet.WithNetNSByPath(args.Netns, func() error {
link, err := netlink.LinkByName(args.IfName)
if err != nil {
return err
}
return netlink.LinkDel(link)
}); err != nil {
// We log the error and carry on instead of returning nil, as there may still be resources to free in IPAM.
logOnStderr(fmt.Errorf("error removing interface %q: %s", args.IfName, err))
}
@@ -207,7 +205,9 @@ func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
} else {
err = ipam.ExecDel(conf.IPAM.Type, args.StdinData)
}
logOnStderr(fmt.Errorf("unable to release IP address: %s", err))
if err != nil {
logOnStderr(fmt.Errorf("unable to release IP address: %s", err))
}
return nil
}
+1 -1
View File
@@ -134,7 +134,7 @@ func (driver *driver) CreateEndpoint(create *api.CreateEndpointRequest) (*api.Cr
// 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 {
if _, err := weavenet.CreateAndAttachVeth(name, peerName, weavenet.WeaveBridgeName, 0, false, true, nil); err != nil {
return nil, driver.error("JoinEndpoint", "%s", err)
}
+3 -5
View File
@@ -8,10 +8,6 @@ import (
weavenet "github.com/weaveworks/weave/net"
)
const (
WeaveDomain = "weave.local"
)
type watcher struct {
client *docker.Client
weave *weaveapi.Client
@@ -53,7 +49,9 @@ func (w *watcher) ContainerStarted(id string) {
rootDir = "/host"
}
netNSPath := weavenet.NSPathByPidWithRoot(rootDir, info.State.Pid)
if _, err := weavenet.WithNetNS(netNSPath, "configure-arp", weavenet.VethName, rootDir); err != nil {
if err := weavenet.WithNetNSByPath(netNSPath, func() error {
return weavenet.ConfigureARP(weavenet.VethName, rootDir)
}); err != nil {
w.driver.warn("ContainerStarted", "unable to configure interfaces: %s", err)
}
}
-60
View File
@@ -1,60 +0,0 @@
package main
import (
"fmt"
"log"
"net"
"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 {
return nil, err
}
addresses := make([]string, 0, len(nodeList.Items))
for _, peer := range nodeList.Items {
var internalIP, externalIP string
for _, addr := range peer.Status.Addresses {
// Check it's a valid ipv4 address
ip := net.ParseIP(addr.Address)
if ip == nil || ip.To4() == nil {
continue
}
if addr.Type == "InternalIP" {
internalIP = ip.To4().String()
} else if addr.Type == "ExternalIP" {
externalIP = ip.To4().String()
}
}
// Fallback for cases where a Node has an ExternalIP but no InternalIP
if internalIP != "" {
addresses = append(addresses, internalIP)
} else if externalIP != "" {
addresses = append(addresses, externalIP)
}
}
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)
}
}
+210
View File
@@ -0,0 +1,210 @@
/*
In order to keep track of active weave peers, we use annotations on the Kubernetes cluster.
Kubernetes uses etcd to distribute and synchronise these annotations so we don't have to.
This module deals with operations on the peerlist backed by Kubernetes' annotation mechanism.
*/
package main
import (
"encoding/json"
"log"
"time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
kubeErrors "k8s.io/apimachinery/pkg/api/errors"
api "k8s.io/apimachinery/pkg/apis/meta/v1"
wait "k8s.io/apimachinery/pkg/util/wait"
kubernetes "k8s.io/client-go/kubernetes"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
)
type configMapAnnotations struct {
ConfigMapName string
Namespace string
Client corev1client.ConfigMapsGetter
cm *v1.ConfigMap
}
func newConfigMapAnnotations(ns string, configMapName string, clientset *kubernetes.Clientset) *configMapAnnotations {
return &configMapAnnotations{
Namespace: ns,
ConfigMapName: configMapName,
Client: clientset.CoreV1(),
}
}
type peerList struct {
Peers []peerInfo
}
type peerInfo struct {
PeerName string // Weave internal unique ID
NodeName string // Kubernetes node name
}
func (pl peerList) contains(peerName string) bool {
for _, peer := range pl.Peers {
if peer.PeerName == peerName {
return true
}
}
return false
}
func (pl *peerList) add(peerName string, name string) {
pl.Peers = append(pl.Peers, peerInfo{PeerName: peerName, NodeName: name})
}
func (pl *peerList) remove(peerNameToRemove string) {
for i := 0; i < len(pl.Peers); {
if pl.Peers[i].PeerName == peerNameToRemove {
pl.Peers = append(pl.Peers[:i], pl.Peers[i+1:]...)
} else {
i++
}
}
}
const (
retryPeriod = time.Second * 2
jitterFactor = 1.0
// Prefix all our annotation keys with this string so they don't clash with anyone else's
KubePeersPrefix = "kube-peers.weave.works/"
// KubePeersAnnotationKey is the default annotation key
KubePeersAnnotationKey = KubePeersPrefix + "peers"
)
func (cml *configMapAnnotations) Init() error {
for {
// Since it's potentially racy to GET, then CREATE if not found, we wrap in a check loop
// so that if the configmap is created after our GET but before or CREATE, we'll gracefully
// re-try to get the configmap.
var err error
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Get(cml.ConfigMapName, api.GetOptions{})
if err != nil {
if !kubeErrors.IsNotFound(err) {
return errors.Wrapf(err, "Unable to fetch ConfigMap %s/%s", cml.Namespace, cml.ConfigMapName)
}
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Create(&v1.ConfigMap{
ObjectMeta: api.ObjectMeta{
Name: cml.ConfigMapName,
Namespace: cml.Namespace,
},
})
if err != nil {
if kubeErrors.IsAlreadyExists(err) {
continue
}
return errors.Wrapf(err, "Unable to create ConfigMap %s/%s", cml.Namespace, cml.ConfigMapName)
}
}
break
}
if cml.cm.Annotations == nil {
cml.cm.Annotations = make(map[string]string)
}
return nil
}
func (cml *configMapAnnotations) GetPeerList() (*peerList, error) {
var record peerList
if cml.cm == nil {
return nil, errors.New("endpoint not initialized, call Init first")
}
if recordBytes, found := cml.cm.Annotations[KubePeersAnnotationKey]; found {
if err := json.Unmarshal([]byte(recordBytes), &record); err != nil {
return nil, err
}
}
return &record, nil
}
func (cml *configMapAnnotations) UpdatePeerList(list peerList) error {
recordBytes, err := json.Marshal(list)
if err != nil {
return err
}
return cml.UpdateAnnotation(KubePeersAnnotationKey, string(recordBytes))
}
// Clean up a string so it meets the Kubernetes requiremements for Annotation keys:
// name part must consist of alphanumeric characters, '-', '_' or '.', and must
// start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc')
func cleanKey(key string) string {
buf := []byte(key)
for i, c := range buf {
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '/' {
continue
}
buf[i] = '_'
}
return string(buf)
}
func (cml *configMapAnnotations) GetAnnotation(key string) (string, bool) {
value, ok := cml.cm.Annotations[cleanKey(key)]
return value, ok
}
func (cml *configMapAnnotations) UpdateAnnotation(key, value string) (err error) {
if cml.cm == nil {
return errors.New("endpoint not initialized, call Init first")
}
// speculatively change the state, then replace with whatever comes back
// from Update(), which will be the latest on the server whatever happened
cml.cm.Annotations[cleanKey(key)] = value
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
return err
}
func (cml *configMapAnnotations) RemoveAnnotation(key string) (err error) {
if cml.cm == nil {
return errors.New("endpoint not initialized, call Init first")
}
// speculatively change the state, then replace with whatever comes back
// from Update(), which will be the latest on the server whatever happened
delete(cml.cm.Annotations, cleanKey(key))
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
return err
}
func (cml *configMapAnnotations) RemoveAnnotationsWithValue(valueToRemove string) (err error) {
if cml.cm == nil {
return errors.New("endpoint not initialized, call Init first")
}
// speculatively change the state, then replace with whatever comes back
// from Update(), which will be the latest on the server whatever happened
for key, value := range cml.cm.Annotations {
if value == valueToRemove {
delete(cml.cm.Annotations, key) // don't need to clean this key as it came from the map
}
}
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
return err
}
// Loop with jitter, fetching the cml data and calling f() until it
// doesn't get an optimistic locking conflict.
// If it succeeds or gets any other kind of error, stop the loop.
func (cml *configMapAnnotations) LoopUpdate(f func() error) error {
stop := make(chan struct{})
var err error
wait.JitterUntil(func() {
if err = cml.Init(); err != nil {
close(stop)
return
}
err = f()
if err != nil && kubeErrors.IsConflict(err) {
log.Printf("Optimistic locking conflict: trying again: %s", err)
return
}
close(stop)
}, retryPeriod, jitterFactor, true, stop)
return err
}
+251
View File
@@ -0,0 +1,251 @@
/*
Package main deals with weave-net peers on the cluster.
This involves peer management, such as getting the latest peers or removing defunct peers from the cluster
*/
package main
import (
"flag"
"fmt"
"net"
"os"
api "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
weaveapi "github.com/weaveworks/weave/api"
"github.com/weaveworks/weave/common"
)
type nodeInfo struct {
name string
addr string
}
// return the IP addresses of all nodes in the cluster
func getKubePeers(c *kubernetes.Clientset) ([]nodeInfo, error) {
nodeList, err := c.CoreV1().Nodes().List(api.ListOptions{})
if err != nil {
return nil, err
}
addresses := make([]nodeInfo, 0, len(nodeList.Items))
for _, peer := range nodeList.Items {
var internalIP, externalIP string
for _, addr := range peer.Status.Addresses {
// Check it's a valid ipv4 address
ip := net.ParseIP(addr.Address)
if ip == nil || ip.To4() == nil {
continue
}
if addr.Type == "InternalIP" {
internalIP = ip.To4().String()
} else if addr.Type == "ExternalIP" {
externalIP = ip.To4().String()
}
}
// Fallback for cases where a Node has an ExternalIP but no InternalIP
if internalIP != "" {
addresses = append(addresses, nodeInfo{name: peer.Name, addr: internalIP})
} else if externalIP != "" {
addresses = append(addresses, nodeInfo{name: peer.Name, addr: externalIP})
}
}
return addresses, nil
}
const (
configMapName = "weave-net"
configMapNamespace = "kube-system"
)
// update the list of all peers that have gone through this code path
func addMyselfToPeerList(cml *configMapAnnotations, c *kubernetes.Clientset, peerName, name string) (*peerList, error) {
var list *peerList
err := cml.LoopUpdate(func() error {
var err error
list, err = cml.GetPeerList()
if err != nil {
return err
}
if !list.contains(peerName) {
list.add(peerName, name)
err = cml.UpdatePeerList(*list)
if err != nil {
return err
}
}
return nil
})
return list, err
}
func checkIamInPeerList(cml *configMapAnnotations, c *kubernetes.Clientset, peerName string) (bool, error) {
if err := cml.Init(); err != nil {
return false, err
}
list, err := cml.GetPeerList()
if err != nil {
return false, err
}
common.Log.Debugf("[kube-peers] Checking peer %q against list %v", peerName, list)
return list.contains(peerName), nil
}
// For each of those peers that is no longer listed as a node by
// Kubernetes, remove it from Weave IPAM
func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, nodes []nodeInfo, myPeerName string) error {
for loopsWhenNothingChanged := 0; loopsWhenNothingChanged < 3; loopsWhenNothingChanged++ {
if err := cml.Init(); err != nil {
return err
}
// 1. Compare peers stored in the peerList against all peers reported by k8s now.
storedPeerList, err := cml.GetPeerList()
if err != nil {
return err
}
peerMap := make(map[string]peerInfo, len(storedPeerList.Peers))
for _, peer := range storedPeerList.Peers {
peerMap[peer.NodeName] = peer
}
for _, node := range nodes {
delete(peerMap, node.name)
}
common.Log.Debugln("[kube-peers] Nodes that have disappeared:", peerMap)
if len(peerMap) == 0 {
break
}
// 2. Loop for each X in the first set and not in the second - we wish to remove X from our data structures
for _, peer := range peerMap {
if peer.PeerName == myPeerName { // Don't remove myself.
common.Log.Warnln("[kube-peers] not removing myself", peer)
continue
}
common.Log.Debugln("[kube-peers] Preparing to remove disappeared peer", peer)
okToRemove := false
// 3. Check if there is an existing annotation with key X
if existingAnnotation, found := cml.GetAnnotation(KubePeersPrefix + peer.PeerName); found {
common.Log.Debugln("[kube-peers] Existing annotation", existingAnnotation)
// 4. If annotation already contains my identity, ok;
if existingAnnotation == myPeerName {
okToRemove = true
}
} else {
// 5. If non-existent, write an annotation with key X and contents "my identity"
common.Log.Debugln("[kube-peers] Noting I plan to remove ", peer.PeerName)
if err := cml.UpdateAnnotation(KubePeersPrefix+peer.PeerName, myPeerName); err == nil {
okToRemove = true
} else {
common.Log.Debugln("[kube-peers] error from UpdateAnnotation: ", err)
}
}
if okToRemove {
// 6. If step 4 or 5 succeeded, rmpeer X
result, err := weave.RmPeer(peer.PeerName)
common.Log.Infof("[kube-peers] rmpeer of %s: %s", peer.PeerName, result)
if err != nil {
return err
}
loopsWhenNothingChanged = 0
cml.LoopUpdate(func() error {
// 7aa. Remove any annotations Z* that have contents X
if err := cml.RemoveAnnotationsWithValue(peer.PeerName); err != nil {
return err
}
// 7a. Remove X from peerList
storedPeerList.remove(peer.PeerName)
if err := cml.UpdatePeerList(*storedPeerList); err != nil {
return err
}
// 7b. Remove annotation with key X
return cml.RemoveAnnotation(KubePeersPrefix + peer.PeerName)
})
}
// 8. If step 5 failed due to optimistic lock conflict, stop: someone else is handling X
// Step 3-5 is to protect against two simultaneous rmpeers of X
// Step 4 is to pick up again after a restart between step 5 and step 7b
// If the peer doing the reclaim disappears between steps 5 and 7a, then someone will clean it up in step 7aa
// If peer doing the reclaim disappears forever between 7a and 7b then we get a dangling annotation
// This should be sufficiently rare that we don't care.
}
// 9. Go back to step 1 until there is no difference between the two sets
// (or we hit the counter that says we've been round the loop 3 times and nothing happened)
}
// Question: Should we narrow step 2 by checking against Weave Net IPAM?
// i.e. If peer X owns any address space and is marked unreachable, we want to rmpeer X
return nil
}
func main() {
var (
justReclaim bool
justCheck bool
justSetNodeStatus bool
peerName string
nodeName string
logLevel string
)
flag.BoolVar(&justReclaim, "reclaim", false, "reclaim IP space from dead peers")
flag.BoolVar(&justCheck, "check-peer-new", false, "return success if peer name is not stored in annotation")
flag.BoolVar(&justSetNodeStatus, "set-node-status", false, "set NodeNetworkUnavailable to false")
flag.StringVar(&peerName, "peer-name", "unknown", "name of this Weave Net peer")
flag.StringVar(&nodeName, "node-name", "unknown", "name of this Kubernetes node")
flag.StringVar(&logLevel, "log-level", "info", "logging level (debug, info, warning, error)")
flag.Parse()
common.SetLogLevel(logLevel)
config, err := rest.InClusterConfig()
if err != nil {
common.Log.Fatalf("[kube-peers] Could not get cluster config: %v", err)
}
c, err := kubernetes.NewForConfig(config)
if err != nil {
common.Log.Fatalf("[kube-peers] Could not make Kubernetes connection: %v", err)
}
if justCheck {
cml := newConfigMapAnnotations(configMapNamespace, configMapName, c)
exists, err := checkIamInPeerList(cml, c, peerName)
if err != nil {
common.Log.Fatalf("[kube-peers] Could not check peer list: %v", err)
}
if exists {
os.Exit(9)
} else {
os.Exit(0)
}
}
if justSetNodeStatus {
err := setNodeNetworkUnavailableFalse(c, nodeName)
if err != nil {
common.Log.Fatalf("[kube-peers] could not set node status: %v", err)
}
return
}
peers, err := getKubePeers(c)
if err != nil {
common.Log.Fatalf("[kube-peers] Could not get peers: %v", err)
}
if justReclaim {
cml := newConfigMapAnnotations(configMapNamespace, configMapName, c)
list, err := addMyselfToPeerList(cml, c, peerName, nodeName)
if err != nil {
common.Log.Fatalf("[kube-peers] Could not update peer list: %v", err)
}
common.Log.Infoln("[kube-peers] Added myself to peer list", list)
weave := weaveapi.NewClient(os.Getenv("WEAVE_HTTP_ADDR"), common.Log)
err = reclaimRemovedPeers(weave, cml, peers, peerName)
if err != nil {
common.Log.Fatalf("[kube-peers] Error while reclaiming space: %v", err)
}
return
}
for _, node := range peers {
fmt.Println(node.addr)
}
}
+29
View File
@@ -0,0 +1,29 @@
package main
import (
"encoding/json"
"fmt"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
// based on k8s.io/kubernetes/pkg/controller/nodeipam/ipam/adapter.go
func setNodeNetworkUnavailableFalse(c *kubernetes.Clientset, nodeName string) error {
condition := v1.NodeCondition{
Type: v1.NodeNetworkUnavailable,
Status: v1.ConditionFalse,
Reason: "WeaveIsUp",
Message: "Weave pod has set this",
LastTransitionTime: metav1.Now(),
LastHeartbeatTime: metav1.Now(),
}
raw, err := json.Marshal(&[]v1.NodeCondition{condition})
if err != nil {
return err
}
patch := []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw))
_, err = c.CoreV1().Nodes().PatchStatus(nodeName, patch)
return err
}
+8
View File
@@ -50,6 +50,14 @@
}
],
"env": [
{
"description": "Log level",
"name": "LOG_LEVEL",
"settable": [
"value"
],
"value": ""
},
{
"description": "Extra args to `weaver` and `plugin`",
"name": "EXTRA_ARGS",
+2 -1
View File
@@ -7,6 +7,7 @@ IPALLOC_RANGE=${IPALLOC_RANGE:-10.32.0.0/12}
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
STATUS_ADDR=${WEAVE_STATUS_ADDR:-0.0.0.0:6782}
HOST_ROOT=${HOST_ROOT:-/host}
LOG_LEVEL=${LOG_LEVEL:-info}
WEAVE_DIR="/host/var/lib/weave"
mkdir $WEAVE_DIR || true
@@ -44,7 +45,7 @@ exec /home/weave/weaver $EXTRA_ARGS --port=6783 $(router_bridge_opts) \
--no-dns \
--ipalloc-range=$IPALLOC_RANGE \
--nickname "$(hostname)" \
--log-level=debug \
--log-level=$LOG_LEVEL \
--db-prefix="$WEAVE_DIR/weave" \
--plugin-v2 \
$(multicast_opt) \
+12 -1
View File
@@ -1,3 +1,14 @@
FROM DOCKERHUB_USER/weaveARCH_EXT
ADD ./launch.sh ./kube-peers /home/weave/
# These labels are pretty static, and can therefore be added early on:
LABEL maintainer="Weaveworks <help@weave.works>" \
org.opencontainers.image.title="weave-kube" \
org.opencontainers.image.source="https://github.com/weaveworks/weave" \
org.opencontainers.image.vendor="Weaveworks"
ADD ./launch.sh ./kube-utils /home/weave/
ENTRYPOINT ["/home/weave/launch.sh"]
# This label will change for every build, and should therefore be the last layer of the image:
ARG revision
LABEL org.opencontainers.image.revision="${revision}"
+48 -5
View File
@@ -27,9 +27,10 @@ xt_set_exists() {
# Default if not supplied - same as weave net default
IPALLOC_RANGE=${IPALLOC_RANGE:-10.32.0.0/12}
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
STATUS_ADDR=${WEAVE_STATUS_ADDR:-0.0.0.0:6782}
METRICS_ADDR=${WEAVE_METRICS_ADDR:-0.0.0.0:6782}
HOST_ROOT=${HOST_ROOT:-/host}
CONN_LIMIT=${CONN_LIMIT:-30}
CONN_LIMIT=${CONN_LIMIT:-100}
DB_PREFIX=${DB_PREFIX:-/weavedb/weave-net}
# Check if the IP range overlaps anything existing on the host
/usr/bin/weaveutil netcheck $IPALLOC_RANGE weave
@@ -53,12 +54,23 @@ else
fi
fi
STATUS_OPTS="--metrics-addr=$METRICS_ADDR"
# --status-addr exposes internal information, so only turn it on if asked to.
if [ -n "${WEAVE_STATUS_ADDR}" ]; then
STATUS_OPTS="$STATUS_OPTS --status-addr=$WEAVE_STATUS_ADDR"
fi
# Default is that npc will be running; allow caller to override
WEAVE_NPC_OPTS="--expect-npc"
if [ "${EXPECT_NPC}" = "0" ]; then
WEAVE_NPC_OPTS=""
fi
NO_MASQ_LOCAL_OPT=""
if [ -n "${NO_MASQ_LOCAL}" ]; then
NO_MASQ_LOCAL_OPT="--no-masq-local"
fi
# Kubernetes sets HOSTNAME to the host's hostname
# when running a pod in host namespace.
NICKNAME_ARG=""
@@ -73,7 +85,7 @@ router_bridge_opts() {
}
if [ -z "$KUBE_PEERS" ]; then
if ! KUBE_PEERS=$(/home/weave/kube-peers) || [ -z "$KUBE_PEERS" ]; then
if ! KUBE_PEERS=$(/home/weave/kube-utils) || [ -z "$KUBE_PEERS" ]; then
echo Failed to get peers >&2
exit 1
fi
@@ -87,6 +99,29 @@ if [ -z "$IPALLOC_INIT" ]; then
IPALLOC_INIT="consensus=$(peer_count $KUBE_PEERS)"
fi
# Find out what peer name we will be using
PEERNAME=$(/home/weave/weaver $EXTRA_ARGS --print-peer-name --host-root=$HOST_ROOT --db-prefix="$DB_PREFIX")
if [ -z "$PEERNAME" ]; then
echo "Unable to get peer name" >&2
exit 2
fi
# If we have persisted data and peer reclaim is in use
if [ -f ${DB_PREFIX}data.db ]; then
if /usr/bin/weaveutil get-db-flag "$DB_PREFIX" peer-reclaim >/dev/null ; then
# If this peer name is not stored in the list then we were removed by another peer.
if /home/weave/kube-utils -check-peer-new -peer-name="$PEERNAME" -log-level=debug ; then
# In order to avoid a CRDT clash, clean up
echo "Peer not in list; removing persisted data" >&2
rm -f ${DB_PREFIX}data.db
fi
fi
fi
# flag that peer reclaim is now in use - note we have to do this before
# weaver is running as the DB can only be opened by one process at a time
/usr/bin/weaveutil set-db-flag "$DB_PREFIX" peer-reclaim ok
post_start_actions() {
# Wait for weave process to become responsive
while true ; do
@@ -108,19 +143,27 @@ post_start_actions() {
export HOST_ROOT
/home/weave/weave --local setup-cni
# Attempt to run the reclaim process, but don't halt the script if it fails
/home/weave/kube-utils -reclaim -node-name="$HOSTNAME" -peer-name="$PEERNAME" -log-level=debug || true
# Expose the weave network so host processes can communicate with pods
/home/weave/weave --local expose $WEAVE_EXPOSE_IP
# Mark network as up
/home/weave/kube-utils -set-node-status -node-name="$HOSTNAME"
}
post_start_actions &
/home/weave/weaver $EXTRA_ARGS --port=6783 $(router_bridge_opts) \
--name="$PEERNAME" \
--host-root=$HOST_ROOT \
--http-addr=$HTTP_ADDR --status-addr=$STATUS_ADDR --docker-api='' --no-dns \
--db-prefix="/weavedb/weave-net" \
--http-addr=$HTTP_ADDR $STATUS_OPTS --docker-api='' --no-dns \
--db-prefix="$DB_PREFIX" \
--ipalloc-range=$IPALLOC_RANGE $NICKNAME_ARG \
--ipalloc-init $IPALLOC_INIT \
--conn-limit=$CONN_LIMIT \
$WEAVE_NPC_OPTS \
$NO_MASQ_LOCAL_OPT \
"$@" \
$KUBE_PEERS
@@ -47,6 +47,44 @@ items:
- kind: ServiceAccount
name: weave-net
namespace: kube-system
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: weave-net-kube-peer
namespace: kube-system
labels:
name: weave-net-kube-peer
rules:
- apiGroups:
- ''
resources:
- configmaps
resourceNames:
- weave-net
verbs:
- get
- update
- apiGroups:
- ''
resources:
- configmaps
verbs:
- create
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: weave-net-kube-peer
namespace: kube-system
labels:
name: weave-net-kube-peer
roleRef:
kind: Role
name: weave-net-kube-peer
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: weave-net
namespace: kube-system
- apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
+48 -1
View File
@@ -26,13 +26,20 @@ items:
- list
- watch
- apiGroups:
- extensions
- 'networking.k8s.io'
resources:
- networkpolicies
verbs:
- get
- list
- watch
- apiGroups:
- ''
resources:
- nodes/status
verbs:
- patch
- update
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
@@ -47,6 +54,44 @@ items:
- kind: ServiceAccount
name: weave-net
namespace: kube-system
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: weave-net
namespace: kube-system
labels:
name: weave-net
rules:
- apiGroups:
- ''
resources:
- configmaps
resourceNames:
- weave-net
verbs:
- get
- update
- apiGroups:
- ''
resources:
- configmaps
verbs:
- create
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: weave-net
namespace: kube-system
labels:
name: weave-net
roleRef:
kind: Role
name: weave-net
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: weave-net
namespace: kube-system
- apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
@@ -55,6 +100,8 @@ items:
name: weave-net
namespace: kube-system
spec:
# Wait 5 seconds to let pod connect before rolling next pod
minReadySeconds: 5
template:
metadata:
labels:
@@ -0,0 +1,209 @@
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ServiceAccount
metadata:
name: weave-net
labels:
name: weave-net
namespace: kube-system
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: weave-net
labels:
name: weave-net
rules:
- apiGroups:
- ''
resources:
- pods
- namespaces
- nodes
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- networkpolicies
verbs:
- get
- list
- watch
- apiGroups:
- 'networking.k8s.io'
resources:
- networkpolicies
verbs:
- get
- list
- watch
- apiGroups:
- ''
resources:
- nodes/status
verbs:
- patch
- update
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: weave-net
labels:
name: weave-net
roleRef:
kind: ClusterRole
name: weave-net
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: weave-net
namespace: kube-system
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: weave-net
namespace: kube-system
labels:
name: weave-net
rules:
- apiGroups:
- ''
resources:
- configmaps
resourceNames:
- weave-net
verbs:
- get
- update
- apiGroups:
- ''
resources:
- configmaps
verbs:
- create
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: weave-net
namespace: kube-system
labels:
name: weave-net
roleRef:
kind: Role
name: weave-net
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: weave-net
namespace: kube-system
- apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: weave-net
labels:
name: weave-net
namespace: kube-system
spec:
# Wait 5 seconds to let pod connect before rolling next pod
minReadySeconds: 5
template:
metadata:
labels:
name: weave-net
spec:
containers:
- name: weave
command:
- /home/weave/launch.sh
env:
- name: HOSTNAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
image: 'weaveworks/weave-kube:latest'
imagePullPolicy: Always
livenessProbe:
httpGet:
host: 127.0.0.1
path: /status
port: 6784
initialDelaySeconds: 30
resources:
requests:
cpu: 10m
securityContext:
privileged: true
volumeMounts:
- name: weavedb
mountPath: /weavedb
- name: cni-bin
mountPath: /host/opt
- name: cni-bin2
mountPath: /host/home
- name: cni-conf
mountPath: /host/etc
- name: dbus
mountPath: /host/var/lib/dbus
- name: lib-modules
mountPath: /lib/modules
- name: xtables-lock
mountPath: /run/xtables.lock
readOnly: false
- name: weave-npc
env:
- name: HOSTNAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
image: 'weaveworks/weave-npc:latest'
imagePullPolicy: Always
#npc-args
resources:
requests:
cpu: 10m
securityContext:
privileged: true
volumeMounts:
- name: xtables-lock
mountPath: /run/xtables.lock
readOnly: false
hostNetwork: true
hostPID: true
restartPolicy: Always
securityContext:
seLinuxOptions: {}
serviceAccountName: weave-net
tolerations:
- effect: NoSchedule
operator: Exists
volumes:
- name: weavedb
hostPath:
path: /var/lib/weave
- name: cni-bin
hostPath:
path: /opt
- name: cni-bin2
hostPath:
path: /home
- name: cni-conf
hostPath:
path: /etc
- name: dbus
hostPath:
path: /var/lib/dbus
- name: lib-modules
hostPath:
path: /lib/modules
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate
updateStrategy:
type: RollingUpdate
+18 -6
View File
@@ -1,17 +1,24 @@
FROM ALPINE_BASEIMAGE
# If we're building for another architecture than amd64, the CROSS_BUILD_ placeholder is removed so e.g. CROSS_BUILD_COPY turns into COPY
# If we're building normally, for amd64, CROSS_BUILD lines are removed
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
LABEL maintainer "Weaveworks Inc <help@weave.works>"
LABEL works.weave.role=system \
# These labels are pretty static, and can therefore be added early on:
LABEL works.weave.role="system" \
maintainer="Weaveworks <help@weave.works>" \
org.opencontainers.image.title="Weave Net" \
org.opencontainers.image.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
org.opencontainers.image.url="https://weave.works" \
org.opencontainers.image.source="https://github.com/weaveworks/weave" \
org.opencontainers.image.vendor="Weaveworks" \
org.label-schema.schema-version="1.0" \
org.label-schema.name="Weave Net" \
org.label-schema.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
org.label-schema.url="https://weave.works" \
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
org.label-schema.vendor="Weaveworks"
# If we're building for another architecture than amd64, the CROSS_BUILD_ placeholder is removed so e.g. CROSS_BUILD_COPY turns into COPY
# If we're building normally, for amd64, CROSS_BUILD lines are removed
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN apk add --update \
iptables \
ipset \
@@ -21,3 +28,8 @@ RUN apk add --update \
COPY ./weave-npc /usr/bin/weave-npc
COPY ./ulogd.conf /etc/ulogd.conf
ENTRYPOINT ["/usr/bin/weave-npc"]
# These labels will change for every build, and should therefore be the last layer of the image:
ARG revision
LABEL org.opencontainers.image.revision="${revision}" \
org.label-schema.vcs-ref="${revision}"
+133 -32
View File
@@ -7,18 +7,19 @@ import (
"github.com/coreos/go-iptables/iptables"
"github.com/spf13/cobra"
coreapi "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
coreapi "k8s.io/client-go/pkg/api/v1"
extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
"k8s.io/client-go/pkg/fields"
"k8s.io/client-go/pkg/runtime"
"k8s.io/client-go/pkg/util/wait"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/net"
"github.com/weaveworks/weave/net/ipset"
"github.com/weaveworks/weave/npc"
"github.com/weaveworks/weave/npc/ipset"
"github.com/weaveworks/weave/npc/metrics"
"github.com/weaveworks/weave/npc/ulogd"
)
@@ -29,12 +30,13 @@ var (
logLevel string
allowMcast bool
nodeName string
maxList int
)
func handleError(err error) { common.CheckFatal(err) }
func makeController(getter cache.Getter, resource string,
objType runtime.Object, handlers cache.ResourceEventHandlerFuncs) *cache.Controller {
objType runtime.Object, handlers cache.ResourceEventHandlerFuncs) cache.Controller {
listWatch := cache.NewListWatchFromClient(getter, resource, "", fields.Everything())
_, controller := cache.NewInformer(listWatch, objType, 0, handlers)
return controller
@@ -50,11 +52,31 @@ func resetIPTables(ipt *iptables.IPTables) error {
return err
}
return ipt.ClearChain(npc.TableFilter, npc.MainChain)
if err := ipt.ClearChain(npc.TableFilter, npc.MainChain); err != nil {
return err
}
if err := ipt.ClearChain(npc.TableFilter, npc.EgressMarkChain); err != nil {
return err
}
if err := ipt.ClearChain(npc.TableFilter, npc.EgressCustomChain); err != nil {
return err
}
if err := ipt.ClearChain(npc.TableFilter, npc.EgressDefaultChain); err != nil {
return err
}
// We do not clear npc.EgressChain here because otherwise, in the case of restarting
// weave-npc process, all egress traffic is allowed for a short period of time.
// The chain is created in createBaseRules.
return nil
}
func resetIPSets(ips ipset.Interface) error {
// Remove ipsets prefixed `weave-` only
// Remove ipsets prefixed `weave-` only.
sets, err := ips.List(npc.IpsetNamePrefix)
if err != nil {
@@ -74,6 +96,11 @@ func resetIPSets(ips ipset.Interface) error {
}
for _, s := range sets {
// LocalIPset might be used by WEAVE-NPC-EGRESS chain which we do not
// flush, so we cannot destroy it.
if s == npc.LocalIpset {
continue
}
common.Log.Debugf("Destroying ipset '%s'", string(s))
if err := ips.Destroy(s); err != nil {
common.Log.Errorf("Failed to destroy ipset '%s'", string(s))
@@ -109,14 +136,86 @@ func createBaseRules(ipt *iptables.IPTables, ips ipset.Interface) error {
}
// If the destination address is not any of the local pods, let it through
if err := ips.Create(npc.LocalIpset, ipset.HashIP); err != nil {
found, err := ipsetExist(ips, npc.LocalIpset)
if err != nil {
return err
}
return ipt.Append(npc.TableFilter, npc.MainChain,
"-m", "set", "!", "--match-set", npc.LocalIpset, "dst", "-j", "ACCEPT")
if !found {
if err := ips.Create(npc.LocalIpset, ipset.HashIP); err != nil {
return err
}
}
if err := ipt.Append(npc.TableFilter, npc.MainChain,
"-m", "set", "!", "--match-set", npc.LocalIpset, "dst", "-j", "ACCEPT"); err != nil {
return err
}
if err := ipt.Append(npc.TableFilter, npc.EgressMarkChain,
"-j", "MARK", "--set-xmark", npc.EgressMark); err != nil {
return err
}
// Egress rules:
//
// -A WEAVE-NPC-EGRESS -m state --state RELATED,ESTABLISHED -j ACCEPT
// -A WEAVE-NPC-EGRESS -m set ! --match-set weave-local-pods src -j RETURN
// -A WEAVE-NPC-EGRESS -d 224.0.0.0/4 -j RETURN
// -A WEAVE-NPC-EGRESS -m state --state NEW -j WEAVE-NPC-EGRESS-DEFAULT
// -A WEAVE-NPC-EGRESS -m state --state NEW -m mark ! --mark 0x40000/0x40000 -j WEAVE-NPC-EGRESS-CUSTOM
// -A WEAVE-NPC-EGRESS -m state --state NEW -m mark ! --mark 0x40000/0x40000 -j NFLOG --nflog-group 86
// -A WEAVE-NPC-EGRESS -m mark ! --mark 0x40000/0x40000 -j DROP
//
// -A WEAVE-NPC-EGRESS-CUSTOM <rulespec> -j MARK --set-xmark 0x40000/0x40000
// -A WEAVE-NPC-EGRESS-CUSTOM <rulespec> -j RETURN
//
// -A WEAVE-NPC-EGRESS-DEFAULT <rulespec> -j MARK --set-xmark 0x40000/0x40000
// -A WEAVE-NPC-EGRESS-DEFAULT <rulespec> -j RETURN
//
// For each rule we create two (mark and return). We cannot just accept
// a packet if it matches any rule, as a packet might need to traverse
// the ingress npc as well which happens later in the chain (in some cases
// we cannot detect whether packet is ingress or egress, so we need to
// check both chains).
ruleSpecs := [][]string{
{"-m", "state", "--state", "RELATED,ESTABLISHED", "-j", "ACCEPT"},
{"-m", "state", "--state", "NEW", "-m", "set", "!", "--match-set", npc.LocalIpset, "src", "-j", "RETURN"},
}
if allowMcast {
ruleSpecs = append(ruleSpecs, []string{"-d", "224.0.0.0/4", "-j", "RETURN"})
}
ruleSpecs = append(ruleSpecs, [][]string{
{"-m", "state", "--state", "NEW", "-j", string(npc.EgressDefaultChain)},
{"-m", "state", "--state", "NEW", "-m", "mark", "!", "--mark", npc.EgressMark, "-j", string(npc.EgressCustomChain)},
{"-m", "state", "--state", "NEW", "-m", "mark", "!", "--mark", npc.EgressMark, "-j", "NFLOG", "--nflog-group", "86"},
{"-m", "mark", "!", "--mark", npc.EgressMark, "-j", "DROP"},
}...)
if err := net.AddChainWithRules(ipt, npc.TableFilter, npc.EgressChain, ruleSpecs); err != nil {
return err
}
return nil
}
// Dummy way to check whether a given ipset exists.
// TODO(brb) Use "ipset -exist create <..>" for our purpose instead (for some reasons
// creating an ipset with -exist fails).
func ipsetExist(ips ipset.Interface, name ipset.Name) (bool, error) {
sets, err := ips.List(string(name))
if err != nil {
return false, err
}
for _, s := range sets {
if s == name {
return true, nil
}
}
return false, nil
}
func root(cmd *cobra.Command, args []string) {
var npController cache.Controller
common.SetLogLevel(logLevel)
if nodeName == "" {
// HOSTNAME is set by Kubernetes for pods in the host network namespace
@@ -144,7 +243,7 @@ func root(cmd *cobra.Command, args []string) {
ipt, err := iptables.New()
handleError(err)
ips := ipset.New(common.LogLogger())
ips := ipset.New(common.LogLogger(), maxList)
handleError(resetIPTables(ipt))
handleError(resetIPSets(ips))
@@ -192,25 +291,26 @@ func root(cmd *cobra.Command, args []string) {
handleError(npc.UpdatePod(old.(*coreapi.Pod), new.(*coreapi.Pod)))
}})
npController := makeController(client.Extensions().RESTClient(), "networkpolicies", &extnapi.NetworkPolicy{},
cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
handleError(npc.AddNetworkPolicy(obj.(*extnapi.NetworkPolicy)))
},
DeleteFunc: func(obj interface{}) {
switch obj := obj.(type) {
case *extnapi.NetworkPolicy:
handleError(npc.DeleteNetworkPolicy(obj))
case cache.DeletedFinalStateUnknown:
// We know this object has gone away, but its final state is no longer
// available from the API server. Instead we use the last copy of it
// that we have, which is good enough for our cleanup.
handleError(npc.DeleteNetworkPolicy(obj.Obj.(*extnapi.NetworkPolicy)))
}
},
UpdateFunc: func(old, new interface{}) {
handleError(npc.UpdateNetworkPolicy(old.(*extnapi.NetworkPolicy), new.(*extnapi.NetworkPolicy)))
}})
npHandlers := cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
handleError(npc.AddNetworkPolicy(obj))
},
DeleteFunc: func(obj interface{}) {
switch obj := obj.(type) {
case cache.DeletedFinalStateUnknown:
// We know this object has gone away, but its final state is no longer
// available from the API server. Instead we use the last copy of it
// that we have, which is good enough for our cleanup.
handleError(npc.DeleteNetworkPolicy(obj.Obj))
default:
handleError(npc.DeleteNetworkPolicy(obj))
}
},
UpdateFunc: func(old, new interface{}) {
handleError(npc.UpdateNetworkPolicy(old, new))
},
}
npController = makeController(client.NetworkingV1().RESTClient(), "networkpolicies", &networkingv1.NetworkPolicy{}, npHandlers)
go nsController.Run(wait.NeverStop)
go podController.Run(wait.NeverStop)
@@ -231,6 +331,7 @@ func main() {
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "debug", "logging level (debug, info, warning, error)")
rootCmd.PersistentFlags().BoolVar(&allowMcast, "allow-mcast", true, "allow all multicast traffic")
rootCmd.PersistentFlags().StringVar(&nodeName, "node-name", "", "only generate rules that apply to this node")
rootCmd.PersistentFlags().IntVar(&maxList, "max-list-size", 1024, "maximum size of ipset list (for namespaces)")
handleError(rootCmd.Execute())
}
+12 -2
View File
@@ -1,7 +1,17 @@
# This is a nearly-empty image that we use to create a data-only container for persistence
FROM scratch
LABEL maintainer "Weaveworks Inc <help@weave.works>"
LABEL works.weave.role=system
# These labels are pretty static, and can therefore be added early on:
LABEL works.weave.role="system" \
maintainer="Weaveworks <help@weave.works>" \
org.opencontainers.image.title="weavedb" \
org.opencontainers.image.source="https://github.com/weaveworks/weave" \
org.opencontainers.image.vendor="Weaveworks"
ENTRYPOINT ["data-only"]
# Work round Docker refusing to save an empty image
COPY Dockerfile /
# This label will change for every build, and should therefore be the last layer of the image:
ARG revision
LABEL org.opencontainers.image.revision="${revision}"
+10 -1
View File
@@ -1,10 +1,19 @@
FROM DOCKERHUB_USER/weaveARCH_EXT
# These labels are pretty static, and can therefore be added early on:
LABEL maintainer="Weaveworks <help@weave.works>" \
org.opencontainers.image.title="weaveexec" \
org.opencontainers.image.source="https://github.com/weaveworks/weave" \
org.opencontainers.image.vendor="Weaveworks"
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
ADD ./sigproxy ./symlink /home/weave/
ADD ./docker /usr/bin/
ADD ./weavewait /w/w
ADD ./weavewait_noop /w-noop/w
ADD ./weavewait_nomcast /w-nomcast/w
WORKDIR /home/weave
# This label will change for every build, and should therefore be the last layer of the image:
ARG revision
LABEL org.opencontainers.image.revision="${revision}"
+19 -7
View File
@@ -1,17 +1,24 @@
FROM ALPINE_BASEIMAGE
# If we're building for another architecture than amd64, the CROSS_BUILD_ placeholder is removed so e.g. CROSS_BUILD_COPY turns into COPY
# If we're building normally, for amd64, CROSS_BUILD lines are removed
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
LABEL maintainer "Weaveworks Inc <help@weave.works>"
LABEL works.weave.role=system \
# These labels are pretty static, and can therefore be added early on:
LABEL works.weave.role="system" \
maintainer="Weaveworks <help@weave.works>" \
org.opencontainers.image.title="Weave Net" \
org.opencontainers.image.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
org.opencontainers.image.url="https://weave.works" \
org.opencontainers.image.source="https://github.com/weaveworks/weave" \
org.opencontainers.image.vendor="Weaveworks" \
org.label-schema.schema-version="1.0" \
org.label-schema.name="Weave Net" \
org.label-schema.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
org.label-schema.url="https://weave.works" \
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
org.label-schema.vendor="Weaveworks"
# If we're building for another architecture than amd64, the CROSS_BUILD_ placeholder is removed so e.g. CROSS_BUILD_COPY turns into COPY
# If we're building normally, for amd64, CROSS_BUILD lines are removed
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
RUN apk add --update \
curl \
ethtool \
@@ -21,11 +28,16 @@ RUN apk add --update \
util-linux \
conntrack-tools \
bind-tools \
ca-certificates \
&& rm -rf /var/cache/apk/*
ADD ./weave ./weaver /home/weave/
ADD ./weaveutil /usr/bin/
ADD weavedata.db /weavedb/
COPY ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/home/weave/weaver"]
WORKDIR /home/weave
# These labels will change for every build, and should therefore be the last layer of the image:
ARG revision
LABEL org.opencontainers.image.revision="${revision}" \
org.label-schema.vcs-ref="${revision}"
File diff suppressed because it is too large. Load diff
+27 -19
View File
@@ -34,23 +34,7 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{
},
"printIPAMRanges": func(router weave.NetworkRouterStatus, status ipam.Status) string {
var buffer bytes.Buffer
type stats struct {
ips uint32
nickname string
reachable bool
}
peerStats := make(map[string]*stats)
for _, entry := range status.Entries {
s, found := peerStats[entry.Peer]
if !found {
s = &stats{nickname: entry.Nickname, reachable: entry.IsKnownPeer}
peerStats[entry.Peer] = s
}
s.ips += entry.Size
}
peerStats := summariseIpamStats(&status)
printOwned := func(name string, nickName string, info string, ips uint32) {
percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs)
@@ -116,6 +100,25 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{
"trimSuffix": strings.TrimSuffix,
})
type ipamStats struct {
ips uint32
nickname string
reachable bool
}
func summariseIpamStats(status *ipam.Status) map[string]*ipamStats {
peerStats := make(map[string]*ipamStats)
for _, entry := range status.Entries {
s, found := peerStats[entry.Peer]
if !found {
s = &ipamStats{nickname: entry.Nickname, reachable: entry.IsKnownPeer}
peerStats[entry.Peer] = s
}
s.ips += entry.Size
}
return peerStats
}
func countDNSEntries(entries []nameserver.EntryStatus) int {
count := 0
for _, entry := range entries {
@@ -326,7 +329,7 @@ func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRout
w.Write(json)
})
muxRouter.Methods("GET").Path("/report").Queries("format", "{format}").HandlerFunc(
muxRouter.Methods("GET").Path("/report").HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
funcs := template.FuncMap{
"json": func(v interface{}) string {
@@ -334,7 +337,12 @@ func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRout
return string(a)
},
}
formatTemplate, err := template.New("format").Funcs(funcs).Parse(mux.Vars(r)["format"])
format, ok := r.URL.Query()["format"]
if !ok || len(format) != 1 {
http.Error(w, "error: must supply one format parameter", http.StatusBadRequest)
return
}
formatTemplate, err := template.New("format").Funcs(funcs).Parse(format[0])
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
+62 -34
View File
@@ -26,6 +26,7 @@ import (
"github.com/weaveworks/weave/nameserver"
weavenet "github.com/weaveworks/weave/net"
"github.com/weaveworks/weave/net/address"
"github.com/weaveworks/weave/net/ipset"
"github.com/weaveworks/weave/plugin"
weaveproxy "github.com/weaveworks/weave/proxy"
weave "github.com/weaveworks/weave/router"
@@ -45,12 +46,20 @@ type ipamConfig struct {
}
type dnsConfig struct {
Domain string
ListenAddress string
TTL int
ClientTimeout time.Duration
EffectiveListenAddress string
ResolvConf string
Domain string
ListenAddress string
TTL int
ClientTimeout time.Duration
ResolvConf string
}
// return the address part of the DNS listen address, without ":53" on the end
func (c dnsConfig) addressOnly() string {
addr, _, err := net.SplitHostPort(c.ListenAddress)
if err != nil {
Log.Fatalf("Error when parsing DNS listen address %q: %s", c.ListenAddress, err)
}
return addr
}
func (c *ipamConfig) Enabled() bool {
@@ -131,6 +140,7 @@ func main() {
var (
justVersion bool
justPeerName bool
config mesh.Config
bridgeConfig weavenet.BridgeConfig
networkConfig weave.NetworkConfig
@@ -146,6 +156,7 @@ func main() {
noDiscovery bool
httpAddr string
statusAddr string
metricsAddr string
ipamConfig ipamConfig
dockerAPI string
peers []string
@@ -163,6 +174,7 @@ func main() {
)
mflag.BoolVar(&justVersion, []string{"-version"}, false, "print version and exit")
mflag.BoolVar(&justPeerName, []string{"-print-peer-name"}, false, "print peer name and exit")
mflag.StringVar(&config.Host, []string{"-host"}, "", "router host")
mflag.IntVar(&config.Port, []string{"-port"}, mesh.Port, "router port")
mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, mesh.ProtocolMinVersion, "minimum weave protocol version")
@@ -176,12 +188,13 @@ func main() {
mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)")
mflag.BoolVar(&pktdebug, []string{"-pkt-debug"}, false, "enable per-packet debug logging")
mflag.StringVar(&prof, []string{"-profile"}, "", "enable profiling and write profiles to given path")
mflag.IntVar(&config.ConnLimit, []string{"-conn-limit"}, 30, "connection limit (0 for unlimited)")
mflag.IntVar(&config.ConnLimit, []string{"-conn-limit"}, 100, "connection limit (0 for unlimited)")
mflag.BoolVar(&noDiscovery, []string{"-no-discovery"}, false, "disable peer discovery")
mflag.IntVar(&bufSzMB, []string{"-bufsz"}, 8, "capture buffer size in MB")
mflag.IntVar(&bridgeConfig.MTU, []string{"-mtu"}, 0, "MTU size")
mflag.StringVar(&httpAddr, []string{"-http-addr"}, "", "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)")
mflag.StringVar(&statusAddr, []string{"-status-addr"}, "", "address to bind status+metrics interface to (disabled if blank, absolute path indicates unix domain socket)")
mflag.StringVar(&metricsAddr, []string{"-metrics-addr"}, "", "address to bind metrics interface to (disabled if blank, absolute path indicates unix domain socket)")
mflag.StringVar(&ipamConfig.Mode, []string{"-ipalloc-init"}, "", "allocator initialisation strategy (consensus, seed or observer)")
mflag.StringVar(&ipamConfig.IPRangeCIDR, []string{"-ipalloc-range"}, "", "IP address range reserved for automatic allocation, in CIDR notation")
mflag.StringVar(&ipamConfig.IPSubnetCIDR, []string{"-ipalloc-default-subnet"}, "", "subnet to allocate within by default, in CIDR notation")
@@ -191,10 +204,10 @@ func main() {
mflag.StringVar(&dnsConfig.ListenAddress, []string{"-dns-listen-address"}, nameserver.DefaultListenAddress, "address to listen on for DNS requests")
mflag.IntVar(&dnsConfig.TTL, []string{"-dns-ttl"}, nameserver.DefaultTTL, "TTL for DNS request from our domain")
mflag.DurationVar(&dnsConfig.ClientTimeout, []string{"-dns-fallback-timeout"}, nameserver.DefaultClientTimeout, "timeout for fallback DNS requests")
mflag.StringVar(&dnsConfig.EffectiveListenAddress, []string{"-dns-effective-listen-address"}, "", "address DNS will actually be listening, after Docker port mapping")
mflag.StringVar(&dnsConfig.ResolvConf, []string{"-resolv-conf"}, "", "path to resolver configuration for fallback DNS lookups")
mflag.StringVar(&bridgeConfig.DatapathName, []string{"-datapath"}, "", "ODP datapath name")
mflag.BoolVar(&bridgeConfig.NoFastdp, []string{"-no-fastdp"}, false, "Disable Fast Datapath")
mflag.BoolVar(&bridgeConfig.NoBridgedFastdp, []string{"-no-bridged-fastdp"}, false, "Disable Bridged Fast Datapath")
mflag.StringVar(&trustedSubnetStr, []string{"-trusted-subnets"}, "", "comma-separated list of trusted subnets in CIDR notation")
mflag.StringVar(&dbPrefix, []string{"-db-prefix"}, "/weavedb/weave", "pathname/prefix of filename to store data")
mflag.StringVar(&procPath, []string{"-proc-path"}, "/proc", "path to reach host /proc filesystem")
@@ -209,12 +222,9 @@ func main() {
mflag.BoolVar(&pluginConfig.EnableV2Multicast, []string{"-plugin-v2-multicast"}, false, "enable multicast for Docker plugin (v2)")
mflag.StringVar(&pluginConfig.Socket, []string{"-plugin-socket"}, "/run/docker/plugins/weave.sock", "plugin socket on which to listen")
mflag.StringVar(&pluginConfig.MeshSocket, []string{"-plugin-mesh-socket"}, "/run/docker/plugins/weavemesh.sock", "plugin socket on which to listen in mesh mode")
mflag.BoolVar(&bridgeConfig.NoMasqLocal, []string{"-no-masq-local"}, false, "do not SNAT external traffic sent to containers running on this node")
proxyConfig := configureProxy(version, defaultDockerHost)
if bridgeConfig.AWSVPC {
proxyConfig.NoMulticastRoute = true
proxyConfig.KeepTXOn = true
}
proxyConfig := newProxyConfig()
// crude way of detecting that we probably have been started in a
// container, with `weave launch` --> suppress misleading paths in
@@ -230,6 +240,17 @@ func main() {
fmt.Printf("weave %s\n", version)
os.Exit(0)
}
name := peerName(routerName, bridgeConfig.WeaveBridgeName, dbPrefix, hostRoot)
if justPeerName {
fmt.Printf("%s\n", name)
os.Exit(0)
}
proxyConfig.DockerHost = dockerAPI
if bridgeConfig.AWSVPC {
proxyConfig.NoMulticastRoute = true
proxyConfig.KeepTXOn = true
}
peers = mflag.Args()
if resume && len(peers) > 0 {
@@ -254,6 +275,8 @@ func main() {
var proxy *weaveproxy.Proxy
var err error
if proxyConfig.Enabled {
proxyConfig.DNSListenAddress = dnsConfig.addressOnly()
proxyConfig.DNSDomain = dnsConfig.Domain
if noDNS {
proxyConfig.WithoutDNS = true
}
@@ -282,11 +305,10 @@ func main() {
}
}
name := peerName(routerName, bridgeConfig.WeaveBridgeName, dbPrefix, hostRoot)
bridgeConfig.Mac = name.String()
bridgeConfig.Port = config.Port
bridgeType, err := weavenet.EnsureBridge(procPath, &bridgeConfig, Log)
ips := ipset.New(common.LogLogger(), 0)
bridgeType, err := weavenet.EnsureBridge(procPath, &bridgeConfig, Log, ips)
checkFatal(err)
Log.Println("Bridge type is", bridgeType)
@@ -317,12 +339,15 @@ func main() {
if bridgeConfig.AWSVPC && !ipamConfig.Enabled() {
Log.Fatalf("--awsvpc mode requires IPAM enabled")
}
if bridgeConfig.AWSVPC && bridgeConfig.NoMasqLocal {
Log.Fatalf("--awsvpc mode is not compatible with the --no-masq-local option")
}
db, err := db.NewBoltDB(dbPrefix)
checkFatal(err)
defer db.Close()
router, err := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlay, db)
router, err := weave.NewNetworkRouter(config, networkConfig, bridgeConfig, name, nickName, overlay, db)
checkFatal(err)
Log.Println("Our name is", router.Ourself)
@@ -376,17 +401,19 @@ func main() {
var (
allocator *ipam.Allocator
defaultSubnet address.CIDR
trackerName string
)
if ipamConfig.Enabled() {
var t tracker.LocalRangeTracker
if bridgeConfig.AWSVPC {
Log.Infoln("Creating AWSVPC LocalRangeTracker")
t, err = tracker.NewAWSVPCTracker(bridgeConfig.WeaveBridgeName)
if err != nil {
Log.Fatalf("Cannot create AWSVPC LocalRangeTracker: %s", err)
}
trackerName = "awsvpc"
} else if bridgeConfig.NoMasqLocal {
t = weavenet.NewNoMasqLocalTracker(ips)
}
if t != nil {
Log.Infof("Using %q LocalRangeTracker", t)
}
preClaims, err := findExistingAddresses(dockerCli, bridgeConfig.WeaveBridgeName)
@@ -434,7 +461,7 @@ func main() {
if httpAddr != "" {
muxRouter := mux.NewRouter()
if allocator != nil {
allocator.HandleHTTP(muxRouter, defaultSubnet, trackerName, dockerCli)
allocator.HandleHTTP(muxRouter, defaultSubnet, dockerCli)
}
if ns != nil {
ns.HandleHTTP(muxRouter, dockerCli)
@@ -457,10 +484,17 @@ func main() {
muxRouter.Methods("GET").Path("/metrics").Handler(metricsHandler(router, allocator, ns, dnsserver))
statusMux := http.NewServeMux()
statusMux.Handle("/", muxRouter)
Log.Println("Listening for metrics requests on", statusAddr)
Log.Println("Listening for status+metrics requests on", statusAddr)
go listenAndServeHTTP(statusAddr, statusMux)
}
if metricsAddr != "" {
metricsMux := http.NewServeMux()
metricsMux.Handle("/metrics", metricsHandler(router, allocator, ns, dnsserver))
Log.Println("Listening for metrics requests on", metricsAddr)
go listenAndServeHTTP(metricsAddr, metricsMux)
}
if plugin != nil {
go plugin.Start(httpAddr, dockerCli, waitReady.Add())
}
@@ -469,17 +503,17 @@ func main() {
// Run this on its own goroutine because the allocator can block
// We remove the default route installed by the kernel,
// because awsvpc has installed it as well
go expose(allocator, defaultSubnet, bridgeConfig.WeaveBridgeName, bridgeConfig.AWSVPC, waitReady.Add())
go exposeForAWSVPC(allocator, defaultSubnet, bridgeConfig.WeaveBridgeName, waitReady.Add())
}
signals.SignalHandlerLoop(common.Log, router)
}
func expose(alloc *ipam.Allocator, subnet address.CIDR, bridgeName string, removeDefaultRoute bool, ready func()) {
func exposeForAWSVPC(alloc *ipam.Allocator, subnet address.CIDR, bridgeName string, ready func()) {
addr, err := alloc.Allocate("weave:expose", subnet, false, func() bool { return false })
checkFatal(err)
cidr := address.MakeCIDR(subnet, addr)
err = weavenet.AddBridgeAddr(bridgeName, cidr.IPNet(), removeDefaultRoute)
err = weavenet.Expose(bridgeName, cidr.IPNet(), true, false)
checkFatal(err)
Log.Printf("Bridge %q exposed on address %v", bridgeName, cidr)
ready()
@@ -525,12 +559,10 @@ func (nopPacketLogging) LogPacket(string, weave.PacketKey) {
func (nopPacketLogging) LogForwardPacket(string, weave.ForwardPacketKey) {
}
func configureProxy(version string, defaultDockerHost string) *weaveproxy.Config {
func newProxyConfig() *weaveproxy.Config {
proxyConfig := weaveproxy.Config{
Version: version,
Image: getenvOrDefault("EXEC_IMAGE", "weaveworks/weaveexec"),
DockerBridge: getenvOrDefault("DOCKER_BRIDGE", "docker0"),
DockerHost: defaultDockerHost,
}
mflag.BoolVar(&proxyConfig.Enabled, []string{"-proxy"}, false, "instruct Weave Net to start its Docker proxy")
mflagext.ListVar(&proxyConfig.ListenAddrs, []string{"H"}, nil, "addresses on which to listen for Docker proxy")
@@ -630,17 +662,13 @@ func createDNSServer(config dnsConfig, router *mesh.Router, isKnownPeer func(mes
gossip, err := router.NewGossip("nameserver", ns)
checkFatal(err)
ns.SetGossip(gossip)
upstream := nameserver.NewUpstream(config.ResolvConf, config.EffectiveListenAddress)
upstream := nameserver.NewUpstream(config.ResolvConf, config.addressOnly())
dnsserver, err := nameserver.NewDNSServer(ns, config.Domain, config.ListenAddress,
upstream, uint32(config.TTL), config.ClientTimeout)
if err != nil {
Log.Fatal("Unable to start dns server: ", err)
}
listenAddr := config.ListenAddress
if config.EffectiveListenAddress != "" {
listenAddr = config.EffectiveListenAddress
}
Log.Println("Listening for DNS queries on", listenAddr)
Log.Println("Listening for DNS queries on", config.ListenAddress)
return ns, dnsserver
}
+21
View File
@@ -82,6 +82,27 @@ var metrics = []metric{
ch <- intGauge(desc, metrics.Flows)
}
}},
{desc("weave_ipam_unreachable_count", "Number of unreachable peers."),
func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
var count int
for _, entry := range summariseIpamStats(s.IPAM) {
if !entry.reachable {
count++
}
}
ch <- intGauge(desc, count)
}},
{desc("weave_ipam_unreachable_percentage", "Percentage of IP addresses owned by unreachable peers."),
func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
var totalUnreachable uint32
for _, entry := range summariseIpamStats(s.IPAM) {
if !entry.reachable {
totalUnreachable += entry.ips
}
}
percentage := float64(totalUnreachable) * 100.0 / float64(s.IPAM.RangeNumIPs)
ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, percentage)
}},
{desc("weave_ipam_pending_allocates", "Number of pending allocates."),
func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
if s.IPAM != nil {
+21 -32
View File
@@ -4,11 +4,9 @@ import (
"fmt"
"net"
"os"
"strconv"
"strings"
"syscall"
docker "github.com/fsouza/go-dockerclient"
"github.com/vishvananda/netns"
weavenet "github.com/weaveworks/weave/net"
@@ -16,8 +14,8 @@ import (
)
func attach(args []string) error {
if len(args) < 4 {
cmdUsage("attach-container", "[--no-multicast-route] [--keep-tx-on] [--hairpin-mode=true|false] <container-id> <bridge-name> <mtu> <cidr>...")
if len(args) < 3 {
cmdUsage("attach-container", "[--no-multicast-route] [--keep-tx-on] [--hairpin-mode=true|false] <container-id> <bridge-name> <cidr>...")
}
keepTXOn := false
@@ -53,16 +51,12 @@ func attach(args []string) error {
} else if nsHost.Equal(nsContainer) {
return fmt.Errorf("Container is running in the host network namespace, and therefore cannot be\nconnected to weave - perhaps the container was started with --net=host")
}
mtu, err := strconv.Atoi(args[2])
if err != nil && args[3] != "" {
return fmt.Errorf("unable to parse mtu %q: %s", args[2], err)
}
cidrs, err := parseCIDRs(args[3:])
cidrs, err := parseCIDRs(args[2:])
if err != nil {
return err
}
err = weavenet.AttachContainer(weavenet.NSPathByPid(pid), fmt.Sprint(pid), weavenet.VethName, args[1], mtu, withMulticastRoute, cidrs, keepTXOn, hairpinMode)
err = weavenet.AttachContainer(weavenet.NSPathByPid(pid), fmt.Sprint(pid), weavenet.VethName, args[1], 0, withMulticastRoute, cidrs, keepTXOn, hairpinMode)
// If we detected an error but the container has died, tell the user that instead.
if err != nil && !processExists(pid) {
err = fmt.Errorf("Container %s died", args[0])
@@ -70,21 +64,6 @@ func attach(args []string) error {
return err
}
func containerPid(containerID string) (int, error) {
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return 0, fmt.Errorf("unable to connect to docker: %s", err)
}
container, err := c.InspectContainer(containerID)
if err != nil {
return 0, fmt.Errorf("unable to inspect container %s: %s", containerID, err)
}
if container.State.Pid == 0 {
return 0, fmt.Errorf("container %s not running", containerID)
}
return container.State.Pid, nil
}
func processExists(pid int) bool {
err := syscall.Kill(pid, syscall.Signal(0))
return err == nil || err == syscall.EPERM
@@ -119,21 +98,31 @@ func detach(args []string) error {
}
func rewriteEtcHosts(args []string) error {
if len(args) < 4 {
cmdUsage("rewrite-etc-hosts", "<hosts-path> <fqdn> <image> <cidr>... [name:addr...]")
if len(args) < 3 {
cmdUsage("rewrite-etc-hosts", "<container-id> <image> <cidr> [name:addr...]")
}
hostsPath := args[0]
fqdn := args[1]
image := args[2]
containerID := args[0]
image := args[1]
cidrs := args[2]
extraHosts := args[3:]
container, err := inspectContainer(containerID)
if err != nil {
return err
}
hostsPath := container.HostsPath
fqdn := container.Config.Hostname + "." + container.Config.Domainname
var ips []*net.IPNet
for _, cidr := range strings.Fields(args[3]) {
for _, cidr := range strings.Fields(cidrs) {
_, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return err
}
ips = append(ips, ipnet)
}
extraHosts := args[4:]
docker := os.Getenv("DOCKER_HOST")
if docker == "" {
docker = "unix:///var/run/docker.sock"
-35
View File
@@ -2,9 +2,7 @@ package main
import (
"fmt"
"strconv"
"github.com/weaveworks/weave/common"
weavenet "github.com/weaveworks/weave/net"
)
@@ -22,36 +20,3 @@ func detectBridgeType(args []string) error {
}
return nil
}
func createBridge(args []string) error {
if len(args) != 10 {
cmdUsage("create-bridge", "<docker-bridge-name> <weave-bridge-name> <datapath-name> <mtu> <port> <mac> <no-fastdp> <no-bridged-fastdp> <proc-path> <expect-npc>")
}
mtu, err := strconv.Atoi(args[3])
if err != nil && args[3] != "" {
return err
}
port, err := strconv.Atoi(args[4])
if err != nil {
return err
}
config := weavenet.BridgeConfig{
DockerBridgeName: args[0],
WeaveBridgeName: args[1],
DatapathName: args[2],
MTU: mtu,
Port: port,
Mac: args[5],
NoFastdp: args[6] != "",
NoBridgedFastdp: args[7] != "",
NPC: args[9] == "--expect-npc",
}
procPath := args[8]
bridgeType, err := weavenet.EnsureBridge(procPath, &config, common.Log)
if err != nil {
return err
}
fmt.Println(bridgeType.String())
return nil
}
+285
View File
@@ -0,0 +1,285 @@
package main
import (
"fmt"
"os"
"strings"
docker "github.com/fsouza/go-dockerclient"
)
func inspectContainer(containerNameOrID string) (*docker.Container, error) {
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return nil, fmt.Errorf("unable to connect to docker: %s", err)
}
container, err := c.InspectContainer(containerNameOrID)
if err != nil {
return nil, fmt.Errorf("unable to inspect container %s: %s", containerNameOrID, err)
}
return container, nil
}
func containerPid(containerID string) (int, error) {
container, err := inspectContainer(containerID)
if err != nil {
return 0, err
}
if container.State.Pid == 0 {
return 0, fmt.Errorf("container %s not running", containerID)
}
return container.State.Pid, nil
}
func containerID(args []string) error {
if len(args) < 1 {
cmdUsage("container-id", "<container-name-or-short-id>")
}
container, err := inspectContainer(args[0])
if err != nil {
return err
}
fmt.Print(container.ID)
return nil
}
func containerState(args []string) error {
if len(args) < 1 {
cmdUsage("container-state", "<container-id> [<image-prefix>]")
}
container, err := inspectContainer(args[0])
if err != nil {
return err
}
if len(args) == 1 {
fmt.Print(container.State.StateString())
} else {
imagePrefix := args[1]
if strings.HasPrefix(container.Config.Image, imagePrefix) {
fmt.Print(container.State.StateString())
} else {
if container.State.Running {
fmt.Print("running image mismatch: ", container.Config.Image)
} else {
fmt.Print("image mismatch: ", container.Config.Image)
}
}
}
return nil
}
func containerFQDN(args []string) error {
if len(args) < 1 {
cmdUsage("container-fqdn", "<container-id>")
}
container, err := inspectContainer(args[0])
if err != nil {
return err
}
fmt.Print(container.Config.Hostname, ".", container.Config.Domainname)
return nil
}
func runContainer(args []string) error {
env := []string{}
name := ""
net := ""
pid := ""
privileged := false
restart := docker.NeverRestart()
volumes := []string{}
volumesFrom := []string{}
done := false
for i := 0; i < len(args) && !done; {
switch args[i] {
case "-e", "--env":
if v := os.Getenv(args[i+1]); v != "" {
env = append(env, args[i+1]+"="+v)
} else {
env = append(env, args[i+1])
}
args = append(args[:i], args[i+2:]...)
case "--name":
name = args[i+1]
args = append(args[:i], args[i+2:]...)
case "--net":
net = args[i+1]
args = append(args[:i], args[i+2:]...)
case "--pid":
pid = args[i+1]
args = append(args[:i], args[i+2:]...)
case "--privileged":
privileged = true
args = append(args[:i], args[i+1:]...)
case "--restart":
restart = docker.RestartPolicy{Name: args[i+1]}
args = append(args[:i], args[i+2:]...)
case "-v", "--volume":
// Must dedup binds, otherwise, container fails creation
skip := false
for _, v := range volumes {
if v == args[i+1] {
skip = true
}
}
if !skip {
volumes = append(volumes, args[i+1])
}
args = append(args[:i], args[i+2:]...)
case "--volumes-from":
volumesFrom = append(volumesFrom, args[i+1])
args = append(args[:i], args[i+2:]...)
default:
done = true
}
}
if len(args) < 2 {
cmdUsage("run-container", `[options] <image> <cmd> [[<cmd-options>] <cmd-arg1> [<cmd-arg2> ...]]
-e, --env list Set environment variables
--name string Assign a name to the container
--net string Network Mode
--pid string PID namespace to use
--privileged Give extended privileges to this container
--restart string Restart policy to apply when a container exits (default "no")
-v, --volume list Bind mount a volume
--volumes-from list Mount volumes from the specified container(s)
`)
}
image := args[0]
cmds := args[1:]
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
config := docker.Config{Image: image, Env: env, Cmd: cmds}
hostConfig := docker.HostConfig{NetworkMode: net, PidMode: pid, Privileged: privileged, RestartPolicy: restart, Binds: volumes, VolumesFrom: volumesFrom}
container, err := c.CreateContainer(docker.CreateContainerOptions{Name: name, Config: &config, HostConfig: &hostConfig})
if err != nil {
return fmt.Errorf("unable to create container: %s", err)
}
err = c.StartContainer(container.ID, &hostConfig)
if err != nil {
return fmt.Errorf("unable to start container: %s", err)
}
fmt.Print(container.ID)
return nil
}
func listContainers(args []string) error {
if len(args) > 1 {
cmdUsage("list-containers", "[<label>]")
}
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
opts := docker.ListContainersOptions{All: true}
if len(args) == 1 {
label := args[0]
opts.Filters = map[string][]string{"label": {label}}
}
containers, err := c.ListContainers(opts)
if err != nil {
return fmt.Errorf("unable to list containers: %s", err)
}
for _, container := range containers {
fmt.Println(container.ID)
}
return nil
}
func stopContainer(args []string) error {
if len(args) < 1 {
cmdUsage("stop-container", "<container-id> [<container-id2> ...]")
}
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
for _, containerID := range args {
err = c.StopContainer(containerID, 10)
if err != nil {
return fmt.Errorf("unable to stop container %s: %s", containerID, err)
}
}
return nil
}
func killContainer(args []string) error {
if len(args) < 1 {
cmdUsage("kill-container", "<container-id> [<container-id2> ...]")
}
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
for _, containerID := range args {
err = c.KillContainer(docker.KillContainerOptions{ID: containerID, Signal: docker.SIGKILL})
if err != nil {
return fmt.Errorf("unable to stop container %s: %s", containerID, err)
}
}
return nil
}
func removeContainer(args []string) error {
if len(args) < 1 {
cmdUsage("remove-container", "[-f | --force] [-v | --volumes] <container-id> [<container-id2> ...]")
}
force := false
volumes := false
for i := 0; i < len(args); {
switch args[i] {
case "--force":
case "-f":
force = true
args = append(args[:i], args[i+1:]...)
case "--volumes":
case "-v":
volumes = true
args = append(args[:i], args[i+1:]...)
default:
i++
}
}
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
for _, containerID := range args {
err = c.RemoveContainer(docker.RemoveContainerOptions{
ID: containerID, Force: force, RemoveVolumes: volumes})
if err != nil {
return fmt.Errorf("unable to stop container %s: %s", containerID, err)
}
}
return nil
}
+54
View File
@@ -0,0 +1,54 @@
// Get/set arbitrary flags in the Weave Net persistence DB
package main
import (
"fmt"
"github.com/weaveworks/weave/db"
)
const dbFlagPrefix = "flag:"
func getDBFlag(args []string) error {
if len(args) != 2 {
cmdUsage("check-db-flag", "<db-prefix> <flag-name>")
}
dbPrefix := args[0]
flagName := args[1]
d, err := db.NewBoltDBReadOnly(dbPrefix)
if err != nil {
return err
}
defer d.Close()
var value string
nameFound, err := d.Load(dbFlagPrefix+flagName, &value)
if err != nil {
return err
}
if !nameFound {
return fmt.Errorf("")
}
fmt.Print(value)
return nil
}
func setDBFlag(args []string) error {
if len(args) != 3 {
cmdUsage("set-db-flag", "<db-prefix> <flag-name> <flag-value>")
}
dbPrefix := args[0]
flagName := args[1]
value := args[2]
d, err := db.NewBoltDB(dbPrefix)
if err != nil {
return err
}
defer d.Close()
err = d.Save(dbFlagPrefix+flagName, value)
if err != nil {
return err
}
return nil
}
-23
View File
@@ -1,23 +0,0 @@
package main
import (
weavenet "github.com/weaveworks/weave/net"
)
func exposeNAT(args []string) error {
if len(args) < 1 {
cmdUsage("expose-nat", "<cidr>...")
}
cidrs, err := parseCIDRs(args)
if err != nil {
return err
}
for _, cidr := range cidrs {
if err := weavenet.ExposeNAT(*cidr); err != nil {
return err
}
}
return nil
}
+14 -20
View File
@@ -4,10 +4,7 @@ package main
import (
"fmt"
"os"
"path/filepath"
"strings"
weavenet "github.com/weaveworks/weave/net"
)
var commands map[string]func([]string) error
@@ -17,7 +14,6 @@ func init() {
"help": help,
"netcheck": netcheck,
"docker-tls-args": dockerTLSArgs,
"create-bridge": createBridge,
"detect-bridge-type": detectBridgeType,
"create-datapath": createDatapath,
"delete-datapath": deleteDatapath,
@@ -26,34 +22,30 @@ func init() {
"remove-plugin-network": removePluginNetwork,
"container-addrs": containerAddrs,
"process-addrs": processAddrs,
"container-id": containerID,
"container-state": containerState,
"container-fqdn": containerFQDN,
"run-container": runContainer,
"list-containers": listContainers,
"stop-container": stopContainer,
"kill-container": killContainer,
"remove-container": removeContainer,
"create-volume-container": createVolumeContainer,
"attach-container": attach,
"detach-container": detach,
"configure-arp": configureARP,
"check-iface": checkIface,
"del-iface": delIface,
"setup-iface": setupIface,
"setup-iface-addrs": setupIfaceAddrs,
"list-netdevs": listNetDevs,
"cni-net": cniNet,
"cni-ipam": cniIPAM,
"expose-nat": exposeNAT,
"bridge-ip": bridgeIP,
"unique-id": uniqueID,
"swarm-manager-peers": swarmManagerPeers,
"is-docker-plugin-enabled": isDockerPluginEnabled,
"rewrite-etc-hosts": rewriteEtcHosts,
"get-db-flag": getDBFlag,
"set-db-flag": setDBFlag,
}
}
func main() {
// force re-exec of this binary
selfPath, err := filepath.EvalSymlinks("/proc/self/exe")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
weavenet.WeaveUtilCmd = selfPath
// If no args passed, act as CNI plugin based on executable name
switch {
case len(os.Args) == 1 && strings.HasSuffix(os.Args[0], "weave-ipam"):
@@ -75,7 +67,9 @@ func main() {
os.Exit(1)
}
if err := cmd(os.Args[2:]); err != nil {
fmt.Fprintln(os.Stderr, err)
if err.Error() != "" {
fmt.Fprintln(os.Stderr, err)
}
os.Exit(1)
}
}
-141
View File
@@ -1,141 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/j-keck/arping"
"github.com/vishvananda/netlink"
weavenet "github.com/weaveworks/weave/net"
)
// checkIface returns an error if the given interface cannot be found.
func checkIface(args []string) error {
if len(args) != 1 {
cmdUsage("check-iface", "<iface-name>")
}
ifaceName := args[0]
if _, err := netlink.LinkByName(ifaceName); err != nil {
return err
}
return nil
}
func delIface(args []string) error {
if len(args) != 1 {
cmdUsage("del-iface", "<iface-name>")
}
ifName := args[0]
link, err := netlink.LinkByName(ifName)
if err != nil {
return err
}
return netlink.LinkDel(link)
}
// setupIface renames the given iface and configures its ARP cache settings.
func setupIface(args []string) error {
if len(args) != 2 {
cmdUsage("setup-iface", "<iface-name> <new-iface-name>")
}
ifaceName := args[0]
newIfName := args[1]
return weavenet.SetupIface(ifaceName, newIfName)
}
// setupIfaceAddrs sets up addresses on an interface. It expects to be called inside the container's netns.
func setupIfaceAddrs(args []string) error {
if len(args) < 1 {
cmdUsage("setup-iface-addrs", "<iface-name> <with-multicast> <cidr>...")
}
link, err := netlink.LinkByName(args[0])
if err != nil {
return err
}
withMulticastRoute, err := strconv.ParseBool(args[1])
if err != nil {
return err
}
cidrs, err := parseCIDRs(args[2:])
if err != nil {
return err
}
return weavenet.SetupIfaceAddrs(link, withMulticastRoute, cidrs)
}
func configureARP(args []string) error {
if len(args) != 2 {
cmdUsage("configure-arp", "<iface-name-prefix> <root-path>")
}
prefix := args[0]
rootPath := args[1]
links, err := netlink.LinkList()
if err != nil {
return err
}
for _, link := range links {
ifName := link.Attrs().Name
if strings.HasPrefix(ifName, prefix) {
weavenet.ConfigureARPCache(rootPath+"/proc", ifName)
if addrs, err := netlink.AddrList(link, netlink.FAMILY_V4); err == nil {
for _, addr := range addrs {
arping.GratuitousArpOverIfaceByName(addr.IPNet.IP, ifName)
}
}
}
}
return nil
}
// listNetDevs outputs network ifaces identified by the given indexes
// in the format of weavenet.Dev.
func listNetDevs(args []string) error {
if len(args) == 0 {
cmdUsage("list-netdevs", "<iface-index>[ <iface-index>]")
}
indexes := make(map[int]struct{})
for _, index := range args {
if index != "" {
id, err := strconv.Atoi(index)
if err != nil {
return err
}
indexes[id] = struct{}{}
}
}
links, err := netlink.LinkList()
if err != nil {
return err
}
var netdevs []weavenet.Dev
for _, link := range links {
if _, found := indexes[link.Attrs().Index]; found {
netdev, err := weavenet.LinkToNetDev(link)
if err != nil {
return err
}
netdevs = append(netdevs, netdev)
}
}
nds, err := json.Marshal(netdevs)
if err != nil {
return err
}
fmt.Println(string(nds))
return nil
}
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"strings"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
docker "github.com/fsouza/go-dockerclient"
)
@@ -58,7 +59,7 @@ func isDockerPluginEnabled(args []string) error {
ctx := context.Background()
plugins, err := c.PluginList(ctx)
plugins, err := c.PluginList(ctx, filters.Args{})
if err != nil {
return err
}
+42
View File
@@ -0,0 +1,42 @@
package main
import (
"fmt"
docker "github.com/fsouza/go-dockerclient"
)
func createVolumeContainer(args []string) error {
if len(args) < 3 {
cmdUsage("create-volume-container", "<name> <image-name-or-id> <label> [<bind-mount1> <bind-mount2> ...]")
}
containerName := args[0]
image := args[1]
label := args[2]
bindMounts := args[3:]
c, err := docker.NewVersionedClientFromEnv("1.18")
if err != nil {
return fmt.Errorf("unable to connect to docker: %s", err)
}
container, err := c.InspectContainer(containerName)
if err == nil {
fmt.Println("volume container already exists " + containerName + ":" + container.ID)
return nil
}
volumes := make(map[string]struct{})
for _, m := range bindMounts {
volumes[m] = struct{}{}
}
labels := map[string]string{label: ""}
config := docker.Config{Image: image, Volumes: volumes, Labels: labels, Entrypoint: []string{"data-only"}}
hostConfig := docker.HostConfig{}
_, err = c.CreateContainer(docker.CreateContainerOptions{Name: containerName, Config: &config, HostConfig: &hostConfig})
if err != nil {
return fmt.Errorf("unable to create container: %s", err)
}
return nil
}
+3 -3
View File
@@ -68,11 +68,11 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
if err != nil {
return err
}
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
if err := i.setHostname(container, hostname, dnsDomain); err != nil {
if !i.proxy.WithoutDNS {
if err := i.setHostname(container, hostname, i.proxy.DNSDomain); err != nil {
return err
}
if err := i.proxy.setWeaveDNS(hostConfig, hostname, dnsDomain); err != nil {
if err := i.proxy.setWeaveDNS(hostConfig, hostname, i.proxy.DNSDomain); err != nil {
return err
}
}
+3 -20
View File
@@ -60,8 +60,9 @@ type Config struct {
NoDefaultIPAM bool
NoRewriteHosts bool
TLSConfig TLSConfig
Version string
WithoutDNS bool
DNSListenAddress string
DNSDomain string
NoMulticastRoute bool
KeepTXOn bool
DockerBridge string
@@ -79,7 +80,6 @@ type Proxy struct {
Config
client *weavedocker.Client
weave *weaveapi.Client
dockerBridgeIP string
hostnameMatchRegexp *regexp.Regexp
weaveWaitVolume string
weaveWaitNoopVolume string
@@ -159,15 +159,6 @@ func NewProxy(c Config) (*Proxy, error) {
Log.Info(p.client.Info())
if !p.WithoutDNS {
ip, err := weavenet.FindBridgeIP(c.DockerBridge, nil)
if err != nil {
return nil, err
}
p.dockerBridgeIP = ip.String()
Log.Infof("Using docker bridge IP for DNS: %v", p.dockerBridgeIP)
}
p.hostnameMatchRegexp, err = regexp.Compile(c.HostnameMatch)
if err != nil {
err := fmt.Errorf("Incorrect hostname match '%s': %s", c.HostnameMatch, err.Error())
@@ -596,7 +587,7 @@ func (proxy *Proxy) setWeaveDNS(hostConfig jsonObject, hostname, dnsDomain strin
if err != nil {
return err
}
hostConfig["Dns"] = append(dns, proxy.dockerBridgeIP)
hostConfig["Dns"] = append(dns, proxy.DNSListenAddress)
dnsSearch, err := hostConfig.StringArray("DnsSearch")
if err != nil {
@@ -613,14 +604,6 @@ func (proxy *Proxy) setWeaveDNS(hostConfig jsonObject, hostname, dnsDomain strin
return nil
}
func (proxy *Proxy) getDNSDomain() string {
if proxy.WithoutDNS {
return ""
}
domain, _ := proxy.weave.DNSDomain()
return domain
}
func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error {
containerID, err := container.String("Id")
if err != nil {
+2 -2
View File
@@ -50,8 +50,8 @@ func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
return err
}
}
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, dnsDomain); err != nil {
if !i.proxy.WithoutDNS {
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, i.proxy.DNSDomain); err != nil {
return err
}
}
+19
View File
@@ -5,7 +5,10 @@ import (
"net/http"
"github.com/gorilla/mux"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/net"
"github.com/weaveworks/weave/net/address"
)
func (router *NetworkRouter) HandleHTTP(muxRouter *mux.Router) {
@@ -26,4 +29,20 @@ func (router *NetworkRouter) HandleHTTP(muxRouter *mux.Router) {
router.ForgetConnections(r.Form["peer"])
})
muxRouter.Methods("POST").Path("/expose/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
cidr, err := address.ParseCIDR(vars["ip"] + "/" + vars["prefixlen"])
if err != nil {
http.Error(w, fmt.Sprint("unable to parse ip addr: ", err.Error()), http.StatusBadRequest)
return
}
if err = net.Expose(router.BridgeConfig.WeaveBridgeName, cidr.IPNet(), router.BridgeConfig.AWSVPC, router.BridgeConfig.NPC); err != nil {
http.Error(w, fmt.Sprint("unable to expose: ", err.Error()), http.StatusInternalServerError)
return
}
w.WriteHeader(204)
})
}
+6 -4
View File
@@ -11,6 +11,7 @@ import (
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/db"
weavenet "github.com/weaveworks/weave/net"
)
const (
@@ -47,11 +48,12 @@ type PacketLogging interface {
type NetworkRouter struct {
*mesh.Router
NetworkConfig
weavenet.BridgeConfig
Macs *MacCache
db db.DB
}
func NewNetworkRouter(config mesh.Config, networkConfig NetworkConfig, name mesh.PeerName, nickName string, overlay NetworkOverlay, db db.DB) (*NetworkRouter, error) {
func NewNetworkRouter(config mesh.Config, networkConfig NetworkConfig, bridgeConfig weavenet.BridgeConfig, name mesh.PeerName, nickName string, overlay NetworkOverlay, db db.DB) (*NetworkRouter, error) {
if overlay == nil {
overlay = NullNetworkOverlay{}
}
@@ -63,12 +65,12 @@ func NewNetworkRouter(config mesh.Config, networkConfig NetworkConfig, name mesh
if err != nil {
return nil, err
}
router := &NetworkRouter{Router: meshRouter, NetworkConfig: networkConfig, db: db}
router := &NetworkRouter{Router: meshRouter, NetworkConfig: networkConfig, BridgeConfig: bridgeConfig, db: db}
router.Peers.OnInvalidateShortIDs(overlay.InvalidateShortIDs)
router.Routes.OnChange(overlay.InvalidateRoutes)
router.Macs = NewMacCache(macMaxAge,
func(mac net.HardwareAddr, peer *mesh.Peer) {
log.Println("Expired MAC", mac, "at", peer)
log.Debugln("Expired MAC", mac, "at", peer)
})
router.Peers.OnGC(func(peer *mesh.Peer) { router.Macs.Delete(peer) })
return router, nil
@@ -90,7 +92,7 @@ func (router *NetworkRouter) handleCapturedPacket(key PacketKey) FlowOp {
switch newSrcMac, conflictPeer := router.Macs.Add(srcMac, router.Ourself.Peer); {
case newSrcMac:
log.Println("Discovered local MAC", srcMac)
log.Debugln("Discovered local MAC", srcMac)
case conflictPeer != nil:
// The MAC cache has an entry for the source MAC
// associated with another peer. This probably means
+1 -1
View File
@@ -493,7 +493,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder, broadcast bo
// non-broadcast frames can be broadcast, if the
// destination MAC was not in our MAC cache.
if broadcast {
log.Print(fwd.logPrefix(), "dropping too big DF broadcast frame (", dec.IP.SrcIP, " -> ", dec.IP.DstIP, "): MTU=", mtu)
log.Print(fwd.logPrefix(), "dropping too big DF broadcast frame: len ", len(frame), " (", dec.IP.SrcIP, " -> ", dec.IP.DstIP, "): MTU=", mtu)
return
}
+17 -15
View File
@@ -6,27 +6,28 @@ search_type: Documentation
You only need to build Weave Net if you want to work on the Weave Net codebase
(or you just enjoy building software).
Apart from the `weave` shell script, weave is delivered as a set of
Apart from the `weave` shell script, Weave Net is delivered as a set of
container images. There is no distribution-specific packaging, so in
principle it shouldn't matter which Linux distribution you build
under. But naturally, Docker is a prerequisite (version 1.6.0 or
later).
The only way to build is by using the the build container; the
Makefile is setup to make this transparent. This method is
`Makefile` is setup to make this transparent. This method is
documented below, and can be run directly on your machine or using
a Vagrant VM.
## <a name="ubuntu"></a>Building directly on your machine
The weave git repository should be cloned into
`$GOPATH/src/github.com/weaveworks/weave`, in accordance with [the go
`$GOPATH/src/github.com/weaveworks/weave`, in accordance with [the Go
workspace conventions](https://golang.org/doc/code.html#Workspaces):
```
$ WEAVE=github.com/weaveworks/weave
$ git clone https://$WEAVE $GOPATH/src/$WEAVE
$ cd $GOPATH/src/$WEAVE
$ git submodule update --init
```
Next install Docker if you haven't already, by following the instructions
@@ -44,7 +45,7 @@ On a fresh repository, the Makefile will do the following:
- build the weave components in the build container
- package them into two Docker images (`weaveworks/weave`,
`weaveworks/weaveexec`)
- Exported these images as `weave.tar.gz`
- export these images as `weave.tar.gz`.
The first two steps may take a while - don't worry, they are
are cached and should not need to be redone very often.
@@ -63,18 +64,19 @@ First, check out the code:
```
$ git clone https://github.com/weaveworks/weave
$ cd weave
$ git submodule update --init
```
The `Vagrantfile` in the top directory constructs a VM that has
The `Vagrantfile` in the top directory constructs a VM that has:
* docker installed
* go tools installed
* weave dependencies installed
* $GOPATH set to ~
* Docker installed
* Go tools installed
* Weave's dependencies installed
* `$GOPATH` set to `~`
* the local working directory mapped as a synced folder into the
right place in $GOPATH
  right place in `$GOPATH`.
Once you are in the working directory you can issue
Once you are in the working directory you can issue:
```
$ vagrant up
@@ -86,7 +88,7 @@ installation is done just once). The working directory is sync'ed with
use git and so on in the regular filesystem.
To build and run the code, you need to use the VM. To log in and build
the weave image, do
the weave image, do:
```
$ vagrant ssh
@@ -94,7 +96,7 @@ vm$ cd src/github.com/weaveworks/weave
vm$ make
```
The Docker daemon is also running in this VM, so you can then do
The Docker daemon is also running in this VM, so you can then do:
```
vm$ sudo ./weave launch
@@ -104,7 +106,7 @@ vm$ sudo docker ps
and so on.
If you are looking to just do a build and not run anything on this VM,
you can do so with
you can do so with:
```
$ vagrant ssh -c 'make -C src/github.com/weaveworks/weave'
@@ -112,7 +114,7 @@ $ vagrant ssh -c 'make -C src/github.com/weaveworks/weave'
you should then find a `weave.tar.gz` container snapshot tarball in the
top-level directory. You can use that snapshot with `docker load`
against a different host, e.g.
against a different host, e.g.:
```
$ export DOCKER_HOST=tcp://<HOST:PORT>
+14 -1
View File
@@ -40,6 +40,18 @@ A simple way to accomplish this would be to run Weave on the host and then run,
Yet another option is to expose a port from the container on host B and then connect to it. You can read about exposing ports in [Exporting Services](/site/tasks/manage/service-management.md#exporting).
<a name="duplicate-peer"></a>
**Q: Why am I seeing "peer names collision" and failed connections?**
This sometimes happens when machines are cloned; we require each
machine in your cluster to have a unique identity.
For more information see [Peer Names](/site/operational-guide/concepts.md#peer-name).
Depending on your Linux distribution you may need to [set up
machine-id](https://www.freedesktop.org/software/systemd/man/machine-id.html)
or [generate a dbus id](https://dbus.freedesktop.org/doc/dbus-uuidgen.1.html).
<a name="duplicate-ip"></a>
**Q: Why am I seeing the same IP address assigned to two different containers on different hosts?**
@@ -92,7 +104,8 @@ Yes, of course! Weave allows you to run isolated networks and still allow open
You must permit traffic to flow through TCP 6783 and UDP 6783/6784,
which are Weave’s control and data ports.
The daemon also uses TCP port 6782 for [metrics](/site/tasks/manage/metrics.md), but
The daemon also uses TCP 6781/6782 for
[metrics](/site/tasks/manage/metrics.md#metrics-endpoint-addresses), but
you would only need to open up this port if you wish to collect metrics
from another host.
+1 -1
View File
@@ -4,7 +4,7 @@ menu_order: 30
search_type: Documentation
---
Install Weave Net from the command line on its own or if you are using Docker, Kubernetes or Mesosphere as a Docker or a CNI plugin. Weave Net can also be launched it as a cloud agent within Weave Cloud to visualize and troubleshoot peer connections.
Install Weave Net from the command line on its own or if you are using Docker, Kubernetes or Mesosphere as a Docker or a CNI plugin. Weave Net can also be launched as a cloud agent within Weave Cloud to visualize and troubleshoot peer connections.
## Installing Weave Net Stand-alone and in Weave Cloud
+2 -2
View File
@@ -8,7 +8,7 @@ search_type: Documentation
The Weave Net legacy plugin actually provides *two* network drivers to Docker -
one named `weavemesh` that can operate without a cluster store and another one
named `weave` that can only work with one (like Docker's overlay driver), while
the V2 plugin provides *one* - `store/weaveworks/net-plugin:latest_release`
the V2 plugin provides *one* - `weaveworks/net-plugin:latest_release`
operating only in swarm mode.
### weavemesh driver
@@ -41,7 +41,7 @@ The plugin accepts the following options via `docker network create ... --opt`:
network created when the plugin is first launched has the multicast
option turned on, but for any networks you create it defaults to off.
### store/weaveworks/net-plugin:latest_release driver
### weaveworks/net-plugin:latest_release driver
* The driver runs within the plugin V2.
* Requires Docker to run in [swarm mode](https://docs.docker.com/engine/swarm/swarm-mode/).
+7 -7
View File
@@ -9,7 +9,7 @@ search_type: Documentation
* [Running Services or Containers Using the Plugin](#usage)
Docker Engine version 1.12 introduced [a new plugin system (V2)](https://docs.docker.com/engine/extend/).
This document describes how to use [the Network Plugin V2 of Weave Net](https://store.docker.com/plugins/weave-net-plugin).
This document describes how to use the Network Plugin V2 of Weave Net.
Before using the plugin, please keep in mind the plugin works only in Swarm
mode and requires Docker version 1.13 or later.
@@ -19,7 +19,7 @@ mode and requires Docker version 1.13 or later.
To install the plugin run the following command on _each_ host already
participating in a Swarm cluster, i.e. on all master and worker nodes:
$ docker plugin install store/weaveworks/net-plugin:latest_release
$ docker plugin install weaveworks/net-plugin:latest_release
Docker will pull the plugin from Docker Store, and it will ask to grant
privileges before installing the plugin. Afterwards, it will start `weaver`
@@ -29,7 +29,7 @@ process which will try to connect to Swarm masters running Weave Net.
There are several configuration parameters which can be set with:
$ docker plugin set store/weaveworks/net-plugin:latest_release PARAM=VALUE
$ docker plugin set weaveworks/net-plugin:latest_release PARAM=VALUE
The parameters include:
@@ -49,22 +49,22 @@ The parameters include:
Before setting any parameter, the plugin has to be disabled with:
$ docker plugin disable store/weaveworks/net-plugin:latest_release
$ docker plugin disable weaveworks/net-plugin:latest_release
To re-enable the plugin run the following command:
$ docker plugin enable store/weaveworks/net-plugin:latest_release
$ docker plugin enable weaveworks/net-plugin:latest_release
### <a name="usage"></a>Running Services or Containers Using the Plugin
After you have launched the plugin, you can create a network for Docker Swarm
services by running the following command on any Docker Swarm master node:
$ docker network create --driver=store/weaveworks/net-plugin:latest_release mynetwork
$ docker network create --driver=weaveworks/net-plugin:latest_release mynetwork
Or you can create a network for any Docker container with:
$ docker network create --driver=store/weaveworks/net-plugin:latest_release --attachable mynetwork
$ docker network create --driver=weaveworks/net-plugin:latest_release --attachable mynetwork
To start a service attached to the network run, for example:
+106 -16
View File
@@ -7,18 +7,26 @@ search_type: Documentation
The following topics are discussed:
* [Installation](#install)
* [Upgrading Kubernetes to version 1.6](#kube-1.6-upgrade)
* [Upgrading the Daemon Sets](#daemon-sets)
* [CPU and Memory Requirements](#resources)
* [Pod Eviction](#eviction)
* [Network Policy Controller](#npc)
* [Upgrading Kubernetes to version 1.6](#kube-1.6-upgrade)
* [Upgrading the Daemon Sets](#daemon-sets)
* [CPU and Memory Requirements](#resources)
* [Pod Eviction](#eviction)
* [Features](#features)
* [Pod Network](#pod-network)
* [Network Policy](#npc)
* [Troubleshooting](#troubleshooting)
* [Troubleshooting Blocked Connections](#blocked-connections)
* [Reading the logs](#logs)
* [Troubleshooting Blocked Connections](#blocked-connections)
* [Things to watch out for](#key-points)
* [Changing Configuration Options](#configuration-options)
## <a name="install"></a> Installation
*Before installing Weave Net, you should make sure the following ports are not
blocked by your firewall: TCP 6783 and UDP 6783/6784.
For more details, see the [FAQ](/site/faq.md#ports).*
Weave Net can be installed onto your CNI-enabled Kubernetes cluster
with a single command:
@@ -146,16 +154,33 @@ mypod-09vkd 0/1 Evicted 0 1h <none> node-1
If you see this in your cluster, consider some of the above steps to
reduce disruption.
## <a name="npc"></a>Network Policy Controller
## <a name="features"></a>Features
The addon also supports the [Kubernetes policy
API](http://kubernetes.io/docs/user-guide/networkpolicies/) so that
you can securely isolate pods from each other based on namespaces and
### <a name="pod-network"></a>Pod Network
Weave Net provides a network to connect all pods together,
implementing the [Kubernetes
model](https://kubernetes.io/docs/concepts/cluster-administration/networking/#kubernetes-model).
Kubernetes uses the _Container Network Interface_
([CNI](https://github.com/containernetworking/cni)) to join pods onto Weave Net.
Kubernetes implements many network features itself on top of the pod
network. This includes
[Services](https://kubernetes.io/docs/concepts/services-networking/service/),
[Service Discovery via DNS](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/)
and [Ingress into the cluster](https://kubernetes.io/docs/concepts/services-networking/ingress/).
WeaveDNS is disabled when using the Kubernetes addon.
### <a name="npc"></a>Network Policy
[Kubernetes Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) let
you securely isolate pods from each other based on namespaces and
labels. For more information on configuring network policies in
Kubernetes see the
[walkthrough](http://kubernetes.io/docs/getting-started-guides/network-policy/walkthrough/)
[walkthrough](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/)
and the [NetworkPolicy API object
definition](http://kubernetes.io/docs/api-reference/extensions/v1beta1/definitions/#_v1beta1_networkpolicy).
definition](https://v1-7.docs.kubernetes.io/docs/api-reference/v1.7/#networkpolicy-v1-networking)
**Note:** as of version 1.9 of Weave Net, the Network Policy
Controller allows all multicast traffic. Since a single multicast
@@ -166,7 +191,46 @@ definition](http://kubernetes.io/docs/api-reference/extensions/v1beta1/definitio
## <a name="troubleshooting"></a> Troubleshooting
The status of Weave Net can be checked by running its CLI commands. This can be done in various ways:
The first thing to check is whether Weave Net is up and
running. The `kubectl apply` command you used to install it only
_requests_ that it be downloaded and started; if anything goes wrong
at startup, those details will only be visible in the [logs](#logs) of
the container(s).
To check what is running:
```
$ kubectl get pods -n kube-system -l name=weave-net
NAME READY STATUS RESTARTS AGE
weave-net-1jkl6 2/2 Running 0 1d
weave-net-bskbv 2/2 Running 0 1d
weave-net-m4x1b 2/2 Running 0 1d
```
You should see one line for each node in your cluster; each line
should have STATUS "Running", and READY should be 2 out of 2. If you
see a STATUS like "Error" or "CrashLoopBackoff", look in the logs of
the container with that status.
### <a name="logs"></a> Reading the logs
Pick one of the pods from the list output by `kubectl get pods` and
ask for the logs like this:
```
$ kubectl logs -n kube-system weave-net-1jkl6 weave
```
For easier viewing, pipe the output into a file , especially if
it is long.
Many Kubernetes network issues occur at a higher level than Weave Net.
The [Kubernetes Service Debugging Guide]
(https://kubernetes.io/docs/tasks/debug-application-cluster/debug-service/)
has a detailed step-by-step guide.
Once it is up and running, the status of Weave Net can be checked by
running its CLI commands. This can be done in various ways:
1\. [Install the `weave` script](/site/installing-weave.md) and run:
@@ -270,6 +334,23 @@ TCP connection from 10.32.0.7:56648 to 10.32.0.11:80 blocked by Weave NPC.
UDP connection from 10.32.0.7:56648 to 10.32.0.11:80 blocked by Weave NPC.
```
### <a name="key-points"></a> Things to watch out for
- Don't turn on `--masquerade-all` on kube-proxy: this will change the
source address of every pod-to-pod conversation which will make it
impossible to correctly enforce network policies that restrict which
pods can talk.
- If you do set the `--cluster-cidr` option on kube-proxy, make sure
it matches the `IPALLOC_RANGE` given to Weave Net (see below).
- IP forwarding must be enabled on each node, in order for pods to
access Kubernetes services or other IP addresses on another
network. Check this with `sysctl net.ipv4.ip_forward`; the result
should be `1`. (Be aware that there can be security implications of
enabling IP forwarding).
- Weave Net can be run on minikube v0.28 or later with the default CNI config shipped with minikube
being disabled. See [#3124](https://github.com/weaveworks/weave/issues/3124#issuecomment-397820940)
for more details.
## <a name="configuration-options"></a> Changing Configuration Options
#### Using `cloud.weave.works`
@@ -277,11 +358,11 @@ UDP connection from 10.32.0.7:56648 to 10.32.0.11:80 blocked by Weave NPC.
You can customise the YAML you get from `cloud.weave.works` by passing some of Weave Net's options, arguments and environment variables as query parameters:
- `version`: Weave Net's version. Default: `latest`, i.e. latest release. *N.B.*: This only changes the specified version inside the generated YAML file, it does not ensure that the rest of the YAML is compatible with that version. To freeze the YAML version save a copy of the YAML file from the [release page](https://github.com/weaveworks/weave/releases) and use that copy instead of downloading it each time from `cloud.weave.works`.
- `password-secret`: name of the Kubernetes secret containing your password.
- `password-secret`: name of the Kubernetes secret containing your password. *N.B*: The Kubernetes secret name must correspond to a name of a file containing your password.
Example:
$ echo "s3cr3tp4ssw0rd" > /var/lib/weave/weave-passwd.txt
$ kubectl create secret -n kube-system generic weave-passwd --from-file=/var/lib/weave/weave-passwd.txt
$ echo "s3cr3tp4ssw0rd" > /var/lib/weave/weave-passwd
$ kubectl create secret -n kube-system generic weave-passwd --from-file=/var/lib/weave/weave-passwd
$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')&password-secret=weave-passwd"
- `known-peers`: comma-separated list of hosts. Default: empty.
@@ -294,6 +375,8 @@ The list of variables you can set is:
* `CHECKPOINT_DISABLE` - if set to 1, disable checking for new Weave Net
versions (default is blank, i.e. check is enabled)
* `CONN_LIMIT` - soft limit on the number of connections between
peers. Defaults to 30.
* `HAIRPIN_MODE` - Weave Net defaults to enabling hairpin on the bridge side of
the `veth` pair for containers attached. If you need to disable hairpin, e.g. your
kernel is one of those that can panic if hairpin is enabled, then you can disable it
@@ -309,11 +392,18 @@ The list of variables you can set is:
* `WEAVE_EXPOSE_IP` - set the IP address used as a gateway from the
Weave network to the host network - this is useful if you are
configuring the addon as a static pod.
* `WEAVE_METRICS_ADDR` - address and port that the Weave Net
daemon will serve Prometheus-style metrics on (defaults to 0.0.0.0:6782)
* `WEAVE_STATUS_ADDR` - address and port that the Weave Net
daemon will serve status requests on (defaults to disabled)
* `WEAVE_MTU` - Weave Net defaults to 1376 bytes, but you can set a
smaller size if your underlying network has a tighter limit, or set
a larger size for better performance if your network supports jumbo
frames - see [here](/site/tasks/manage/fastdp.md#mtu) for more
details.
* `NO_MASQ_LOCAL` - set to 1 to preserve the client source IP address when
accessing Service annotated with `service.spec.externalTrafficPolicy=Local`.
The feature works only with Weave IPAM (default).
Example:
```
+1 -1
View File
@@ -39,7 +39,7 @@ You do not have to keep track of and specify the addresses
of other dynamic peers in `$PEERS` - they will discover and connect to
each other via the fixed cluster.
>>**Note:** The use of `--ipalloc-init=observer` prevents dynamic peers from
>**Note:** The use of `--ipalloc-init=observer` prevents dynamic peers from
coming to a consensus on their own - this is important to stop a
clique forming amongst a group of dynamically added peers if they
become partitioned from the fixed cluster after having learned about
+1 -1
View File
@@ -99,7 +99,7 @@ To minimize downtime while the new script is pulling the new container images:
* Start the new Weave Net with `weave launch <existing peer list>` (or
`systemctl start weave` if you're using a systemd unit file)
>>**Note:** Always check the Release Notes for specific versions in case
>**Note:** Always check the Release Notes for specific versions in case
there are any special caveats or deviations from the standard
procedure.
Loaded 100 of 3021 files, more files were not shown because too many files have changed in this diff. Show more