Compare commits

...
241 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 192e5a1f79 Merge branch '2.1' 2017-12-04 13:51:30 +00:00
Bryan Boreham 692bccc4fc Merge branch '2.1' 2017-11-27 15:03:48 +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 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 a3fd36e2bb Update k8s netpol docs
- Mention `--use-legacy-netpol` flag.
- Link to NetworkPolicy from 1.7.
2017-11-16 17:00:27 +02:00
3009 changed files with 948028 additions and 5796 deletions

No files matched your search

+3 -2
View File
@@ -46,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
@@ -68,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
-177
View File
@@ -1,180 +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
[submodule "vendor/k8s.io/api"]
path = vendor/k8s.io/api
url = https://github.com/kubernetes/api
[submodule "vendor/k8s.io/apimachinery"]
path = vendor/k8s.io/apimachinery
url = https://github.com/kubernetes/apimachinery
[submodule "vendor/github.com/PuerkitoBio/purell"]
path = vendor/github.com/PuerkitoBio/purell
url = https://github.com/PuerkitoBio/purell
[submodule "vendor/github.com/PuerkitoBio/urlesc"]
path = vendor/github.com/PuerkitoBio/urlesc
url = https://github.com/PuerkitoBio/urlesc
[submodule "vendor/github.com/emicklei/go-restful"]
path = vendor/github.com/emicklei/go-restful
url = https://github.com/emicklei/go-restful
[submodule "vendor/github.com/go-openapi/jsonpointer"]
path = vendor/github.com/go-openapi/jsonpointer
url = https://github.com/go-openapi/jsonpointer
[submodule "vendor/github.com/go-openapi/jsonreference"]
path = vendor/github.com/go-openapi/jsonreference
url = https://github.com/go-openapi/jsonreference
[submodule "vendor/github.com/go-openapi/spec"]
path = vendor/github.com/go-openapi/spec
url = https://github.com/go-openapi/spec
[submodule "vendor/github.com/go-openapi/swag"]
path = vendor/github.com/go-openapi/swag
url = https://github.com/go-openapi/swag
[submodule "vendor/github.com/golang/glog"]
path = vendor/github.com/golang/glog
url = https://github.com/golang/glog
[submodule "vendor/github.com/google/gofuzz"]
path = vendor/github.com/google/gofuzz
url = https://github.com/google/gofuzz
[submodule "vendor/github.com/mailru/easyjson"]
path = vendor/github.com/mailru/easyjson
url = https://github.com/mailru/easyjson
[submodule "vendor/k8s.io/kube-openapi"]
path = vendor/k8s.io/kube-openapi
url = https://github.com/kubernetes/kube-openapi
[submodule "vendor/golang.org/x/text"]
path = vendor/golang.org/x/text
url = https://go.googlesource.com/text
[submodule "vendor/gopkg.in/yaml.v2"]
path = vendor/gopkg.in/yaml.v2
url = https://gopkg.in/yaml.v2
+129
View File
@@ -1,3 +1,132 @@
## 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
+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.7.8
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
+20 -23
View File
@@ -101,6 +101,7 @@ 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
@@ -108,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
@@ -179,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
@@ -196,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 \
@@ -220,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)
@@ -234,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:
@@ -274,7 +271,7 @@ endif
$(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 $(SIGPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVER_UPTODATE)
@@ -282,7 +279,7 @@ $(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexe
cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
cp $(WEAVEWAIT_NOMCAST_EXE) prog/weaveexec/weavewait_nomcast
$(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.
@@ -302,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)
@@ -322,7 +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 > $@
tools/.git $(MANIFEST_TOOL_DIR)/.git:
tools/.git:
git submodule update --init
# CODE FOR PUBLISHING THE IMAGES
@@ -378,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:
@@ -398,7 +395,7 @@ clean-bin:
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
+15
View File
@@ -92,6 +92,7 @@ build() {
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"
}
@@ -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"
+1 -1
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
+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
}
+169 -47
View File
@@ -6,12 +6,18 @@ import (
"net"
"path/filepath"
"github.com/Sirupsen/logrus"
"github.com/coreos/go-iptables/iptables"
"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
@@ -47,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 {
@@ -213,6 +220,7 @@ type BridgeConfig struct {
MTU int
Mac string
Port int
NoMasqLocal bool
}
func (config *BridgeConfig) configuredBridgeType() Bridge {
@@ -226,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 {
@@ -245,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")
}
@@ -268,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
}
@@ -288,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 {
@@ -320,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")
@@ -370,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
@@ -394,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)
@@ -436,48 +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 a chain for allowing ingress traffic when the bridge is exposed
_ = ipt.NewChain("filter", "WEAVE-EXPOSE")
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-j", "WEAVE-EXPOSE"); err != nil {
// 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
fwdRules = append(fwdRules, []string{"-i", config.WeaveBridgeName, "!", "-o", config.WeaveBridgeName, "-j", "ACCEPT"})
// and allow replies back
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, "failed to clear/create nat/WEAVE chain")
}
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
}
}
// 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
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
}
// and allow replies back
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"); err != nil {
return err
}
func (t *NoMasqLocalTracker) String() string {
return "no-masq-local"
}
func (t *NoMasqLocalTracker) HandleUpdate(prevRanges, currRanges []address.Range, local bool) error {
if !local {
return nil
}
// create a chain for masquerading
if err = ipt.ClearChain("nat", "WEAVE"); err != nil {
return errors.Wrap(err, "clearing WEAVE chain")
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
}
}
return ipt.AppendUnique("nat", "POSTROUTING", "-j", "WEAVE")
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 {
@@ -487,3 +583,29 @@ func linkSetUpByName(linkName string) error {
}
return netlink.LinkSetUp(link)
}
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, "cannot find bridge %q", config.WeaveBridgeName)
}
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return errors.Wrapf(err, "cannot list IPv4 addrs of bridge %q", config.WeaveBridgeName)
}
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
}
+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"
+18 -2
View File
@@ -1,6 +1,9 @@
package ipset
import (
"crypto/rand"
"encoding/hex"
"fmt"
"log"
"os/exec"
"strings"
@@ -16,6 +19,7 @@ type Type string
const (
ListSet = Type("list:set")
HashIP = Type("hash:ip")
HashNet = Type("hash:net")
)
type Interface interface {
@@ -40,6 +44,7 @@ type entryKey struct {
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:
@@ -47,15 +52,23 @@ type ipset struct {
users map[entryKey]map[types.UID]struct{}
}
func New(logger *log.Logger) Interface {
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
testIpsetName := Name("weave-test-comment")
// 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
@@ -71,6 +84,9 @@ func New(logger *log.Logger) Interface {
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")
}
+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 -20
View File
@@ -13,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)
@@ -28,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)
}
@@ -99,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
}
@@ -116,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
@@ -134,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
@@ -198,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
@@ -214,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 {
@@ -234,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)
+124 -134
View File
@@ -4,173 +4,163 @@ import (
"fmt"
apiv1 "k8s.io/api/core/v1"
extnapi "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"github.com/weaveworks/weave/npc/ipset"
"github.com/weaveworks/weave/net/ipset"
)
// analysePolicyLegacy is used to analyse extensions/v1beta1/NetworkPolicy (legacy) and
// implements pre-1.7 k8s netpol semantics, whilst analysePolicy - networking.k8s.io/v1/NetworkPolicy
// and 1.7 semantics.
func (ns *ns) analysePolicyLegacy(policy *extnapi.NetworkPolicy) (
rules map[string]*ruleSpec,
nsSelectors, podSelectors map[string]*selectorSpec,
err error) {
nsSelectors = make(map[string]*selectorSpec)
podSelectors = make(map[string]*selectorSpec)
rules = make(map[string]*ruleSpec)
dstSelector, err := newSelectorSpec(&policy.Spec.PodSelector, true, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, err
}
podSelectors[dstSelector.key] = dstSelector
for _, ingressRule := range policy.Spec.Ingress {
if ingressRule.Ports != nil && len(ingressRule.Ports) == 0 {
// Ports is empty, this rule matches no ports (no traffic matches).
continue
}
if ingressRule.From != nil && len(ingressRule.From) == 0 {
// From is empty, this rule matches no sources (no traffic matches).
continue
}
if ingressRule.From == nil {
// From is not provided, this rule matches all sources (traffic not restricted by source).
if ingressRule.Ports == nil {
// Ports is not provided, this rule matches all ports (traffic not restricted by port).
rule := newRuleSpec(nil, nil, dstSelector, nil)
rules[rule.key] = rule
} else {
// Ports is present and contains at least one item, then this rule allows traffic
// only if the traffic matches at least one port in the ports list.
withNormalisedProtoAndPortLegacy(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, false, 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, false, "", ipset.ListSet)
if err != nil {
return nil, nil, nil, err
}
nsSelectors[srcSelector.key] = srcSelector
}
if ingressRule.Ports == nil {
// Ports is not provided, this rule matches all ports (traffic not restricted by port).
rule := newRuleSpec(nil, srcSelector, dstSelector, nil)
rules[rule.key] = rule
} else {
// Ports is present and contains at least one item, then this rule allows traffic
// only if the traffic matches at least one port in the ports list.
withNormalisedProtoAndPortLegacy(ingressRule.Ports, func(proto, port string) {
rule := newRuleSpec(&proto, srcSelector, dstSelector, &port)
rules[rule.key] = rule
})
}
}
}
}
return rules, nsSelectors, podSelectors, nil
}
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)
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
dstSelector, err := newSelectorSpec(&policy.Spec.PodSelector, true, ns.name, ipset.HashIP)
targetSelector, err := newSelectorSpec(&policy.Spec.PodSelector, policyTypes, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, err
}
podSelectors[dstSelector.key] = dstSelector
// If ingress is empty then this NetworkPolicy does not allow any traffic
if policy.Spec.Ingress == nil || len(policy.Spec.Ingress) == 0 {
return
return nil, nil, nil, nil, err
}
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
// 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 allSources {
if allPorts {
rule := newRuleSpec(nil, nil, dstSelector, nil)
rules[rule.key] = rule
} else {
withNormalisedProtoAndPort(ingressRule.Ports, func(proto, port string) {
rule := newRuleSpec(&proto, nil, dstSelector, &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, false, ns.name, ipset.HashIP)
if err != nil {
return nil, nil, nil, err
}
podSelectors[srcSelector.key] = srcSelector
} else if peer.NamespaceSelector != nil {
srcSelector, err = newSelectorSpec(peer.NamespaceSelector, false, "", ipset.ListSet)
if err != nil {
return nil, nil, nil, err
}
nsSelectors[srcSelector.key] = srcSelector
}
// 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 allSources {
if allPorts {
rule := newRuleSpec(nil, srcSelector, dstSelector, nil)
rule := newRuleSpec(policyTypeIngress, nil, nil, targetSelector, nil)
rules[rule.key] = rule
} else {
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 withNormalisedProtoAndPortLegacy(npps []extnapi.NetworkPolicyPort, f func(proto, port string)) {
for _, npp := range npps {
f(proto(npp.Protocol), port(npp.Port))
func addIfNotExist(s *selectorSpec, ss map[string]*selectorSpec) {
if _, ok := ss[s.key]; !ok {
ss[s.key] = s
}
}
+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"
+4 -7
View File
@@ -9,7 +9,7 @@ import (
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"
)
@@ -37,19 +37,16 @@ type controller struct {
nss map[string]*ns // ns name -> ns struct
nsSelectors *selectorSet // selector string -> nsSelector
legacy bool // use legacy network policy semantics (k8s pre-1.7)
}
func New(nodeName string, legacy bool, ipt iptables.Interface, ips ipset.Interface) NetworkPolicyController {
func New(nodeName string, ipt iptables.Interface, ips ipset.Interface) NetworkPolicyController {
c := &controller{
nodeName: nodeName,
legacy: legacy,
ipt: ipt,
ips: ips,
nss: make(map[string]*ns)}
doNothing := func(*selector) error { return nil }
doNothing := func(*selector, policyType) error { return nil }
c.nsSelectors = newSelectorSet(ips, c.onNewNsSelector, doNothing, doNothing)
return c
@@ -71,7 +68,7 @@ func (npc *controller) onNewNsSelector(selector *selector) error {
func (npc *controller) withNS(name string, f func(ns *ns) error) error {
ns, found := npc.nss[name]
if !found {
newNs, err := newNS(name, npc.nodeName, npc.legacy, npc.ipt, npc.ips, npc.nsSelectors)
newNs, err := newNS(name, npc.nodeName, npc.ipt, npc.ips, npc.nsSelectors)
if err != nil {
return err
}
+248 -32
View File
@@ -1,12 +1,14 @@
package npc
import (
"fmt"
"log"
"strings"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/weaveworks/weave/npc/ipset"
"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"
@@ -103,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) {
@@ -144,6 +174,7 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
Namespace: "destination",
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
Ingress: []networkingv1.NetworkPolicyIngressRule{
{
From: []networkingv1.NetworkPolicyPeer{
@@ -167,7 +198,7 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
// Namespaces first
m := newMockIPSet()
controller := New("foo", false, &mockIPTables{}, &m)
controller := New("foo", newMockIPTables(), &m)
const (
selectorIPSetName = "weave-I239Zp%sCvoVt*D6u=A!2]YEk"
@@ -183,7 +214,7 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
// NetworkPolicy first
m = newMockIPSet()
controller = New("foo", false, &mockIPTables{}, &m)
controller = New("foo", newMockIPTables(), &m)
controller.AddNetworkPolicy(networkPolicy)
@@ -193,17 +224,18 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
require.Equal(t, true, len(m.sets[selectorIPSetName].subSets[sourceIPSetName]) > 0)
}
// Tests default-allow ipset behavior when running in non-legacy mode.
// Tests default-allow ipset behavior
func TestDefaultAllow(t *testing.T) {
const (
defaultAllowIPSetName = "weave-E.1.0W^NGSp]0_t5WwH/]gX@L"
fooPodIP = "10.32.0.10"
barPodIP = "10.32.0.11"
barPodNewIP = "10.32.0.12"
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", false, &mockIPTables{}, &m)
controller := New("bar", newMockIPTables(), &m)
defaultNamespace := &coreapi.Namespace{
ObjectMeta: metav1.ObjectMeta{
@@ -213,7 +245,8 @@ func TestDefaultAllow(t *testing.T) {
controller.AddNamespace(defaultNamespace)
// Should create an ipset for default-allow
require.Contains(t, m.sets, defaultAllowIPSetName)
require.Contains(t, m.sets, ingressDefaultAllowIPSetName)
require.Contains(t, m.sets, egressDefaultAllowIPSetName)
podFoo := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
@@ -225,7 +258,8 @@ func TestDefaultAllow(t *testing.T) {
controller.AddPod(podFoo)
// Should add the foo pod to default-allow
require.True(t, m.entryExists(defaultAllowIPSetName, fooPodIP))
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
require.True(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
podBar := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
@@ -236,10 +270,12 @@ func TestDefaultAllow(t *testing.T) {
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(defaultAllowIPSetName, barPodIP))
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{
@@ -248,6 +284,10 @@ func TestDefaultAllow(t *testing.T) {
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{{
@@ -256,55 +296,74 @@ func TestDefaultAllow(t *testing.T) {
},
}},
}},
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(defaultAllowIPSetName, fooPodIP))
require.True(t, m.entryExists(defaultAllowIPSetName, barPodIP))
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(defaultAllowIPSetName, barPodIP))
require.True(t, m.entryExists(defaultAllowIPSetName, barPodNewIP))
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(defaultAllowIPSetName, barPodNewIP))
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(defaultAllowIPSetName, fooPodIP))
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(defaultAllowIPSetName, fooPodIP))
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(defaultAllowIPSetName, fooPodIP))
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(defaultAllowIPSetName, fooPodIP))
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 (
defaultAllowIPSetName = "weave-E.1.0W^NGSp]0_t5WwH/]gX@L"
runBarIPSetName = "weave-bZ~x=yBgzH)Ht()K*Uv3z{M]Y"
podIP = "10.32.0.10"
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", false, &mockIPTables{}, &m)
controller := New("qux", newMockIPTables(), &m)
defaultNamespace := &coreapi.Namespace{
ObjectMeta: metav1.ObjectMeta{
@@ -323,7 +382,7 @@ func TestOutOfOrderPodEvents(t *testing.T) {
controller.AddPod(podFoo)
// Should be in default-allow as no netpol selects podFoo
require.True(t, m.entryExists(defaultAllowIPSetName, podIP))
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
netpol := &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
@@ -331,6 +390,7 @@ func TestOutOfOrderPodEvents(t *testing.T) {
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{{
@@ -344,7 +404,7 @@ func TestOutOfOrderPodEvents(t *testing.T) {
controller.AddNetworkPolicy(netpol)
// Shouldn't be in default-allow as netpol above selects podFoo
require.False(t, m.entryExists(defaultAllowIPSetName, podIP))
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
podBar := &coreapi.Pod{
ObjectMeta: metav1.ObjectMeta{
@@ -356,8 +416,8 @@ func TestOutOfOrderPodEvents(t *testing.T) {
controller.AddPod(podBar)
// Should be in default-allow as no netpol selects podBar
require.True(t, m.entryExists(defaultAllowIPSetName, podIP))
require.True(t, m.Exist(podBar.ObjectMeta.UID, defaultAllowIPSetName, podIP))
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))
@@ -368,11 +428,167 @@ func TestOutOfOrderPodEvents(t *testing.T) {
// 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(defaultAllowIPSetName, podIP))
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[defaultAllowIPSetName].subSets))
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
}
+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)
}
}
}
}
+185 -156
View File
@@ -1,7 +1,6 @@
package npc
import (
"encoding/json"
"errors"
"fmt"
@@ -13,7 +12,7 @@ import (
"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"
)
@@ -32,20 +31,20 @@ type ns struct {
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 dst podSelector of
// any netpol; used only in non-legacy mode and is used as a dst in
// the WEAVE-NPC-DEFAULT iptables chain.
defaultAllowIPSet ipset.Name
// 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
legacy bool
}
func newNS(name, nodeName string, legacy bool, ipt iptables.Interface, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
allPods, err := newSelectorSpec(&metav1.LabelSelector{}, false, name, ipset.HashIP)
func newNS(name, nodeName string, ipt iptables.Interface, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
allPods, err := newSelectorSpec(&metav1.LabelSelector{}, nil, name, ipset.HashIP)
if err != nil {
return nil, err
}
@@ -60,19 +59,24 @@ func newNS(name, nodeName string, legacy bool, ipt iptables.Interface, ips ipset
uid: uuid.NewUUID(),
allPods: allPods,
nsSelectors: nsSelectors,
ipBlocks: newIPBlockSet(ips),
rules: newRuleSet(ipt),
legacy: legacy}
ns.podSelectors = newSelectorSet(ips, ns.onNewPodSelector, ns.onNewDstPodSelector, ns.onDestroyDstPodSelector)
if !legacy {
defaultAllowIPSet := ipset.Name(IpsetNamePrefix + shortName("default-allow:"+name))
if err := ips.Create(defaultAllowIPSet, ipset.HashIP); err != nil {
return nil, err
}
ns.defaultAllowIPSet = defaultAllowIPSet
}
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
}
@@ -102,16 +106,13 @@ func (ns *ns) onNewPodSelector(selector *selector) error {
return nil
}
func (ns *ns) onNewDstPodSelector(selector *selector) error {
if ns.legacy {
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, ns.defaultAllowIPSet, pod.Status.PodIP); err != nil {
if err := ns.ips.DelEntry(pod.ObjectMeta.UID, ipset, pod.Status.PodIP); err != nil {
return err
}
}
@@ -121,15 +122,11 @@ func (ns *ns) onNewDstPodSelector(selector *selector) error {
return nil
}
func (ns *ns) onDestroyDstPodSelector(selector *selector) error {
if ns.legacy {
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); err != nil {
if err := ns.addToDefaultAllowIfNoMatching(pod, policyType); err != nil {
return err
}
}
@@ -139,18 +136,19 @@ func (ns *ns) onDestroyDstPodSelector(selector *selector) error {
return nil
}
// Add pod IP addr to default-allow ipset if there are no matching dst selectors
func (ns *ns) addToDefaultAllowIfNoMatching(pod *coreapi.Pod) error {
// 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.dstSelectorExist(s) && s.matches(pod.ObjectMeta.Labels) {
if ns.podSelectors.targetSelectorExist(s, policyType) && s.matches(pod.ObjectMeta.Labels) {
found = true
break
}
}
if !found {
if err := ns.ips.AddEntry(pod.ObjectMeta.UID, ns.defaultAllowIPSet, pod.Status.PodIP, podComment(pod)); err != nil {
ipset := ns.defaultAllowIPSetName(policyType)
if err := ns.ips.AddEntry(pod.ObjectMeta.UID, ipset, pod.Status.PodIP, podComment(pod)); err != nil {
return err
}
}
@@ -175,13 +173,18 @@ func (ns *ns) addPod(obj *coreapi.Pod) error {
ns.ips.AddEntry(obj.ObjectMeta.UID, LocalIpset, obj.Status.PodIP, podComment(obj))
}
found, err := ns.podSelectors.addToMatching(obj.ObjectMeta.UID, 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 dst selectors, add the pod to default-allow
if !ns.legacy && !found {
if err := ns.ips.AddEntry(obj.ObjectMeta.UID, ns.defaultAllowIPSet, obj.Status.PodIP, podComment(obj)); err != nil {
// 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
}
}
@@ -202,10 +205,11 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
ns.ips.DelEntry(oldObj.ObjectMeta.UID, LocalIpset, oldObj.Status.PodIP)
}
if !ns.legacy {
if err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ns.defaultAllowIPSet, oldObj.Status.PodIP); err != nil {
return err
}
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)
@@ -215,13 +219,18 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
if ns.checkLocalPod(newObj) {
ns.ips.AddEntry(newObj.ObjectMeta.UID, LocalIpset, newObj.Status.PodIP, podComment(newObj))
}
found, err := ns.podSelectors.addToMatching(newObj.ObjectMeta.UID, newObj.ObjectMeta.Labels, 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 !ns.legacy && !found {
if err := ns.ips.AddEntry(newObj.ObjectMeta.UID, ns.defaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
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
}
}
@@ -229,17 +238,11 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
return nil
}
if !ns.legacy &&
oldObj.Status.PodIP != newObj.Status.PodIP &&
ns.ips.Exist(oldObj.ObjectMeta.UID, ns.defaultAllowIPSet, oldObj.Status.PodIP) {
// 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 err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ns.defaultAllowIPSet, oldObj.Status.PodIP); err != nil {
if oldObj.Status.PodIP != newObj.Status.PodIP {
if err := ns.updateDefaultAllowIPSetEntry(oldObj, newObj, ns.ingressDefaultAllowIPSet); err != nil {
return err
}
if err := ns.ips.AddEntry(newObj.ObjectMeta.UID, ns.defaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
if err := ns.updateDefaultAllowIPSetEntry(oldObj, newObj, ns.egressDefaultAllowIPSet); err != nil {
return err
}
}
@@ -264,17 +267,11 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
}
}
if !ns.legacy && ns.podSelectors.dstSelectorExist(ps) {
switch {
case !oldMatch && newMatch:
if err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ns.defaultAllowIPSet, oldObj.Status.PodIP); err != nil {
return err
}
case oldMatch && !newMatch:
if err := ns.addToDefaultAllowIfNoMatching(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
}
}
}
@@ -282,6 +279,23 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
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)
@@ -293,10 +307,11 @@ func (ns *ns) deletePod(obj *coreapi.Pod) error {
ns.ips.DelEntry(obj.ObjectMeta.UID, LocalIpset, obj.Status.PodIP)
}
if !ns.legacy {
if err := ns.ips.DelEntry(obj.ObjectMeta.UID, ns.defaultAllowIPSet, obj.Status.PodIP); err != nil {
return err
}
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)
@@ -305,7 +320,7 @@ func (ns *ns) deletePod(obj *coreapi.Pod) error {
func (ns *ns) addNetworkPolicy(obj interface{}) error {
// Analyse policy, determine which rules and ipsets are required
uid, rules, nsSelectors, podSelectors, err := ns.analyse(obj)
uid, rules, nsSelectors, podSelectors, ipBlocks, err := ns.analyse(obj)
if err != nil {
return err
}
@@ -317,16 +332,19 @@ func (ns *ns) addNetworkPolicy(obj interface{}) error {
if err := ns.podSelectors.provision(uid, nil, podSelectors); err != nil {
return err
}
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 interface{}) error {
// Analyse the old and the new policy so we can determine differences
oldUID, oldRules, oldNsSelectors, oldPodSelectors, err := ns.analyse(oldObj)
oldUID, oldRules, oldNsSelectors, oldPodSelectors, oldIPBlocks, err := ns.analyse(oldObj)
if err != nil {
return err
}
newUID, newRules, newNsSelectors, newPodSelectors, err := ns.analyse(newObj)
newUID, newRules, newNsSelectors, newPodSelectors, newIPBlocks, err := ns.analyse(newObj)
if err != nil {
return err
}
@@ -344,18 +362,24 @@ func (ns *ns) updateNetworkPolicy(oldObj, newObj interface{}) error {
if err := ns.podSelectors.deprovision(oldUID, oldPodSelectors, newPodSelectors); err != nil {
return err
}
if err := ns.ipBlocks.deprovision(oldUID, oldIPBlocks, newIPBlocks); err != nil {
return err
}
if err := ns.nsSelectors.provision(oldUID, oldNsSelectors, newNsSelectors); err != nil {
return err
}
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 interface{}) error {
// Analyse network policy to free resources
uid, rules, nsSelectors, podSelectors, err := ns.analyse(obj)
uid, rules, nsSelectors, podSelectors, ipBlocks, err := ns.analyse(obj)
if err != nil {
return err
}
@@ -369,73 +393,89 @@ func (ns *ns) deleteNetworkPolicy(obj interface{}) error {
if err := ns.nsSelectors.deprovision(uid, nsSelectors, nil); err != nil {
return err
}
return ns.podSelectors.deprovision(uid, podSelectors, 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) ensureBypassRule() error {
var ipset ipset.Name
if ns.legacy {
ipset = ns.allPods.ipsetName
} else {
ipset = ns.defaultAllowIPSet
if err := ns.podSelectors.deprovision(uid, podSelectors, nil); err != nil {
return err
}
if err := ns.ipBlocks.deprovision(uid, ipBlocks, nil); err != nil {
return err
}
common.Log.Debugf("ensuring rule for DefaultAllow in namespace: %s, set %s", ns.name, ipset)
return ns.ipt.Append(TableFilter, DefaultChain, bypassRule(ipset, ns.name)...)
return nil
}
func (ns *ns) deleteBypassRule() error {
var ipset ipset.Name
if ns.legacy {
ipset = ns.allPods.ipsetName
} else {
ipset = ns.defaultAllowIPSet
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 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) 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
}
}
}
common.Log.Debugf("removing default rule in namespace: %s, set %s", ns.name, ipset)
return ns.ipt.Delete(TableFilter, DefaultChain, bypassRule(ipset, ns.name)...)
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 !ns.isDefaultDeny(obj) {
if err := ns.ensureBypassRule(); 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
_, err := ns.nsSelectors.addToMatching(obj.ObjectMeta.UID, 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 := ns.isDefaultDeny(oldObj)
newDefaultDeny := ns.isDefaultDeny(newObj)
if oldDefaultDeny != newDefaultDeny {
common.Log.Infof("namespace DefaultDeny changed from %t to %t", oldDefaultDeny, newDefaultDeny)
if oldDefaultDeny {
if err := ns.ensureBypassRule(); err != nil {
return err
}
}
if newDefaultDeny {
if err := ns.deleteBypassRule(); 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 {
@@ -464,37 +504,24 @@ func (ns *ns) deleteNamespace(obj *coreapi.Namespace) error {
ns.namespace = nil
// Remove bypass rule
if !ns.isDefaultDeny(obj) {
if err := ns.deleteBypassRule(); 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.UID, obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
}
func (ns *ns) isDefaultDeny(namespace *coreapi.Namespace) bool {
nnpJSON, found := namespace.ObjectMeta.Annotations["net.beta.kubernetes.io/network-policy"]
if !found {
return false
err := ns.nsSelectors.delFromMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
if err != nil {
return err
}
if !ns.legacy {
common.Log.Warn("DefaultDeny annotation is supported only in legacy mode (--use-legacy-netpol)")
return false
if err := ns.ips.Destroy(ns.ingressDefaultAllowIPSet); err != nil {
return err
}
if err := ns.ips.Destroy(ns.egressDefaultAllowIPSet); err != nil {
return err
}
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
return nil
}
func hasIP(pod *coreapi.Pod) bool {
@@ -523,10 +550,19 @@ 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) {
@@ -541,16 +577,9 @@ func (ns *ns) analyse(obj interface{}) (
ns.policies[uid] = obj
// Analyse policy, determine which rules and ipsets are required
if ns.legacy {
rules, nsSelectors, podSelectors, err = ns.analysePolicyLegacy(obj.(*extnapi.NetworkPolicy))
if err != nil {
return
}
} else {
rules, nsSelectors, podSelectors, err = ns.analysePolicy(obj.(*networkingv1.NetworkPolicy))
if err != nil {
return
}
rules, nsSelectors, podSelectors, ipBlocks, err = ns.analysePolicy(obj.(*networkingv1.NetworkPolicy))
if err != nil {
return
}
return
+64 -23
View File
@@ -2,6 +2,7 @@ package npc
import (
"fmt"
"reflect"
"strings"
"k8s.io/apimachinery/pkg/types"
@@ -10,38 +11,71 @@ import (
"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, "")
+66 -38
View File
@@ -1,34 +1,36 @@
package npc
import (
"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)
dst bool // destination selector
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 *metav1.LabelSelector, dst bool, nsName string, ipsetType ipset.Type) (*selectorSpec, error) {
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,
dst: dst,
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
@@ -37,6 +39,23 @@ func newSelectorSpec(json *metav1.LabelSelector, dst bool, nsName string, ipsetT
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
@@ -55,49 +74,54 @@ func (s *selector) delEntry(user types.UID, entry string) error {
}
type selectorFn func(selector *selector) error
type selectorWithPolicyTypeFn func(selector *selector, policyType policyType) error
type selectorSet struct {
ips ipset.Interface
onNewSelector selectorFn
// invoked after dst selector has been provisioned for the first time
onNewDstSelector selectorFn
// invoked after the last instance of dst selector has been deprovisioned
onDestroyDstSelector selectorFn
// 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 dst selector instances to be able to invoke
// onNewDstSelector and onDestroyDstSelector callbacks at the right time;
// selectorSpec.Key -> count
dstSelectorsCount map[string]int
// 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, onNewDstSelector selectorFn, onDestroyDstSelector selectorFn) *selectorSet {
func newSelectorSet(ips ipset.Interface, onNewSelector selectorFn, onNewTargetSelector, onDestroyTargetSelector selectorWithPolicyTypeFn) *selectorSet {
return &selectorSet{
ips: ips,
onNewSelector: onNewSelector,
onNewDstSelector: onNewDstSelector,
onDestroyDstSelector: onDestroyDstSelector,
ips: ips,
onNewSelector: onNewSelector,
onNewTargetSelector: onNewTargetSelector,
onDestroyTargetSelector: onDestroyTargetSelector,
users: make(map[string]map[types.UID]struct{}),
entries: make(map[string]*selector),
dstSelectorsCount: make(map[string]int)}
targetSelectorsCount: make(map[string]map[policyType]int)}
}
func (ss *selectorSet) addToMatching(user types.UID, labelMap map[string]string, entry string, comment string) (bool, error) {
found := false
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 ss.dstSelectorExist(s) {
found = true
if ss.targetSelectorExist(s, policyTypeIngress) {
foundIngress = true
}
if ss.targetSelectorExist(s, policyTypeEgress) {
foundEgress = true
}
if err := s.addEntry(user, entry, comment); err != nil {
return found, err
return foundIngress, foundEgress, err
}
}
}
return found, nil
return foundIngress, foundEgress, nil
}
func (ss *selectorSet) delFromMatching(user types.UID, labelMap map[string]string, entry string) error {
@@ -111,8 +135,8 @@ func (ss *selectorSet) delFromMatching(user types.UID, labelMap map[string]strin
return nil
}
func (ss *selectorSet) dstSelectorExist(s *selector) bool {
return ss.dstSelectorsCount[s.spec.key] > 0
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 {
@@ -129,13 +153,14 @@ func (ss *selectorSet) deprovision(user types.UID, current, desired map[string]*
delete(ss.users, key)
}
if spec.dst {
ss.dstSelectorsCount[key]--
if ss.dstSelectorsCount[key] == 0 {
if err := ss.onDestroyDstSelector(&selector{ss.ips, spec}); err != nil {
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(...)
}
}
}
@@ -160,10 +185,13 @@ func (ss *selectorSet) provision(user types.UID, current, desired map[string]*se
}
ss.users[key][user] = struct{}{}
if spec.dst {
ss.dstSelectorsCount[key]++
if ss.dstSelectorsCount[key] == 1 {
if err := ss.onNewDstSelector(selector); err != nil {
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
}
}
+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 {
+18 -2
View File
@@ -117,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)
@@ -130,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)
@@ -177,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))
}
+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 -1
View File
@@ -49,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)
}
}
File renamed without changes.
@@ -97,7 +97,7 @@ func checkIamInPeerList(cml *configMapAnnotations, c *kubernetes.Clientset, peer
// 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 {
for loopsWhenNothingChanged := 0; loopsWhenNothingChanged < 3; loopsWhenNothingChanged++ {
if err := cml.Init(); err != nil {
return err
}
@@ -119,6 +119,10 @@ func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, node
}
// 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
@@ -144,6 +148,7 @@ func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, node
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 {
@@ -168,6 +173,7 @@ func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, node
}
// 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
@@ -176,14 +182,16 @@ func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, node
func main() {
var (
justReclaim bool
justCheck bool
peerName string
nodeName string
logLevel string
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)")
@@ -210,6 +218,13 @@ func main() {
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)
+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}"
+21 -6
View File
@@ -27,9 +27,9 @@ 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
@@ -54,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=""
@@ -74,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
@@ -99,7 +110,7 @@ fi
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-peers -check-peer-new -peer-name="$PEERNAME" -log-level=debug ; then
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
@@ -133,10 +144,13 @@ post_start_actions() {
/home/weave/weave --local setup-cni
# Attempt to run the reclaim process, but don't halt the script if it fails
/home/weave/kube-peers -reclaim -node-name="$HOSTNAME" -peer-name="$PEERNAME" -log-level=debug || true
/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 &
@@ -144,11 +158,12 @@ 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 \
--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
+9 -9
View File
@@ -25,14 +25,6 @@ items:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- networkpolicies
verbs:
- get
- list
- watch
- apiGroups:
- 'networking.k8s.io'
resources:
@@ -41,6 +33,13 @@ items:
- get
- list
- watch
- apiGroups:
- ''
resources:
- nodes/status
verbs:
- patch
- update
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
@@ -101,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:
@@ -154,7 +155,6 @@ items:
fieldPath: spec.nodeName
image: 'weaveworks/weave-npc:latest'
imagePullPolicy: Always
#npc-args
resources:
requests:
cpu: 10m
@@ -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}"
+107 -20
View File
@@ -8,7 +8,6 @@ import (
"github.com/coreos/go-iptables/iptables"
"github.com/spf13/cobra"
coreapi "k8s.io/api/core/v1"
extnapi "k8s.io/api/extensions/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
@@ -18,8 +17,9 @@ import (
"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"
)
@@ -30,7 +30,7 @@ var (
logLevel string
allowMcast bool
nodeName string
legacy bool
maxList int
)
func handleError(err error) { common.CheckFatal(err) }
@@ -52,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 {
@@ -76,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))
@@ -111,11 +136,81 @@ 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) {
@@ -131,10 +226,6 @@ func root(cmd *cobra.Command, args []string) {
}
common.Log.Infof("Starting Weaveworks NPC %s; node name %q", version, nodeName)
if legacy {
common.Log.Info("Running in legacy mode (k8s pre-1.7 network policy semantics)")
}
if err := metrics.Start(metricsAddr); err != nil {
common.Log.Fatalf("Failed to start metrics: %v", err)
}
@@ -152,13 +243,13 @@ 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))
handleError(createBaseRules(ipt, ips))
npc := npc.New(nodeName, legacy, ipt, ips)
npc := npc.New(nodeName, ipt, ips)
nsController := makeController(client.Core().RESTClient(), "namespaces", &coreapi.Namespace{},
cache.ResourceEventHandlerFuncs{
@@ -219,11 +310,7 @@ func root(cmd *cobra.Command, args []string) {
handleError(npc.UpdateNetworkPolicy(old, new))
},
}
if legacy {
npController = makeController(client.Extensions().RESTClient(), "networkpolicies", &extnapi.NetworkPolicy{}, npHandlers)
} else {
npController = makeController(client.NetworkingV1().RESTClient(), "networkpolicies", &networkingv1.NetworkPolicy{}, npHandlers)
}
npController = makeController(client.NetworkingV1().RESTClient(), "networkpolicies", &networkingv1.NetworkPolicy{}, npHandlers)
go nsController.Run(wait.NeverStop)
go podController.Run(wait.NeverStop)
@@ -244,7 +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().BoolVar(&legacy, "use-legacy-netpol", false, "use legacy network policies (pre k8s 1.7 vsn)")
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
View File
@@ -1,5 +1,11 @@
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/
@@ -7,3 +13,7 @@ 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
+7 -2
View File
@@ -329,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 {
@@ -337,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
+43 -20
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 {
@@ -147,6 +156,7 @@ func main() {
noDiscovery bool
httpAddr string
statusAddr string
metricsAddr string
ipamConfig ipamConfig
dockerAPI string
peers []string
@@ -178,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")
@@ -193,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")
@@ -211,6 +222,7 @@ 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 := newProxyConfig()
@@ -263,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
}
@@ -293,7 +307,8 @@ func main() {
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)
@@ -324,6 +339,9 @@ 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)
@@ -383,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)
@@ -441,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)
@@ -464,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())
}
@@ -635,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
}
+4 -9
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"net"
"os"
"strconv"
"strings"
"syscall"
@@ -15,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
@@ -52,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])
-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
}
-18
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,
@@ -37,12 +33,6 @@ func init() {
"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,
"bridge-ip": bridgeIP,
@@ -56,14 +46,6 @@ func init() {
}
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"):
-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
}
+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 -19
View File
@@ -61,6 +61,8 @@ type Config struct {
NoRewriteHosts bool
TLSConfig TLSConfig
WithoutDNS bool
DNSListenAddress string
DNSDomain string
NoMulticastRoute bool
KeepTXOn bool
DockerBridge string
@@ -78,7 +80,6 @@ type Proxy struct {
Config
client *weavedocker.Client
weave *weaveapi.Client
dockerBridgeIP string
hostnameMatchRegexp *regexp.Regexp
weaveWaitVolume string
weaveWaitNoopVolume string
@@ -158,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())
@@ -595,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 {
@@ -612,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
}
}
+2 -2
View File
@@ -70,7 +70,7 @@ func NewNetworkRouter(config mesh.Config, networkConfig NetworkConfig, bridgeCon
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
@@ -92,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
+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.
+97 -18
View File
@@ -7,19 +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)
* [Things to watch out for](#key-points)
* [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:
@@ -147,14 +154,31 @@ 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](https://v1-7.docs.kubernetes.io/docs/api-reference/v1.7/#networkpolicy-v1-networking)
@@ -167,7 +191,46 @@ definition](https://v1-7.docs.kubernetes.io/docs/api-reference/v1.7/#networkpoli
## <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:
@@ -278,7 +341,15 @@ UDP connection from 10.32.0.7:56648 to 10.32.0.11:80 blocked by Weave NPC.
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)
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
@@ -287,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.
@@ -299,12 +370,13 @@ You can customise the YAML you get from `cloud.weave.works` by passing some of W
- `disable-npc`: boolean (`true|false`). Default: `false`.
- `env.NAME=VALUE`: add environment variable `NAME` and set it to `VALUE`.
- `seLinuxOptions.NAME=VALUE`: add SELinux option `NAME` and set it to `VALUE`, e.g. `seLinuxOptions.type=spc_t`
- `use-legacy-netpol`: use [legacy NetworkPolicy semantics](https://v1-7.docs.kubernetes.io/docs/api-reference/v1.7/#networkpolicy-v1-networking), boolean (`true|false`). Default: `true` for Kubernetes version <= 1.6, `false` for > 1.6.
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
@@ -320,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:
```
+18 -1
View File
@@ -50,7 +50,7 @@ peers and their reachability can be obtained with
```
$ weave status ipam
00:00:00:00:00:01(one) 349526 IPs (33.3% of total)
00:00:00:00:00:01(one) 349526 IPs (33.3% of total) (2 active)
00:00:00:00:00:02(two) 349525 IPs (33.3% of total)
00:00:00:00:00:03(three) 349525 IPs (33.3% of total) - unreachable!
```
@@ -59,9 +59,26 @@ Columns are as follows:
* Peer Name and Nickname
* Absolute quantity/percentage of allocation range managed by peer
* Active - number of IP addresses in use on that peer - this is only
available for the peer where you run the status command.
* Indication of unreachability. This means that the peer is not
visible (directly or indirectly) to the peer on which `weave status
ipam` was run; whilst this could be a transient condition due to a
partition, it may be because the peer has failed and needs to be
removed administratively - see [Starting, Stopping and Removing
Peers](/site/tasks/ipam/stop-remove-peers-ipam.md) for more details.
### <a name="seeded-different-peers"></a>Seeded by Different Peers
If you see the message: `IP allocation was seeded by different peers`,
this means that some Weave Net peers were initialized into one cluster
and some into another cluster; Weave Net cannot operate in this state.
To recover, you need to eliminate the IPAM data from the affected
nodes and restart. If you installed via the Kubernetes Addon, this
data will be in a file under `/var/lib/weave` on the node - delete
this file and restart the node.
For other installations, run `weave reset` and restart. Any existing
connections to containers will be lost.
+22 -17
View File
@@ -10,9 +10,6 @@ controller](/site/kubernetes/kube-addon.md#npc).
### Router Metrics
The endpoint address is `localhost:6782`; the following metrics are
exposed:
* `weave_connections` - Number of peer-to-peer connections.
* `weave_connection_terminations_total` - Number of peer-to-peer
connections terminated.
@@ -25,27 +22,35 @@ exposed:
* `weave_ipam_pending_allocates` - Number of pending allocates.
* `weave_ipam_pending_claims` - Number of pending claims.
#### Publish Router Metrics Endpoint
By default, when started via `weave launch`, weave listens on its local
interface to serve metrics. To publish your metrics throughout your cluster,
e.g. if your prometheus server is installed on a different host machine,
you need to set `WEAVE_STATUS_ADDR` to your corresponding IP and port.
Default port is 6782.
`WEAVE_STATUS_ADDR=X.X.X.X:PORT`
You can set `WEAVE_STATUS_ADDR=0.0.0.0:6782` to listen on all interfaces,
but be aware, this may expose your metrics to the public internet.
### Kubernetes Network Policy Controller Metrics
The endpoint address is `localhost:6781`; the following metric is
The following metric is
exposed:
* `weavenpc_blocked_connections_total` - Connection attempts blocked
by policy controller.
### Metrics Endpoint Addresses
When installed as a Kubernetes Addon, the router listens for metrics
requests on 0.0.0.0:6782 and the Network Policy Controller listens on
0.0.0.0:6781. No other requests are served on these endpoints.
>Note: If your Kubernetes hosts are exposed to the public internet
then these metrics endpoints will also be exposed.
When started via `weave launch`, by default weave listens on its local
interface to serve metrics and other read-only status requests. To
publish your metrics throughout your cluster, you can set
`WEAVE_STATUS_ADDR`:
`WEAVE_STATUS_ADDR=X.X.X.X:PORT`
Set it to an empty string to disable.
You can also pass the parameter `--metrics-addr=X.X.X.X:PORT` to
`weave launch` to specify an address to listen for metrics only.
# Static Configuration for Weave Net
The following YAML fragment can be used in your Prometheus configuration to
+4
View File
@@ -43,6 +43,10 @@ To disable an application container's use of weaveDNS, add the
`--without-dns` option to `weave launch`. To
disable weaveDNS itself, launch weave with the `--no-dns` option.
> **Note** WeaveDNS is not part of the Weave Net Kubernetes add-on.
Kubernetes has its own DNS service, integrated with Kubernetes
Services, and WeaveDNS does not duplicate that functionality.
**See Also**
* [Integrating Docker via the API Proxy](/site/tasks/weave-docker-api/weave-docker-api.md)
+4
View File
@@ -157,6 +157,9 @@ The columns are as follows:
the encryption mode, data transport method, remote peer name and
nickname for pending and established connections, mtu if known
Specific error messages:
* `IP allocation was seeded by different peers` - [more details here](/site/ipam/troubleshooting-ipam.md#seeded-different-peers)
### <a name="weave-status-peers"></a>List Peers
Detailed information on peers can be obtained with `weave status
@@ -329,5 +332,6 @@ and the container image versions as git hashes.
**See Also**
* [Troubleshooting the Kubernetes Addon](/site/kubernetes/kube-addon/#troubleshooting)
* [Troubleshooting IPAM](/site/tasks/ipam/troubleshooting-ipam.md)
* [Troubleshooting the Proxy](/site/tasks/weave-docker-api/using-proxy.md)
+59
View File
@@ -0,0 +1,59 @@
#! /bin/bash
. "$(dirname "$0")/config.sh"
C1=10.32.0.2
C2=10.32.0.3
kill_weaver() {
run_on $HOST1 sudo ip link set weave down
WEAVER_PID=$(container_pid $HOST1 weave)
run_on $HOST1 sudo kill -9 $WEAVER_PID
sleep 3
}
start_suite "Re-create bridge after restart"
# Should create a bridge of the "bridge" type.
WEAVE_NO_FASTDP=1 weave_on $HOST1 launch
WEAVE_NO_FASTDP=1 weave_on $HOST2 launch $HOST1
start_container $HOST1 $C1/24 --name=c1
start_container $HOST2 $C2/24 --name=c2
assert_raises "exec_on $HOST1 c1 $PING $C2"
kill_weaver # should re-create the bridge
assert_raises "exec_on $HOST1 c1 $PING $C2"
# Should create a bridge of the "bridged_fastdp" type
weave_on $HOST1 reset
weave_on $HOST1 launch $HOST2
weave_on $HOST1 attach $C1/24 c1
assert_raises "exec_on $HOST1 c1 $PING $C2"
kill_weaver # should re-create the bridge
assert_raises "exec_on $HOST1 c1 $PING $C2"
# test restore of iptables
weave_on $HOST1 reset
# `--expect-npc` to trigger creation of WEAVE-NPC iptables chain.
weave_on $HOST1 launch --expect-npc
# To create POSTROUTING rules.
weave_on $HOST1 expose
IPT_BEFORE=$(mktemp)
IPT_AFTER=$(mktemp)
run_on $HOST1 "sudo iptables-save | grep -i weave | grep -v '\[.*:.*\]' > $IPT_BEFORE"
run_on $HOST1 "sudo iptables -t filter -D FORWARD -o weave -m comment --comment \"NOTE: this must go before '-j KUBE-FORWARD'\" -j WEAVE-NPC"
run_on $HOST1 sudo iptables -t nat -D POSTROUTING -j WEAVE
kill_weaver # should re-create the bridge and iptables friends
# Rudimentary check that weave related iptables rules has been restored
run_on $HOST1 "sudo iptables-save | grep -i weave | grep -v '\[.*:.*\]' > $IPT_AFTER"
assert_raises "run_on $HOST1 diff $IPT_BEFORE $IPT_AFTER"
end_suite
+3 -3
View File
@@ -21,7 +21,7 @@ start_container_local_plugin $HOST1 --name=c3
assert "show_multicast_route_on $HOST1 c1"
assert "show_multicast_route_on $HOST1 c2"
assert "show_multicast_route_on $HOST1 c3" "224.0.0.0/4 dev ethwe0 "
assert "show_multicast_route_on $HOST1 c3" "224.0.0.0/4 dev ethwe0 scope link "
# Now try via docker network options
# using ssh rather than docker -H because CircleCI docker client is older
@@ -30,7 +30,7 @@ $SSH $HOST1 docker run --net=testmcastfalse --name c4 -di $SMALL_IMAGE /bin/sh
assert "show_multicast_route_on $HOST1 c4"
$SSH $HOST1 docker network create --driver weavemesh --ipam-driver weavemesh --opt works.weave.multicast testmcasttrue
$SSH $HOST1 docker run --net=testmcasttrue --name c5 -di $SMALL_IMAGE /bin/sh
assert "show_multicast_route_on $HOST1 c5" "224.0.0.0/4 dev ethwe0 "
assert "show_multicast_route_on $HOST1 c5" "224.0.0.0/4 dev ethwe0 scope link "
# Ensure current proxy options are obeyed on container start
docker_on $HOST1 stop -t 1 c2
@@ -39,7 +39,7 @@ weave_on $HOST1 launch
proxy docker_on $HOST1 start c2
assert "show_multicast_route_on $HOST1 c2" "224.0.0.0/4 dev ethwe "
assert "show_multicast_route_on $HOST1 c2" "224.0.0.0/4 dev ethwe scope link "
docker_on $HOST1 rm -f c3 c4 c5
$SSH $HOST1 docker network rm testmcasttrue testmcastfalse
+155 -25
View File
@@ -4,7 +4,11 @@
tear_down_kubeadm() {
for host in $HOSTS; do
run_on $host "sudo kubeadm reset && sudo rm -r -f /opt/cni/bin/*weave*"
run_on $host "sudo kubeadm reset --force && sudo rm -r -f /opt/cni/bin/*weave*"
# 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.
run_on $host "sudo iptables -t nat -D PREROUTING -m comment --comment \"kubernetes service portals\" -j KUBE-SERVICES" || true
done
}
@@ -18,6 +22,7 @@ NUM_HOSTS=$(howmany $HOSTS)
SUCCESS="$(( $NUM_HOSTS * ($NUM_HOSTS-1) )) established"
KUBECTL="sudo kubectl --kubeconfig /etc/kubernetes/admin.conf"
KUBE_PORT=6443
WEAVE_NETWORK=10.32.0.0/12
IMAGE=weaveworks/network-tester:latest
DOMAIN=nettest.default.svc.cluster.local.
@@ -29,27 +34,25 @@ docker_on $HOST1 run --rm --privileged --net=host --entrypoint=/usr/sbin/ipset w
# kubeadm init upgrades to latest Kubernetes version by default, therefore we try to lock the version using the below option:
k8s_version="$(run_on $HOST1 "kubelet --version" | grep -oP "(?<=Kubernetes )v[\d\.\-beta]+")"
k8s_version_option="$([[ "$k8s_version" > "v1.6" ]] && echo "kubernetes-version" || echo "use-kubernetes-version")"
for host in $HOSTS; do
if [ $host = $HOST1 ] ; then
run_on $host "sudo systemctl start kubelet && sudo kubeadm init --$k8s_version_option=$k8s_version --token=$TOKEN"
run_on $host "sudo systemctl start kubelet && sudo kubeadm init --kubernetes-version=$k8s_version --token=$TOKEN --pod-network-cidr=$WEAVE_NETWORK"
else
run_on $host "sudo systemctl start kubelet && sudo kubeadm join --token=$TOKEN $HOST1IP:$KUBE_PORT"
run_on $host "sudo systemctl start kubelet && sudo kubeadm join --token=$TOKEN --discovery-token-unsafe-skip-ca-verification $HOST1IP:$KUBE_PORT"
fi
done
if [ -n "$COVERAGE" ]; then
COVERAGE_ARGS="env:\\n - name: EXTRA_ARGS\\n value: \"-test.coverprofile=/home/weave/cover.prof --\""
WEAVE_ENV_VARS="env:\\n - name: EXTRA_ARGS\\n value: \"-test.coverprofile=/home/weave/cover.prof --\""
else
COVERAGE_ARGS="env:"
WEAVE_ENV_VARS="env:"
fi
# Ensure Kubernetes uses locally built container images and inject code coverage environment variable (or do nothing depending on $COVERAGE):
sed -e "s%imagePullPolicy: Always%imagePullPolicy: Never%" \
-e "s%env:%$COVERAGE_ARGS%" \
-e "s%#npc-args% args:\n - '--use-legacy-netpol'%" \
"$(dirname "$0")/../prog/weave-kube/weave-daemonset-k8s-1.7.yaml" | run_on "$HOST1" "$KUBECTL apply -n kube-system -f -"
-e "s%env:%$WEAVE_ENV_VARS%" \
"$(dirname "$0")/../prog/weave-kube/weave-daemonset-k8s-1.8.yaml" | run_on "$HOST1" "$KUBECTL apply -n kube-system -f -"
sleep 5
@@ -59,7 +62,7 @@ check_connections() {
assert_raises 'wait_for_x check_connections "connections to establish"'
# Check we can ping between the Weave bridg IPs on each host
# Check we can ping between the Weave bridge IPs on each host
HOST1EXPIP=$($SSH $HOST1 "weave expose" || true)
HOST2EXPIP=$($SSH $HOST2 "weave expose" || true)
HOST3EXPIP=$($SSH $HOST3 "weave expose" || true)
@@ -72,10 +75,19 @@ assert "run_on $HOST1 ps aux | grep -c '[d]efunct'" "0"
assert "run_on $HOST2 ps aux | grep -c '[d]efunct'" "0"
assert "run_on $HOST3 ps aux | grep -c '[d]efunct'" "0"
# Set up a simple network policy so all our test pods can talk to each other
run_on $HOST1 "$KUBECTL annotate ns default net.beta.kubernetes.io/network-policy='{\"ingress\":{\"isolation\":\"DefaultDeny\"}}'"
# Set up simple network policies so all our test pods can talk to each other
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
EOF
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test840
@@ -98,7 +110,7 @@ EOF
# Another policy, this time with no 'from' section, just to check that doesn't cause a crash
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test840f
@@ -134,6 +146,22 @@ spec:
run: nettest
EOF
# And a NodePort service so we can test virtual IP access
run_on $HOST1 "$KUBECTL create -f -" <<EOF
apiVersion: v1
kind: Service
metadata:
name: netvirt
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 31138
selector:
run: nettest
EOF
podName=$($SSH $HOST1 "$KUBECTL get pods -l run=nettest -o go-template='{{(index .items 0).metadata.name}}'")
check_all_pods_communicate() {
@@ -159,16 +187,14 @@ run_on $HOST1 "$KUBECTL run nettest-deny --labels=\"access=deny,run=nettest-deny
denyPodName=$($SSH $HOST1 "$KUBECTL get pods -l run=nettest-deny -o go-template='{{(index .items 0).metadata.name}}'")
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$DOMAIN:8080/status >/dev/null"
# Restart weave-net with npc in non-legacy mode
$SSH $HOST1 "$KUBECTL delete ds weave-net -n=kube-system"
sed -e "s%imagePullPolicy: Always%imagePullPolicy: Never%" \
-e "s%env:%$COVERAGE_ARGS%" \
"$(dirname "$0")/../prog/weave-kube/weave-daemonset-k8s-1.7.yaml" | run_on "$HOST1" "$KUBECTL apply -n kube-system -f -"
# check access via virtual IP
VIRTUAL_IP=$($SSH $HOST1 $KUBECTL get service netvirt -o template --template={{.spec.clusterIP}})
assert_raises "$SSH $HOST1 $KUBECTL exec $podName -- curl -s -S -f -m 2 http://$VIRTUAL_IP/status >/dev/null"
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$VIRTUAL_IP/status >/dev/null"
assert_raises 'wait_for_x check_all_pods_communicate pods'
# nettest-deny should still not be able to reach nettest pods
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$DOMAIN:8080/status >/dev/null"
# host should not be able to reach pods via service virtual IP or NodePort
assert_raises "! $SSH $HOST1 curl -s -S -f -m 2 http://$VIRTUAL_IP/status >/dev/null"
assert_raises "! $SSH $HOST1 curl -s -S -f -m 2 http://$HOST2:31138/status >/dev/null"
# allow access for nettest-deny
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
@@ -196,12 +222,39 @@ run_on $HOST1 "$KUBECTL delete netpol allow-nettest-deny"
# nettest-deny should still not be able to reach nettest pods
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$DOMAIN:8080/status >/dev/null"
# allow access for all
# Create many namespaces to stress namespaceSelector
for n in 1 2 3 4 5 6 7 8 9 10; do
run_on $HOST1 "$KUBECTL create namespace namespace${n}"
done
# allow access from any namespace
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-nettest-deny
name: allow-any-namespace
namespace: default
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector: {}
EOF
# Should be able to access from the "deny" pod now
assert_raises "$SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$DOMAIN:8080/status >/dev/null"
# host should still not be able to reach pods via service virtual IP or NodePort
# because host is not in a namespace
assert_raises "! $SSH $HOST1 curl -s -S -f -m 2 http://$VIRTUAL_IP/status >/dev/null"
assert_raises "! $SSH $HOST1 curl -s -S -f -m 2 http://$HOST2:31138/status >/dev/null"
# allow access from anywhere
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-anywhere
namespace: default
spec:
podSelector: {}
@@ -209,8 +262,85 @@ spec:
- {}
EOF
# Virtual IP and NodePort should now work
assert_raises "$SSH $HOST1 curl -s -S -f -m 2 http://$VIRTUAL_IP/status >/dev/null"
assert_raises "$SSH $HOST1 curl -s -S -f -m 2 http://$HOST2:31138/status >/dev/null"
# allow nettest-deny to access only to 8.8.8.0/24
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-nettest-deny-dns
namespace: default
spec:
podSelector:
matchLabels:
run: nettest-deny
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 8.8.8.0/24
except:
- 8.8.8.4/32
EOF
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$DOMAIN:8080/status >/dev/null"
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- dig @8.8.8.4 google.com >/dev/null"
assert_raises "$SSH $HOST1 $KUBECTL exec $denyPodName -- dig @8.8.8.8 google.com >/dev/null"
# also, allow nettest-deny to access nettest and kube-system (for kube-dns)
run_on $HOST1 "$KUBECTL label namespace kube-system name=kube-system"
run_on $HOST1 "$KUBECTL replace -f -" <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-nettest-deny-dns
namespace: default
spec:
podSelector:
matchLabels:
run: nettest-deny
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 8.8.8.0/24
except:
- 8.8.8.4/32
- podSelector:
matchLabels:
run: nettest
- namespaceSelector:
matchLabels:
name: kube-system
EOF
assert_raises "$SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$DOMAIN:8080/status >/dev/null"
# Passing --no-masq-local and setting externalTrafficPolicy to Local must preserve
# the client source IP addr
CLIENT_IP_MASQ="$($SSH $HOST1 curl -sS http://$HOST2:31138/client_ip)"
WEAVE_ENV_VARS="${WEAVE_ENV_VARS}\\n - name: NO_MASQ_LOCAL\\n value: \"1\""
$SSH $HOST1 "$KUBECTL delete ds weave-net -n=kube-system"
sed -e "s%imagePullPolicy: Always%imagePullPolicy: Never%" \
-e "s%env:%$WEAVE_ENV_VARS%" \
"$(dirname "$0")/../prog/weave-kube/weave-daemonset-k8s-1.8.yaml" | run_on "$HOST1" "$KUBECTL apply -n kube-system -f -"
sleep 5
run_on $HOST1 "$KUBECTL patch svc netvirt -p '{\"spec\":{\"externalTrafficPolicy\":\"Local\"}}'"
CLIENT_IP_NO_MASQ="$($SSH $HOST1 curl -sS http://$HOST2:31138/client_ip)"
assert_raises "[ $CLIENT_IP_NO_MASQ != $CLIENT_IP_MASQ ]"
assert_raises "[ $HOST1IP == $CLIENT_IP_NO_MASQ ]"
tear_down_kubeadm
# Destroy our test ipset, and implicitly check it is still there
@@ -27,7 +27,7 @@ fi
function teardown_kubernetes_cluster {
greyly echo "Tearing down kubernetes cluster"
for host in $HOSTS; do
run_on $host "sudo kubeadm reset && sudo rm -r -f /opt/cni/bin/*weave*"
run_on $host "sudo kubeadm reset --force && sudo rm -r -f /opt/cni/bin/*weave*"
done
}
@@ -38,13 +38,12 @@ function setup_kubernetes_cluster {
# kubeadm init upgrades to latest Kubernetes version by default, therefore we try to lock the version using the below option:
k8s_version="$(run_on $HOST1 "kubelet --version" | grep -oP "(?<=Kubernetes )v[\d\.\-beta]+")"
k8s_version_option="$([[ "$k8s_version" > "v1.6" ]] && echo "kubernetes-version" || echo "use-kubernetes-version")"
for host in $HOSTS; do
if [ $host = $HOST1 ] ; then
run_on $host "sudo systemctl start kubelet && sudo kubeadm init --$k8s_version_option=$k8s_version --token=$TOKEN"
run_on $host "sudo systemctl start kubelet && sudo kubeadm init --kubernetes-version=$k8s_version --token=$TOKEN"
else
run_on $host "sudo systemctl start kubelet && sudo kubeadm join --token=$TOKEN $HOST1IP:$KUBE_PORT"
run_on $host "sudo systemctl start kubelet && sudo kubeadm join --token=$TOKEN --discovery-token-unsafe-skip-ca-verification $HOST1IP:$KUBE_PORT"
fi
done
+79 -1
View File
@@ -13,7 +13,7 @@ it is recommended to run the tests from the build VM and not the host.
> **NOTE WELL** The number of hosts required by a test must be specified in the test name. For example, `000_some_test.sh` will use one host, while `001_some_other_3_test.sh` will use three hosts. The number of hosts must be the last part of the test name before the `_test.sh` prefix. See `/tools/runner/runner.go` for details
## Running tests
## Running tests locally using VMs
**TL;DR**: You can run the steps 2. to 7. below with one command:
@@ -23,46 +23,62 @@ it is recommended to run the tests from the build VM and not the host.
1. Start the build virtual machine (see above article for more details):
```
vagrant up
```
2. Start the three testing VMs:
```
cd test
vagrant up
```
3. SSH into the build VM and go to Weave Net's sources:
```
cd ..
vagrant ssh
# you are now on the build VM:
cd ~/weave
```
4. Compile all code and dependencies:
```
make
make testrunner
cd test
```
5. Upload the weave images from where the `Makefile` puts them (`weave.tar.gz`) to
the three docker hosts, `docker load` these, and copies the `weave` script over:
```
./setup.sh
```
6. Run individual tests, e.g.:
```
./200_dns_test.sh
```
or run all tests (everything named `*_test.sh`):
```
./run_all.sh
```
7. Stop all VMs:
```
exit
# you are now on your host machine
vagrant destroy -f
cd test
vagrant destroy -f
```
## Using other VMs
@@ -92,3 +108,65 @@ When a new version of Docker is released, you willneed to update the GCE test im
To do this, change the Docker version in `run-integration-tests.sh` and push the change.
Next build in CircleCI will detect that there is no template for this version of Docker and will first create the template before running tests.
Subsequent builds will then simply re-use the template.
## Running the tests on a cloud provider
Running the tests against a remote provider instead of local vagrant VMs is a little more involved, and reproduces the environment used for CI. It is recommended that you use the build VM to coordinate the build phase. Make sure you have a recent version of [ansible](https://github.com/ansible/ansible) installed, terraform will fail to provision the VMs.
1. Create the build VM in the repository root and log in
```
# On your development machine
$ vagrant up
$ vagrant ssh
```
2. Once in the build vm, install the `gcloud` tools as [per the documentation](https://cloud.google.com/sdk/downloads). You need to do this manually as the circleCI VMs are already provisioned with `gcloud`.
```
# On the build VM
$ curl https://sdk.cloud.google.com | bash
$ exec -l $SHELL
```
You don't need to initialise the `gcloud` tools by running `gcloud init`.
3. Export the secret key needed to decrypt the cloud credentials - This assumes you're using the build tools
```
# On the build VM
$ export SECRET_KEY="XXXXXXXXXX"
```
4. Navigate to the test directory and provision the VMs
```
# On the build VM
$ cd weave/test
/weave/test$ ./run-integration-tests.sh up
```
5. Run the tests you need
```
# On the build VM
/weave/test$ export TESTS="./090_docker_restart_policy_2_test.sh"
/weave/test$ ./run-integration-tests.sh test
```
6. Don't forget to close down your remote VMs when you're done
```
# On the build VM
/weave/test$ ./run-integration-tests.sh destroy
```
7. And switch off your build VM
```
# On the build VM
/weave/test$ exit
# On your development machine
$ vagrant destroy -f
# or "vagrant suspend" if you want to preserve the machine state
```
+1 -1
View File
@@ -25,7 +25,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define hostname do |host|
host.vm.provider :virtualbox do |vb|
vb.name = hostname
vb.memory = 384
vb.memory = 2048
configure_nat_dns(vb)
end
+1 -1
View File
@@ -13,7 +13,7 @@
# limitations under the License.
FROM bash
RUN apk add --no-cache curl
RUN apk add --no-cache curl bind-tools
ADD webserver webserver
EXPOSE 8080
ENTRYPOINT ["/webserver"]
+17
View File
@@ -13,6 +13,8 @@
// Visit /status to see pass/running/fail determination. (literally, it will
// return one of those words.)
//
// Visit /client_ip to see the source IP addr of the request.
//
// /write is used by other network test servers to register connectivity.
package main
@@ -78,6 +80,20 @@ func (s *State) serveStatus(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "fail")
}
// serveClientIP returns the client source IP addr.
func (s *State) serveClientIP(w http.ResponseWriter, r *http.Request) {
s.lock.Lock()
defer s.lock.Unlock()
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
go s.Logf("Warning: unable to parse remote addr: %s", err)
w.WriteHeader(http.StatusInternalServerError)
}
fmt.Fprintf(w, host)
}
// serveRead writes our json encoded state
func (s *State) serveRead(w http.ResponseWriter, r *http.Request) {
s.lock.Lock()
@@ -186,6 +202,7 @@ func main() {
http.HandleFunc("/read", state.serveRead)
http.HandleFunc("/write", state.serveWrite)
http.HandleFunc("/status", state.serveStatus)
http.HandleFunc("/client_ip", state.serveClientIP)
go log.Fatal(http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", *port), nil))
+1 -1
View File
@@ -23,4 +23,4 @@ if [ -n "$CIRCLECI" -o -n "$PARALLEL" ]; then
RUNNER_ARGS="$RUNNER_ARGS -parallel"
fi
HOSTS="$HOSTS" "${DIR}/../tools/runner/runner" -timeout=300 $RUNNER_ARGS $TESTS
HOSTS="$HOSTS" "${DIR}/../tools/runner/runner" -timeout=360 $RUNNER_ARGS $TESTS
+18 -18
View File
@@ -41,15 +41,15 @@ func main() {
log.Fatalf("The client key already exists. Please remove it or specify a different key/cert.")
}
err = cert.GenerateCert(
[]string{""},
clientCertPath,
clientKeyPath,
caCertPath,
caKeyPath,
org,
bits,
)
err = cert.GenerateCert(&cert.Options{
Hosts: []string{""},
CertFile: clientCertPath,
KeyFile: clientKeyPath,
CAFile: caCertPath,
CAKeyFile: caKeyPath,
Org: org,
Bits: bits,
})
if err != nil {
log.Fatalf("Error generating client certificate: %s", err)
}
@@ -64,15 +64,15 @@ func main() {
if _, err := os.Stat(serverCertPath); os.IsNotExist(err) {
log.Printf("Creating server certificate: %s", serverCertPath)
err = cert.GenerateCert(
[]string{ip},
serverCertPath,
serverKeyPath,
caCertPath,
caKeyPath,
org,
bits,
)
err = cert.GenerateCert(&cert.Options{
Hosts: []string{ip},
CertFile: serverCertPath,
KeyFile: serverKeyPath,
CAFile: caCertPath,
CAKeyFile: caKeyPath,
Org: org,
Bits: bits,
})
if err != nil {
log.Fatalf("error generating server cert: %s", err)
}
+1 -1
Submodule tools updated: 74dc626b6d...ca69607f79.
+1 -1
View File
@@ -16,7 +16,7 @@ def ansibleize(h)
end
def get_go_version_from_build_dockerfile()
go_regexp = /FROM golang:(\S*).*?/
go_regexp = /FROM golang:([\d\.]*).*?/
dockerfile_path = File.expand_path(File.join(File.dirname(__FILE__), 'build', 'Dockerfile'))
go_version = File.readlines(dockerfile_path).select { |line| line.match(go_regexp) }.first.match(go_regexp).captures.first
if go_version.nil?
-26
View File
@@ -1,26 +0,0 @@
# Managing Vendored Dependencies with `git submodule`
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.
## Adding a New Dependency
~/weave$ git submodule add https://example.com/organisation/module vendor/example.com/organisation/module
## Update All Dependencies to Upstream `master`
~/weave$ git submodule foreach git pull origin master
## Force a Specific Dependency to a Particular Commit
~/weave$ (cd vendor/example.com/organisation/module && git checkout <commit-ish>)
~/weave$ git add vendor/example.com/organisation/module
## Remove a Dependency
~/weave$ git submodule deinit vendor/example.com/organisation/module
~/weave$ git rm vendor/example.com/organisation/module
~/weave$ rm -rf .git/modules/vendor/example.con/organisation/module
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+12
View File
@@ -0,0 +1,12 @@
# go-ansiterm
This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
-----
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+188
View File
@@ -0,0 +1,188 @@
package ansiterm
const LogEnv = "DEBUG_TERMINAL"
// ANSI constants
// References:
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
// -- http://vt100.net/emu/dec_ansi_parser
// -- http://vt100.net/emu/vt500_parser.svg
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
// -- http://www.inwap.com/pdp10/ansicode.txt
const (
// ECMA-48 Set Graphics Rendition
// Note:
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
ANSI_SGR_RESET = 0
ANSI_SGR_BOLD = 1
ANSI_SGR_DIM = 2
_ANSI_SGR_ITALIC = 3
ANSI_SGR_UNDERLINE = 4
_ANSI_SGR_BLINKSLOW = 5
_ANSI_SGR_BLINKFAST = 6
ANSI_SGR_REVERSE = 7
_ANSI_SGR_INVISIBLE = 8
_ANSI_SGR_LINETHROUGH = 9
_ANSI_SGR_FONT_00 = 10
_ANSI_SGR_FONT_01 = 11
_ANSI_SGR_FONT_02 = 12
_ANSI_SGR_FONT_03 = 13
_ANSI_SGR_FONT_04 = 14
_ANSI_SGR_FONT_05 = 15
_ANSI_SGR_FONT_06 = 16
_ANSI_SGR_FONT_07 = 17
_ANSI_SGR_FONT_08 = 18
_ANSI_SGR_FONT_09 = 19
_ANSI_SGR_FONT_10 = 20
_ANSI_SGR_DOUBLEUNDERLINE = 21
ANSI_SGR_BOLD_DIM_OFF = 22
_ANSI_SGR_ITALIC_OFF = 23
ANSI_SGR_UNDERLINE_OFF = 24
_ANSI_SGR_BLINK_OFF = 25
_ANSI_SGR_RESERVED_00 = 26
ANSI_SGR_REVERSE_OFF = 27
_ANSI_SGR_INVISIBLE_OFF = 28
_ANSI_SGR_LINETHROUGH_OFF = 29
ANSI_SGR_FOREGROUND_BLACK = 30
ANSI_SGR_FOREGROUND_RED = 31
ANSI_SGR_FOREGROUND_GREEN = 32
ANSI_SGR_FOREGROUND_YELLOW = 33
ANSI_SGR_FOREGROUND_BLUE = 34
ANSI_SGR_FOREGROUND_MAGENTA = 35
ANSI_SGR_FOREGROUND_CYAN = 36
ANSI_SGR_FOREGROUND_WHITE = 37
_ANSI_SGR_RESERVED_01 = 38
ANSI_SGR_FOREGROUND_DEFAULT = 39
ANSI_SGR_BACKGROUND_BLACK = 40
ANSI_SGR_BACKGROUND_RED = 41
ANSI_SGR_BACKGROUND_GREEN = 42
ANSI_SGR_BACKGROUND_YELLOW = 43
ANSI_SGR_BACKGROUND_BLUE = 44
ANSI_SGR_BACKGROUND_MAGENTA = 45
ANSI_SGR_BACKGROUND_CYAN = 46
ANSI_SGR_BACKGROUND_WHITE = 47
_ANSI_SGR_RESERVED_02 = 48
ANSI_SGR_BACKGROUND_DEFAULT = 49
// 50 - 65: Unsupported
ANSI_MAX_CMD_LENGTH = 4096
MAX_INPUT_EVENTS = 128
DEFAULT_WIDTH = 80
DEFAULT_HEIGHT = 24
ANSI_BEL = 0x07
ANSI_BACKSPACE = 0x08
ANSI_TAB = 0x09
ANSI_LINE_FEED = 0x0A
ANSI_VERTICAL_TAB = 0x0B
ANSI_FORM_FEED = 0x0C
ANSI_CARRIAGE_RETURN = 0x0D
ANSI_ESCAPE_PRIMARY = 0x1B
ANSI_ESCAPE_SECONDARY = 0x5B
ANSI_OSC_STRING_ENTRY = 0x5D
ANSI_COMMAND_FIRST = 0x40
ANSI_COMMAND_LAST = 0x7E
DCS_ENTRY = 0x90
CSI_ENTRY = 0x9B
OSC_STRING = 0x9D
ANSI_PARAMETER_SEP = ";"
ANSI_CMD_G0 = '('
ANSI_CMD_G1 = ')'
ANSI_CMD_G2 = '*'
ANSI_CMD_G3 = '+'
ANSI_CMD_DECPNM = '>'
ANSI_CMD_DECPAM = '='
ANSI_CMD_OSC = ']'
ANSI_CMD_STR_TERM = '\\'
KEY_CONTROL_PARAM_2 = ";2"
KEY_CONTROL_PARAM_3 = ";3"
KEY_CONTROL_PARAM_4 = ";4"
KEY_CONTROL_PARAM_5 = ";5"
KEY_CONTROL_PARAM_6 = ";6"
KEY_CONTROL_PARAM_7 = ";7"
KEY_CONTROL_PARAM_8 = ";8"
KEY_ESC_CSI = "\x1B["
KEY_ESC_N = "\x1BN"
KEY_ESC_O = "\x1BO"
FILL_CHARACTER = ' '
)
func getByteRange(start byte, end byte) []byte {
bytes := make([]byte, 0, 32)
for i := start; i <= end; i++ {
bytes = append(bytes, byte(i))
}
return bytes
}
var toGroundBytes = getToGroundBytes()
var executors = getExecuteBytes()
// SPACE 20+A0 hex Always and everywhere a blank space
// Intermediate 20-2F hex !"#$%&'()*+,-./
var intermeds = getByteRange(0x20, 0x2F)
// Parameters 30-3F hex 0123456789:;<=>?
// CSI Parameters 30-39, 3B hex 0123456789;
var csiParams = getByteRange(0x30, 0x3F)
var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
var upperCase = getByteRange(0x40, 0x5F)
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
var lowerCase = getByteRange(0x60, 0x7E)
// Alphabetics 40-7E hex (all of upper and lower case)
var alphabetics = append(upperCase, lowerCase...)
var printables = getByteRange(0x20, 0x7F)
var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
var escapeToGroundBytes = getEscapeToGroundBytes()
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
// byte ranges below
func getEscapeToGroundBytes() []byte {
escapeToGroundBytes := getByteRange(0x30, 0x4F)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
return escapeToGroundBytes
}
func getExecuteBytes() []byte {
executeBytes := getByteRange(0x00, 0x17)
executeBytes = append(executeBytes, 0x19)
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
return executeBytes
}
func getToGroundBytes() []byte {
groundBytes := []byte{0x18}
groundBytes = append(groundBytes, 0x1A)
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
groundBytes = append(groundBytes, 0x99)
groundBytes = append(groundBytes, 0x9A)
groundBytes = append(groundBytes, 0x9C)
return groundBytes
}
// Delete 7F hex Always and everywhere ignored
// C1 Control 80-9F hex 32 additional control characters
// G1 Displayable A1-FE hex 94 additional displayable characters
// Special A0+FF hex Same as SPACE and DELETE
+7
View File
@@ -0,0 +1,7 @@
package ansiterm
type ansiContext struct {
currentChar byte
paramBuffer []byte
interBuffer []byte
}
+49
View File
@@ -0,0 +1,49 @@
package ansiterm
type csiEntryState struct {
baseState
}
func (csiState csiEntryState) Handle(b byte) (s state, e error) {
csiState.parser.logf("CsiEntry::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
return csiState.parser.csiParam, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiEntryState) Transition(s state) error {
csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
case csiState.parser.csiParam:
switch {
case sliceContains(csiParams, csiState.parser.context.currentChar):
csiState.parser.collectParam()
case sliceContains(intermeds, csiState.parser.context.currentChar):
csiState.parser.collectInter()
}
}
return nil
}
func (csiState csiEntryState) Enter() error {
csiState.parser.clear()
return nil
}
+38
View File
@@ -0,0 +1,38 @@
package ansiterm
type csiParamState struct {
baseState
}
func (csiState csiParamState) Handle(b byte) (s state, e error) {
csiState.parser.logf("CsiParam::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
csiState.parser.collectParam()
return csiState, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiParamState) Transition(s state) error {
csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
}
return nil
}
Loaded 100 of 3009 files, more files were not shown because too many files have changed in this diff. Show more