Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2d6ee4223 | ||
|
|
90a81ce736 | ||
|
|
9cf0dd1b87 | ||
|
|
e65cf32372 | ||
|
|
0ad2001ab4 | ||
|
|
70ff510e49 | ||
|
|
6377aeabdd | ||
|
|
1649080a35 | ||
|
|
c1ee358f66 | ||
|
|
2c708b57a1 | ||
|
|
c5772c814c | ||
|
|
10a5b6fb51 | ||
|
|
07d31a8558 | ||
|
|
cf3a3be8f2 | ||
|
|
49224ec9f7 | ||
|
|
dee24aec65 | ||
|
|
9a63ade1b5 | ||
|
|
18a6237ec7 | ||
|
|
be8298926a | ||
|
|
86958be6cf | ||
|
|
a2d07c85da | ||
|
|
295ddc5248 | ||
|
|
a85a19e40a | ||
|
|
cec3c8a846 | ||
|
|
7da7ce85df | ||
|
|
6055431b6f | ||
|
|
c0e2deb5a0 | ||
|
|
1f86ed55ba | ||
|
|
35f1ba17e1 | ||
|
|
b84fbf86ec | ||
|
|
a5e0b3452d | ||
|
|
0a1ca30aae | ||
|
|
2e85018c26 | ||
|
|
affdc6f5af | ||
|
|
9198bb5a68 | ||
|
|
9769c8d5b9 | ||
|
|
688328dc57 | ||
|
|
8904a4b144 | ||
|
|
8d1ee752d4 | ||
|
|
f02a11b27b | ||
|
|
5e675f26f7 | ||
|
|
497a9c7fd0 | ||
|
|
5afcd0595d | ||
|
|
f27d4d2117 | ||
|
|
79727a86fa | ||
|
|
d474c1c26d | ||
|
|
29ec43bdc8 | ||
|
|
cabc05b06c | ||
|
|
89e820d62e | ||
|
|
88616007b0 | ||
|
|
b262a1eedc | ||
|
|
b8ce722a2c | ||
|
|
b8fa4af06a | ||
|
|
ea8f041a20 | ||
|
|
52e8cdb011 | ||
|
|
ac9f47783c | ||
|
|
27f9aa16d6 | ||
|
|
08dc649b9a | ||
|
|
bb1a373272 | ||
|
|
e192f68891 | ||
|
|
73654791c1 | ||
|
|
8908458942 | ||
|
|
26792283ab | ||
|
|
32a92a4695 | ||
|
|
3bea2ae419 | ||
|
|
58eaf19026 | ||
|
|
d513e68fab | ||
|
|
ca8bbb27a0 | ||
|
|
287dab27ae | ||
|
|
25c26519ed | ||
|
|
cf66c8d507 | ||
|
|
318bb767a5 | ||
|
|
ad6148f0f6 | ||
|
|
8042d3f22a | ||
|
|
c7259fc424 | ||
|
|
62c949df6e | ||
|
|
8c7dc342e0 | ||
|
|
d15439aeac | ||
|
|
c19c64a990 | ||
|
|
8e374d9416 | ||
|
|
49216ce365 | ||
|
|
812c58297f | ||
|
|
2a04df1049 | ||
|
|
2eda624653 | ||
|
|
2f8aa7a351 | ||
|
|
b6115f0147 | ||
|
|
5ff22a1a77 | ||
|
|
7fdf8fee13 | ||
|
|
45a9ea666e | ||
|
|
efd5d0e410 | ||
|
|
6dbe95a0b5 | ||
|
|
a0ec06a487 | ||
|
|
ebf4b4b48a | ||
|
|
4f99efaaf4 | ||
|
|
62c30d9130 | ||
|
|
21fb953d0f | ||
|
|
27c98070e8 | ||
|
|
039750a7fa | ||
|
|
9b0d1bd054 | ||
|
|
4c1c2a5661 | ||
|
|
791d9aecfc | ||
|
|
48aaac90fb | ||
|
|
bfaa3a3a92 | ||
|
|
6dce685105 | ||
|
|
8c4e33faef | ||
|
|
81582b04f9 | ||
|
|
dbcc72a6f6 | ||
|
|
9f207f161a | ||
|
|
1ee4039681 | ||
|
|
3203814940 | ||
|
|
acc8c33260 | ||
|
|
22ecf505e3 | ||
|
|
c2c14410d2 | ||
|
|
ba578c91a7 | ||
|
|
7b46391e30 | ||
|
|
ae551cafea | ||
|
|
672c770dbe | ||
|
|
847046a225 | ||
|
|
4da998ab45 | ||
|
|
b534ea60f5 | ||
|
|
549ccff5eb | ||
|
|
9cf6749b2e | ||
|
|
d2999cf1d7 | ||
|
|
391b55ceaf | ||
|
|
e05345d3bb | ||
|
|
67bd54e55d | ||
|
|
20919fd6db | ||
|
|
ada2af04ff | ||
|
|
fcb6f762a9 | ||
|
|
5645f31934 | ||
|
|
a7295e2d03 | ||
|
|
c3e6ac2cac | ||
|
|
f1f3c8c8fe | ||
|
|
81b2f2e15a | ||
|
|
f6fdaf6492 | ||
|
|
519c5d686a | ||
|
|
f7e62ccbcc | ||
|
|
19161c0c92 | ||
|
|
c528303841 | ||
|
|
a439288765 | ||
|
|
416410912d | ||
|
|
b3f26f00e2 | ||
|
|
90e6ecdd11 | ||
|
|
842354bc5a | ||
|
|
4d3875cec2 | ||
|
|
74dfe49046 | ||
|
|
d0f23ed9e0 | ||
|
|
8a0992315e | ||
|
|
18b5cb10dc | ||
|
|
8afc6f208d | ||
|
|
d35d931179 | ||
|
|
093174e757 | ||
|
|
ac78762910 | ||
|
|
fff656f7e4 | ||
|
|
83b36e4c76 | ||
|
|
b42895b5c0 | ||
|
|
42e4b9addc | ||
|
|
91ab0e4a76 | ||
|
|
51feec3785 | ||
|
|
20eee3818e | ||
|
|
94cd6226ea | ||
|
|
5534ecf1b1 | ||
|
|
d498df3933 | ||
|
|
75bf62ca80 | ||
|
|
ad42357dd6 | ||
|
|
2de899342a | ||
|
|
8df48dc69d | ||
|
|
0f2809d2e9 | ||
|
|
aa44153af7 | ||
|
|
ce9c5162bd | ||
|
|
5c0da56ad5 | ||
|
|
08858c2a10 | ||
|
|
0268aeb25f | ||
|
|
ea3aba8971 | ||
|
|
265bfcf9d7 | ||
|
|
7a9fae5892 | ||
|
|
f66b0cc0aa | ||
|
|
e7f30106c0 | ||
|
|
86d2800b59 | ||
|
|
e65006042d | ||
|
|
65efc89b78 | ||
|
|
ae38834507 | ||
|
|
4261777613 | ||
|
|
7bc089f5c5 | ||
|
|
c46e3e8cf7 | ||
|
|
180d554205 | ||
|
|
a450d2e741 | ||
|
|
d528196033 | ||
|
|
0da2cbf84e | ||
|
|
20f981bc42 | ||
|
|
9a5514ffe0 | ||
|
|
439b4ad190 | ||
|
|
9a9c06966b | ||
|
|
b3f9baac8f | ||
|
|
bb961489b0 | ||
|
|
d6ae1f8375 | ||
|
|
5a1361167e | ||
|
|
4d5172f67e | ||
|
|
6f01c31458 | ||
|
|
6cfb208f3f | ||
|
|
3074892f1b | ||
|
|
b05d977cf9 | ||
|
|
36d183d988 | ||
|
|
b154fd56fb | ||
|
|
3419f69246 | ||
|
|
8e23301028 | ||
|
|
72724ee389 | ||
|
|
ae59a053b1 | ||
|
|
e71919226b | ||
|
|
6c5dd75216 | ||
|
|
23095728f5 | ||
|
|
498dacb4d2 | ||
|
|
b373a069e9 | ||
|
|
1d67e2f955 | ||
|
|
9a6935bf40 | ||
|
|
921ffefd90 | ||
|
|
a4fccd43eb | ||
|
|
48e1a8295b | ||
|
|
890c8c1905 | ||
|
|
38d50ce6fb | ||
|
|
14768d6947 | ||
|
|
b96399b563 | ||
|
|
d8c008dc7d | ||
|
|
b2ae5f4f4b | ||
|
|
ba871d7855 | ||
|
|
a0c8fc2ddb | ||
|
|
2a12053122 | ||
|
|
1860f21efb | ||
|
|
541adf6bb1 | ||
|
|
a71e90ddb8 | ||
|
|
60f4b3cdb8 | ||
|
|
0c249fa126 | ||
|
|
db1b57900b | ||
|
|
12b4898b3d | ||
|
|
f5f9bab77c | ||
|
|
ba7aa674d1 | ||
|
|
f670be4315 | ||
|
|
a658861fde | ||
|
|
192e5a1f79 | ||
|
|
475b15e372 | ||
|
|
d2ed91ccc8 | ||
|
|
333f4a1d3c | ||
|
|
832fe2f0b0 | ||
|
|
ea76185873 | ||
|
|
51c3ea184a | ||
|
|
692bccc4fc | ||
|
|
59fe76f29b | ||
|
|
51c2a0d732 | ||
|
|
2ab01b55c9 | ||
|
|
461f9e736b | ||
|
|
8e16b03ae8 | ||
|
|
6469809b9a | ||
|
|
0205adcedb | ||
|
|
0a0dbe115a | ||
|
|
a3fd36e2bb |
No files matched your search
+3
-2
@@ -46,8 +46,8 @@ prog/weavewait/weavewait_noop
|
|||||||
prog/weavewait/weavewait_nomcast
|
prog/weavewait/weavewait_nomcast
|
||||||
prog/weaveutil/weaveutil
|
prog/weaveutil/weaveutil
|
||||||
prog/*/Dockerfile.weaveworks
|
prog/*/Dockerfile.weaveworks
|
||||||
prog/kube-peers/kube-peers
|
prog/kube-utils/kube-utils
|
||||||
prog/weave-kube/kube-peers
|
prog/weave-kube/kube-utils
|
||||||
prog/weave-npc/weave-npc
|
prog/weave-npc/weave-npc
|
||||||
prog/plugin/plugin
|
prog/plugin/plugin
|
||||||
testing/cover/cover
|
testing/cover/cover
|
||||||
@@ -68,6 +68,7 @@ test/tls/tls
|
|||||||
test/tls/*.pem
|
test/tls/*.pem
|
||||||
test/coverage
|
test/coverage
|
||||||
test/coverage.*
|
test/coverage.*
|
||||||
|
test/images/network-tester/webserver
|
||||||
*qemu-*-static
|
*qemu-*-static
|
||||||
terraform.tfstate
|
terraform.tfstate
|
||||||
terraform.tfstate.backup
|
terraform.tfstate.backup
|
||||||
|
|||||||
-177
@@ -1,180 +1,3 @@
|
|||||||
[submodule "tools"]
|
[submodule "tools"]
|
||||||
path = tools
|
path = tools
|
||||||
url = https://github.com/weaveworks/build-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
|
|
||||||
+150
@@ -1,3 +1,153 @@
|
|||||||
|
## Release 2.4.0
|
||||||
|
|
||||||
|
This release introduces a support for Kubernetes Egress Network Policy (#2624, #3313)
|
||||||
|
and adds a mechanism for preserving the client source IP address to enable
|
||||||
|
`externalTrafficPolicy: Local` on Kubernetes (#2924, #3298).
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
* Increase the ipset list size which prevents weave-npc from crashing on older
|
||||||
|
kernels when more than eight Kubernetes Namespaces are used (#3289, #3305).
|
||||||
|
* Avoid a possible livelock when reclaiming IP address space in weave-kube (#3317).
|
||||||
|
* Ensure `xtables.lock` is mounted as a file so that kube-proxy can take the lock
|
||||||
|
if it has started after Weave Net (#3351, #3353).
|
||||||
|
* Upgrade the CNI plugin symlinks only if the plugin has changed (#3337, #3345).
|
||||||
|
|
||||||
|
### Other improvements
|
||||||
|
|
||||||
|
* Manipulate the Kubernetes node status `NetworkUnavailable` so that Pods can be
|
||||||
|
scheduled on nodes when the GCE cloud provider is in use (#3249, #3307, #3332, #3334).
|
||||||
|
* Refrain from creating a subprocess for configuring a network interface in
|
||||||
|
a container network namespace (#3291).
|
||||||
|
* Protect against handling the CNI plugin request with the host namespace which
|
||||||
|
prevents Weave Net from misconfiguring the host network (#3206, #3346).
|
||||||
|
* Weave Net can be run on minikube VM (#3124).
|
||||||
|
* Add `org.opencontainers.image.*` labels to Dockerfiles to improve association
|
||||||
|
of the container images with git revisions (#3299).
|
||||||
|
* Improve the error message when running `weave reset` on Kubernetes (#3319).
|
||||||
|
|
||||||
|
### Build and Testing
|
||||||
|
|
||||||
|
* Use `dep` instead of `git submodules` for managing external packages (#3268).
|
||||||
|
* Fix usage of `manifest-tool` in Makefile (#3320).
|
||||||
|
* Update Kubernetes to 1.11 for the integration tests (#3340).
|
||||||
|
|
||||||
|
### External Contributors
|
||||||
|
|
||||||
|
Thanks to the following contributors:
|
||||||
|
|
||||||
|
* @kitt1987
|
||||||
|
* @louismunro
|
||||||
|
* @Nodraak
|
||||||
|
* @stevenjohnstone
|
||||||
|
|
||||||
|
[Full list of changes](https://github.com/weaveworks/weave/milestone/73?closed=1)
|
||||||
|
|
||||||
|
## Release 2.3.0
|
||||||
|
|
||||||
|
### Security fixes
|
||||||
|
|
||||||
|
* By default, do not expose Weave "/status" and "/report" to all (0.0.0.0) when
|
||||||
|
running on Kubernetes #3271
|
||||||
|
|
||||||
|
### Other improvements
|
||||||
|
|
||||||
|
* Increase the default connection limit for Weave peers (from 30 to 100) when
|
||||||
|
running on Kubernetes, so that more peers could directly connect #3265
|
||||||
|
|
||||||
|
## Build and test
|
||||||
|
|
||||||
|
* Build Weave Net with Go 1.10.1 #3273
|
||||||
|
* Run integration tests against Kubernetes 1.10.0 #3266
|
||||||
|
|
||||||
|
[Full list of changes](https://github.com/weaveworks/weave/milestone/70?closed=1)
|
||||||
|
|
||||||
|
## Release 2.2.1
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
* Fix a bug in weave-npc which would allow ingress traffic to Kubernetes Pods selected
|
||||||
|
by a NetworkPolicy in which source and destination selectors were the same #3222,#3237
|
||||||
|
* Fix a bug in weave-npc which would crash if a previously deleted Kubernetes Namespace
|
||||||
|
has been created again #3247,#3250
|
||||||
|
|
||||||
|
### Other improvements
|
||||||
|
|
||||||
|
* Increase the default connection limit for Weave peers (from 30 to 100), so that
|
||||||
|
more peers could directly connect #3234
|
||||||
|
* When doing a rolling update of Weave Net on Kubernetes, allow each node five seconds
|
||||||
|
to initialize before rolling next Weave Net Pod, so that issues at startup will halt
|
||||||
|
the rollout and not spread across the whole cluster #3235
|
||||||
|
* Install common CA certificates from Alpine Linux package instead of copying
|
||||||
|
them manually #3236
|
||||||
|
|
||||||
|
### External contributors
|
||||||
|
|
||||||
|
Thanks to the following contributors:
|
||||||
|
|
||||||
|
* @alok87
|
||||||
|
|
||||||
|
[Full list of changes](https://github.com/weaveworks/weave/milestone/71?closed=1)
|
||||||
|
|
||||||
|
## Release 2.2.0
|
||||||
|
|
||||||
|
This release improves the way Weave Net configures Linux network
|
||||||
|
devices and network filter rules, so that it is more robust in the face
|
||||||
|
of unexpected changes in its environment. #3204,#3224
|
||||||
|
|
||||||
|
As a consequence of these changes, the `weave attach` command will now
|
||||||
|
fail unless the Weave Net daemon is up and running - previously it was
|
||||||
|
possible to run independently as long as you managed all IP addresses
|
||||||
|
yourself.
|
||||||
|
|
||||||
|
## Other improvements
|
||||||
|
|
||||||
|
* Update library miekg/dns for CVE-2017-15133 (details under embargo) #3223,#3227
|
||||||
|
* Reduce the volume of logging from weave-npc #3183
|
||||||
|
* Add ability to set log level for Docker "v2" plugin, and change
|
||||||
|
default log level from DEBUG to INFO #3197
|
||||||
|
* Downgrade log messages about Discovery and Expiration to DEBUG level #3202,#3203
|
||||||
|
* Use command-line parameter for WeaveDNS address in Docker proxy #3196
|
||||||
|
|
||||||
|
## Bug fixes
|
||||||
|
|
||||||
|
* Ensure that rules to block traffic for NetworkPolicy are placed
|
||||||
|
ahead of rules that Kubernetes has added to allow other traffic #3209,#3210
|
||||||
|
|
||||||
|
## Build and test
|
||||||
|
|
||||||
|
* Update CI tests to use Kubernetes 1.9.2 #3229
|
||||||
|
* Remove "daily update" from test VMs that only run for a few minutes #3224
|
||||||
|
|
||||||
|
## External Contributors
|
||||||
|
|
||||||
|
Thanks to the following contributors:
|
||||||
|
@vetal4444
|
||||||
|
|
||||||
|
[Full list of changes](https://github.com/weaveworks/weave/milestone/67?closed=1)
|
||||||
|
|
||||||
|
|
||||||
|
## Release 2.1.3
|
||||||
|
|
||||||
|
This release fixes a race-condition in the IP reclaim code for weave-kube
|
||||||
|
where two nodes could end up fighting over the same space and break
|
||||||
|
connectivity #3190, #3192
|
||||||
|
|
||||||
|
## Release 2.1.2
|
||||||
|
|
||||||
|
This release fixes a couple of bugs discovered since the release of Weave Net 2.1.0
|
||||||
|
|
||||||
|
##Bug fixes
|
||||||
|
|
||||||
|
* Fix crash seen when starting 10-15 nodes simultaneously #3184,#3186
|
||||||
|
* Fix NetworkPolicy blocking traffic if updates come out of order from Kubernetes #3177,#3181
|
||||||
|
|
||||||
|
Thanks to the following contributors:
|
||||||
|
@zignig
|
||||||
|
|
||||||
|
[Full list of changes](https://github.com/weaveworks/weave/milestone/66?closed=1)
|
||||||
|
|
||||||
|
|
||||||
## Release 2.1.1
|
## Release 2.1.1
|
||||||
|
|
||||||
As 2.1.0, but fixing a couple of installation glitches. #3175,#3176
|
As 2.1.0, but fixing a couple of installation glitches. #3175,#3176
|
||||||
|
|||||||
@@ -24,6 +24,25 @@ taking the time to read this guide.
|
|||||||
* Keep pull requests small so core developers can review them quickly.
|
* 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.
|
* 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
|
## Workflow
|
||||||
See [WorkingOnWeave](https://github.com/weaveworks/weave/wiki/WorkingOnWeave)
|
See [WorkingOnWeave](https://github.com/weaveworks/weave/wiki/WorkingOnWeave)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
DOCKER_VERSION=17.06
|
DOCKER_VERSION=17.06
|
||||||
KUBERNETES_VERSION=1.7.8
|
KUBERNETES_VERSION=1.11.0
|
||||||
KUBERNETES_CNI_VERSION=0.5.1
|
KUBERNETES_CNI_VERSION=0.6.0
|
||||||
Generated
+782
@@ -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
@@ -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
|
||||||
@@ -101,6 +101,7 @@ endif
|
|||||||
# The name of the user that this Makefile should produce image artifacts for. Can/should be overridden
|
# The name of the user that this Makefile should produce image artifacts for. Can/should be overridden
|
||||||
DOCKERHUB_USER?=weaveworks
|
DOCKERHUB_USER?=weaveworks
|
||||||
# The default version that's chosen when pushing the images. Can/should be overridden
|
# 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)
|
WEAVE_VERSION?=git-$(shell git rev-parse --short=12 HEAD)
|
||||||
# Docker Store does not allow the "latest" tag.
|
# Docker Store does not allow the "latest" tag.
|
||||||
NET_PLUGIN_LATEST=latest_release
|
NET_PLUGIN_LATEST=latest_release
|
||||||
@@ -108,20 +109,20 @@ NET_PLUGIN_LATEST=latest_release
|
|||||||
# Paths to all relevant binaries that should be compiled
|
# Paths to all relevant binaries that should be compiled
|
||||||
WEAVER_EXE=prog/weaver/weaver
|
WEAVER_EXE=prog/weaver/weaver
|
||||||
SIGPROXY_EXE=prog/sigproxy/sigproxy
|
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
|
WEAVENPC_EXE=prog/weave-npc/weave-npc
|
||||||
WEAVEWAIT_EXE=prog/weavewait/weavewait
|
WEAVEWAIT_EXE=prog/weavewait/weavewait
|
||||||
WEAVEWAIT_NOOP_EXE=prog/weavewait/weavewait_noop
|
WEAVEWAIT_NOOP_EXE=prog/weavewait/weavewait_noop
|
||||||
WEAVEWAIT_NOMCAST_EXE=prog/weavewait/weavewait_nomcast
|
WEAVEWAIT_NOMCAST_EXE=prog/weavewait/weavewait_nomcast
|
||||||
WEAVEUTIL_EXE=prog/weaveutil/weaveutil
|
WEAVEUTIL_EXE=prog/weaveutil/weaveutil
|
||||||
RUNNER_EXE=tools/runner/runner
|
RUNNER_EXE=tools/runner/runner
|
||||||
MANIFEST_TOOL_DIR=vendor/github.com/estesp/manifest-tool
|
# manifest-tool needs registry credentials; we assume here that the active user has logged in
|
||||||
MANIFEST_TOOL_EXE=$(MANIFEST_TOOL_DIR)/manifest-tool
|
MANIFEST_TOOL_CMD=docker run --rm -v $(HOME)/.docker:/.docker weshigbee/manifest-tool --docker-cfg=/.docker
|
||||||
TEST_TLS_EXE=test/tls/tls
|
TEST_TLS_EXE=test/tls/tls
|
||||||
NETWORKTESTER_EXE=test/images/network-tester/webserver
|
NETWORKTESTER_EXE=test/images/network-tester/webserver
|
||||||
|
|
||||||
# All binaries together in a list
|
# 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
|
# 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
|
BUILD_UPTODATE=.build.uptodate
|
||||||
@@ -179,11 +180,10 @@ $(WEAVER_EXE): api/*.go plugin/*.go plugin/*/*
|
|||||||
$(WEAVER_EXE): proxy/*.go
|
$(WEAVER_EXE): proxy/*.go
|
||||||
$(WEAVEUTIL_EXE): prog/weaveutil/*.go net/*.go plugin/net/*.go plugin/ipam/*.go db/*.go
|
$(WEAVEUTIL_EXE): prog/weaveutil/*.go net/*.go plugin/net/*.go plugin/ipam/*.go db/*.go
|
||||||
$(SIGPROXY_EXE): prog/sigproxy/*.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
|
$(WEAVENPC_EXE): prog/weave-npc/*.go npc/*.go npc/*/*.go
|
||||||
$(TEST_TLS_EXE): test/tls/*.go
|
$(TEST_TLS_EXE): test/tls/*.go
|
||||||
$(RUNNER_EXE): tools/runner/*.go
|
$(RUNNER_EXE): tools/runner/*.go
|
||||||
$(MANIFEST_TOOL_EXE): $(MANIFEST_TOOL_DIR)/*.go
|
|
||||||
$(WEAVEWAIT_NOOP_EXE): prog/weavewait/*.go
|
$(WEAVEWAIT_NOOP_EXE): prog/weavewait/*.go
|
||||||
$(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
|
$(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
|
||||||
$(WEAVEWAIT_NOMCAST_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
|
# 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
|
# It bind-mounts the source into the container and passes all important variables
|
||||||
exes $(EXES) tests lint: $(BUILD_UPTODATE)
|
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
|
@mkdir -p $(shell pwd)/.pkg
|
||||||
$(SUDO) docker run $(RM) $(RUN_FLAGS) \
|
$(SUDO) docker run $(RM) $(RUN_FLAGS) \
|
||||||
-v $(shell pwd):/go/src/github.com/weaveworks/weave \
|
-v $(shell pwd):/go/src/github.com/weaveworks/weave \
|
||||||
@@ -220,7 +217,7 @@ else
|
|||||||
endif
|
endif
|
||||||
$(NETGO_CHECK)
|
$(NETGO_CHECK)
|
||||||
|
|
||||||
$(WEAVEUTIL_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE) $(NETWORKTESTER_EXE):
|
$(WEAVEUTIL_EXE) $(KUBEUTILS_EXE) $(WEAVENPC_EXE) $(NETWORKTESTER_EXE):
|
||||||
go build $(BUILD_FLAGS) -o $@ ./$(@D)
|
go build $(BUILD_FLAGS) -o $@ ./$(@D)
|
||||||
$(NETGO_CHECK)
|
$(NETGO_CHECK)
|
||||||
|
|
||||||
@@ -234,7 +231,7 @@ $(WEAVEWAIT_NOMCAST_EXE):
|
|||||||
|
|
||||||
# These programs need a separate rule as they fail the netgo check in
|
# These programs need a separate rule as they fail the netgo check in
|
||||||
# the main build stanza due to not importing net package
|
# 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)
|
go build $(BUILD_FLAGS) -o $@ ./$(@D)
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
@@ -274,7 +271,7 @@ endif
|
|||||||
$(WEAVER_UPTODATE): prog/weaver/Dockerfile.$(DOCKERHUB_USER) $(WEAVER_EXE) weave $(WEAVEUTIL_EXE)
|
$(WEAVER_UPTODATE): prog/weaver/Dockerfile.$(DOCKERHUB_USER) $(WEAVER_EXE) weave $(WEAVEUTIL_EXE)
|
||||||
cp $(WEAVEUTIL_EXE) prog/weaver/weaveutil
|
cp $(WEAVEUTIL_EXE) prog/weaver/weaveutil
|
||||||
cp weave prog/weaver/weave
|
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 $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexec/symlink $(SIGPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVER_UPTODATE)
|
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexec/symlink $(SIGPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVER_UPTODATE)
|
||||||
@@ -282,7 +279,7 @@ $(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexe
|
|||||||
cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait
|
cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait
|
||||||
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
|
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
|
||||||
cp $(WEAVEWAIT_NOMCAST_EXE) prog/weaveexec/weavewait_nomcast
|
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 $@
|
touch $@
|
||||||
|
|
||||||
# Builds Docker plugin.
|
# 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
|
$(SUDO) docker plugin create $(PLUGIN_IMAGE):$(NET_PLUGIN_LATEST) prog/net-plugin
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVEKUBE_UPTODATE): prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) prog/weave-kube/launch.sh $(KUBEPEERS_EXE) $(WEAVER_UPTODATE)
|
$(WEAVEKUBE_UPTODATE): prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) prog/weave-kube/launch.sh $(KUBEUTILS_EXE) $(WEAVER_UPTODATE)
|
||||||
cp $(KUBEPEERS_EXE) prog/weave-kube/
|
cp $(KUBEUTILS_EXE) prog/weave-kube/
|
||||||
$(SUDO) docker build -f prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVEKUBE_IMAGE) 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 $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVENPC_UPTODATE): prog/weave-npc/Dockerfile.$(DOCKERHUB_USER) $(WEAVENPC_EXE) prog/weave-npc/ulogd.conf
|
$(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 $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVEDB_UPTODATE): prog/weavedb/Dockerfile
|
$(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 $@
|
touch $@
|
||||||
|
|
||||||
$(NETWORKTESTER_UPTODATE): test/images/network-tester/Dockerfile $(NETWORKTESTER_EXE)
|
$(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)
|
$(WEAVE_EXPORT): $(IMAGES_UPTODATE) $(WEAVEDB_UPTODATE)
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker save $(addsuffix :latest,$(IMAGES)) | gzip > $@
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker save $(addsuffix :latest,$(IMAGES)) | gzip > $@
|
||||||
|
|
||||||
tools/.git $(MANIFEST_TOOL_DIR)/.git:
|
tools/.git:
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
|
||||||
# CODE FOR PUBLISHING THE IMAGES
|
# CODE FOR PUBLISHING THE IMAGES
|
||||||
@@ -378,13 +375,13 @@ endif
|
|||||||
|
|
||||||
# This target pushes a manifest list; it takes one parameter, the image name.
|
# 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
|
# 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)
|
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
|
endif
|
||||||
ifneq ($(UPDATE_LATEST),false)
|
ifneq ($(UPDATE_LATEST),false)
|
||||||
# Push the manifest list to :latest as well
|
# 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
|
endif
|
||||||
|
|
||||||
clean-work-dir:
|
clean-work-dir:
|
||||||
@@ -398,7 +395,7 @@ clean-bin:
|
|||||||
|
|
||||||
clean: clean-bin clean-work-dir
|
clean: clean-bin clean-work-dir
|
||||||
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(BUILD_IMAGE)
|
-$(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:
|
build:
|
||||||
$(SUDO) go clean -i net
|
$(SUDO) go clean -i net
|
||||||
|
|||||||
+17
-2
@@ -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.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.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.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
|
make SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER
|
||||||
|
|
||||||
if make tests; then
|
if make tests; then
|
||||||
@@ -181,6 +182,13 @@ draft() {
|
|||||||
--name "weave-daemonset-k8s-1.7.yaml" \
|
--name "weave-daemonset-k8s-1.7.yaml" \
|
||||||
--file "./prog/weave-kube/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 "** Draft $TYPE $RELEASE_NAME $VERSION created at"
|
||||||
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG"
|
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG"
|
||||||
}
|
}
|
||||||
@@ -196,7 +204,7 @@ publish() {
|
|||||||
|
|
||||||
if [ "$RELEASE_TYPE" = 'PRERELEASE' ] ; then
|
if [ "$RELEASE_TYPE" = 'PRERELEASE' ] ; then
|
||||||
echo "== Building and pushing plugin"
|
echo "== Building and pushing plugin"
|
||||||
make UPDATE_LATEST=$IS_MAINLINE SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
|
make UPDATE_LATEST=false SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
|
||||||
echo "** Plugin built and pushed"
|
echo "** Plugin built and pushed"
|
||||||
|
|
||||||
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
|
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
|
||||||
@@ -232,7 +240,7 @@ publish() {
|
|||||||
echo '** Sanity checks OK for publishing tag' $LATEST_TAG as $DOCKERHUB_USER/weave:$VERSION
|
echo '** Sanity checks OK for publishing tag' $LATEST_TAG as $DOCKERHUB_USER/weave:$VERSION
|
||||||
|
|
||||||
echo "== Building and pushing plugin"
|
echo "== Building and pushing plugin"
|
||||||
make UPDATE_LATEST=$IS_MAINLINE SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
|
make UPDATE_LATEST=true SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER plugin_publish
|
||||||
echo "** Plugin built and pushed"
|
echo "** Plugin built and pushed"
|
||||||
|
|
||||||
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
|
echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER"
|
||||||
@@ -289,6 +297,13 @@ publish() {
|
|||||||
--name "weave-daemonset-k8s-1.7.yaml" \
|
--name "weave-daemonset-k8s-1.7.yaml" \
|
||||||
--file "./prog/weave-kube/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 "** 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_TAG"
|
||||||
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/latest_release"
|
echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/latest_release"
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.8.1
|
FROM golang:1.10.1-stretch
|
||||||
|
|
||||||
# Support Raspberry Pi 2 and newer
|
# Support Raspberry Pi 2 and newer
|
||||||
ENV GOARM 7
|
ENV GOARM 7
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ test:
|
|||||||
parallel: true
|
parallel: true
|
||||||
- "$SRCDIR/bin/circle-test-smoke":
|
- "$SRCDIR/bin/circle-test-smoke":
|
||||||
parallel: true
|
parallel: true
|
||||||
timeout: 300
|
timeout: 360
|
||||||
post:
|
post:
|
||||||
- "$SRCDIR/bin/circle-test-teardown":
|
- "$SRCDIR/bin/circle-test-teardown":
|
||||||
parallel: true
|
parallel: true
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ func (c *Client) EnsureNetwork(networkName, driver, subnet string, options map[s
|
|||||||
Name: networkName,
|
Name: networkName,
|
||||||
CheckDuplicate: true,
|
CheckDuplicate: true,
|
||||||
Driver: driver,
|
Driver: driver,
|
||||||
IPAM: docker.IPAMOptions{
|
IPAM: &docker.IPAMOptions{
|
||||||
Driver: driver,
|
Driver: driver,
|
||||||
Config: []docker.IPAMConfig{{Subnet: subnet}},
|
Config: []docker.IPAMConfig{{Subnet: subnet}},
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type textFormatter struct {
|
type textFormatter struct {
|
||||||
|
|||||||
@@ -75,6 +75,14 @@ func DeleteDatapath(dpname string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AddDatapathInterface(dpname string, ifname 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()
|
dpif, err := odp.NewDpif()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -87,5 +95,9 @@ func AddDatapathInterface(dpname string, ifname string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = dp.CreateVport(odp.NewNetdevVportSpec(ifname))
|
_, err = dp.CreateVport(odp.NewNetdevVportSpec(ifname))
|
||||||
|
if ignoreIfExist && err == odp.NetlinkError(syscall.EEXIST) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -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
@@ -127,14 +127,52 @@ Finally, for **Mainline** releases only:
|
|||||||
|
|
||||||
* Images tagged `latest` are updated on DockerHub
|
* 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
|
### Finish up
|
||||||
|
|
||||||
* If not on master, merge branch into master and push to GitHub.
|
* 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
|
* 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)
|
* 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
|
* 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
|
tag, push to GitHub and set [WEAVE_NET_REV](https://github.com/weaveworks/website-next/blob/master/Makefile)
|
||||||
published to https://www.weave.works
|
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
|
* Add the new version of `weave-net` to the checkpoint system at
|
||||||
https://checkpoint-api.weave.works/admin
|
https://checkpoint-api.weave.works/admin
|
||||||
* File a PR to update the version of the daemonset at
|
* File a PR to update the version of the daemonset at
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ type Allocator struct {
|
|||||||
isKnownPeer func(mesh.PeerName) bool
|
isKnownPeer func(mesh.PeerName) bool
|
||||||
quorum func() uint
|
quorum func() uint
|
||||||
now func() time.Time
|
now func() time.Time
|
||||||
|
tracker tracker.LocalRangeTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreClaims are IP addresses discovered before we could initialize IPAM
|
// PreClaims are IP addresses discovered before we could initialize IPAM
|
||||||
@@ -130,6 +131,7 @@ func NewAllocator(config Config) *Allocator {
|
|||||||
quorum: config.Quorum,
|
quorum: config.Quorum,
|
||||||
dead: make(map[string]time.Time),
|
dead: make(map[string]time.Time),
|
||||||
now: time.Now,
|
now: time.Now,
|
||||||
|
tracker: config.Tracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc.pendingClaims = make([]operation, len(config.PreClaims))
|
alloc.pendingClaims = make([]operation, len(config.PreClaims))
|
||||||
|
|||||||
+2
-2
@@ -88,7 +88,7 @@ func (alloc *Allocator) handleHTTPClaim(dockerCli *docker.Client, w http.Respons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HandleHTTP wires up ipams HTTP endpoints to the provided mux.
|
// 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) {
|
router.Methods("GET").Path("/ipinfo/defaultsubnet").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "%s", defaultSubnet)
|
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) {
|
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
@@ -43,7 +43,7 @@ func listenHTTP(alloc *Allocator, subnet address.CIDR) int {
|
|||||||
router.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
|
router.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
|
||||||
io.WriteString(w, fmt.Sprintln(alloc))
|
io.WriteString(w, fmt.Sprintln(alloc))
|
||||||
})
|
})
|
||||||
alloc.HandleHTTP(router, subnet, "", nil)
|
alloc.HandleHTTP(router, subnet, nil)
|
||||||
|
|
||||||
httpListener, err := net.Listen("tcp", ":0")
|
httpListener, err := net.Listen("tcp", ":0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -132,7 +132,7 @@ func TestBadHttp(t *testing.T) {
|
|||||||
// Verb that's not handled
|
// Verb that's not handled
|
||||||
resp, err := doHTTP("HEAD", fmt.Sprintf("http://localhost:%d/ip/%s/%s", port, containerID, testAddr1))
|
resp, err := doHTTP("HEAD", fmt.Sprintf("http://localhost:%d/ip/%s/%s", port, containerID, testAddr1))
|
||||||
require.NoError(t, err)
|
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
|
// Mis-spelled URL
|
||||||
resp, err = doHTTP("POST", fmt.Sprintf("http://localhost:%d/xip/%s/", port, containerID))
|
resp, err = doHTTP("POST", fmt.Sprintf("http://localhost:%d/xip/%s/", port, containerID))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func CheckAllExpectedMessagesSent(allocs ...*Allocator) {
|
|||||||
m := alloc.gossip.(*mockGossipComms)
|
m := alloc.gossip.(*mockGossipComms)
|
||||||
m.RLock()
|
m.RLock()
|
||||||
if len(m.messages) > 0 {
|
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()
|
m.RUnlock()
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-42
@@ -84,7 +84,7 @@ func NewAWSVPCTracker(bridgeName string) (*AWSVPCTracker, error) {
|
|||||||
func (t *AWSVPCTracker) HandleUpdate(prevRanges, currRanges []address.Range, local bool) error {
|
func (t *AWSVPCTracker) HandleUpdate(prevRanges, currRanges []address.Range, local bool) error {
|
||||||
t.debugf("replacing %q by %q; local(%t)", prevRanges, currRanges, local)
|
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
|
// 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
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *AWSVPCTracker) String() string {
|
||||||
|
return "awsvpc"
|
||||||
|
}
|
||||||
|
|
||||||
func (t *AWSVPCTracker) createVPCRoute(cidr string) (*ec2.CreateRouteOutput, error) {
|
func (t *AWSVPCTracker) createVPCRoute(cidr string) (*ec2.CreateRouteOutput, error) {
|
||||||
route := &ec2.CreateRouteInput{
|
route := &ec2.CreateRouteInput{
|
||||||
RouteTableId: &t.routeTableID,
|
RouteTableId: &t.routeTableID,
|
||||||
@@ -232,47 +236,6 @@ func (t *AWSVPCTracker) infof(fmt string, args ...interface{}) {
|
|||||||
|
|
||||||
// Helpers
|
// 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) {
|
func parseCIDR(cidr string) (*net.IPNet, error) {
|
||||||
ip, ipnet, err := net.ParseCIDR(cidr)
|
ip, ipnet, err := net.ParseCIDR(cidr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -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) {
|
func TestRemoveCommon(t *testing.T) {
|
||||||
a := []address.CIDR{r0to127, r1dot0to255}
|
a := []address.CIDR{r0to127, r1dot0to255}
|
||||||
b := []address.CIDR{r1dot0to255, r2dot0to255}
|
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{r0to127}, newA)
|
||||||
require.Equal(t, []address.CIDR{r2dot0to255}, newB)
|
require.Equal(t, []address.CIDR{r2dot0to255}, newB)
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ func TestMerge(t *testing.T) {
|
|||||||
r128to255.Range(),
|
r128to255.Range(),
|
||||||
r2dot0to255.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
|
// Helper
|
||||||
@@ -17,4 +17,7 @@ type LocalRangeTracker interface {
|
|||||||
// The local parameter indicates whether the ranges belong to the peer
|
// The local parameter indicates whether the ranges belong to the peer
|
||||||
// by which the method is called.
|
// by which the method is called.
|
||||||
HandleUpdate(prevRanges, currRanges []address.Range, local bool) error
|
HandleUpdate(prevRanges, currRanges []address.Range, local bool) error
|
||||||
|
|
||||||
|
// String returns the tracker name
|
||||||
|
String() string
|
||||||
}
|
}
|
||||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
|||||||
// Configure the ARP cache parameters for the given interface. This
|
// Configure the ARP cache parameters for the given interface. This
|
||||||
// makes containers react more quickly to a change in the MAC address
|
// makes containers react more quickly to a change in the MAC address
|
||||||
// associated with an IP 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 {
|
if err := sysctl(procPath, fmt.Sprintf("net/ipv4/neigh/%s/base_reachable_time", name), "5"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+169
-47
@@ -6,12 +6,18 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/common/odp"
|
"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
|
/* 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 (
|
const (
|
||||||
WeaveBridgeName = "weave"
|
WeaveBridgeName = "weave"
|
||||||
DatapathName = "datapath"
|
DatapathName = "datapath"
|
||||||
DatapathIfName = "vethwe-datapath"
|
DatapathIfName = "vethwe-datapath"
|
||||||
BridgeIfName = "vethwe-bridge"
|
BridgeIfName = "vethwe-bridge"
|
||||||
PcapIfName = "vethwe-pcap"
|
PcapIfName = "vethwe-pcap"
|
||||||
|
NoMasqLocalIpset = ipset.Name("weaver-no-masq-local")
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bridge interface {
|
type Bridge interface {
|
||||||
@@ -213,6 +220,7 @@ type BridgeConfig struct {
|
|||||||
MTU int
|
MTU int
|
||||||
Mac string
|
Mac string
|
||||||
Port int
|
Port int
|
||||||
|
NoMasqLocal bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *BridgeConfig) configuredBridgeType() Bridge {
|
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) {
|
func EnsureBridge(procPath string, config *BridgeConfig, log *logrus.Logger, ips ipset.Interface) (Bridge, error) {
|
||||||
bridgeType, err := ExistingBridgeType(config.WeaveBridgeName, config.DatapathName)
|
existingBridgeType, err := ExistingBridgeType(config.WeaveBridgeName, config.DatapathName)
|
||||||
if bridgeType != nil || err != nil {
|
if err != nil {
|
||||||
return bridgeType, err
|
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 {
|
for {
|
||||||
if err := bridgeType.init(config); err != nil {
|
if err := bridgeType.init(config); err != nil {
|
||||||
if errors.Cause(err) == errBridgeNotSupported {
|
if errors.Cause(err) == errBridgeNotSupported {
|
||||||
@@ -245,7 +260,7 @@ func EnsureBridge(procPath string, config *BridgeConfig, log *logrus.Logger) (Br
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := configureIPTables(config); err != nil {
|
if err := configureIPTables(config, ips); err != nil {
|
||||||
return bridgeType, errors.Wrap(err, "configuring iptables")
|
return bridgeType, errors.Wrap(err, "configuring iptables")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,10 +283,16 @@ func EnsureBridge(procPath string, config *BridgeConfig, log *logrus.Logger) (Br
|
|||||||
return bridgeType, err
|
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)
|
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
|
return bridgeType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +309,7 @@ func (b bridgeImpl) initPrep(config *BridgeConfig) error {
|
|||||||
config.MTU = 65535
|
config.MTU = 65535
|
||||||
}
|
}
|
||||||
b.bridge = &netlink.Bridge{LinkAttrs: linkAttrs}
|
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)
|
return errors.Wrapf(err, "creating bridge %q", config.WeaveBridgeName)
|
||||||
}
|
}
|
||||||
if err := netlink.LinkSetHardwareAddr(b.bridge, mac); err != nil {
|
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 {
|
if err := b.initPrep(config); err != nil {
|
||||||
return err
|
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)
|
return netlink.LinkSetUp(veth)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errors.Wrap(err, "creating pcap veth pair")
|
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 {
|
if err := bf.bridgeImpl.initPrep(config); err != nil {
|
||||||
return err
|
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 {
|
if err := netlink.LinkSetUp(veth); err != nil {
|
||||||
return errors.Wrapf(err, "setting link up on %q", veth.Attrs().Name)
|
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 errors.Wrapf(err, "adding interface %q to datapath %q", veth.Attrs().Name, bf.datapathName)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -394,20 +415,21 @@ func (bf bridgedFastdpImpl) attach(veth *netlink.Veth) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f fastdpImpl) 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()
|
ipt, err := iptables.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "creating iptables object")
|
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.DockerBridgeName != "" {
|
||||||
if config.WeaveBridgeName != config.DockerBridgeName {
|
if config.WeaveBridgeName != config.DockerBridgeName {
|
||||||
err := ipt.Insert("filter", "FORWARD", 1, "-i", config.DockerBridgeName, "-o", config.WeaveBridgeName, "-j", "DROP")
|
fwdRules = append(fwdRules, []string{"-i", config.DockerBridgeName, "-o", config.WeaveBridgeName, "-j", "DROP"})
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerBridgeIP, err := FindBridgeIP(config.DockerBridgeName, nil)
|
dockerBridgeIP, err := FindBridgeIP(config.DockerBridgeName, nil)
|
||||||
@@ -436,48 +458,122 @@ func configureIPTables(config *BridgeConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.NPC {
|
if config.NPC {
|
||||||
// Steer traffic via the 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 = ensureChains(ipt, "filter", npc.MainChain, npc.EgressChain); err != nil {
|
||||||
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-j", "WEAVE-NPC"); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-m", "state", "--state", "NEW", "-j", "NFLOG", "--nflog-group", "86"); err != nil {
|
|
||||||
return err
|
// Steer egress traffic destined to local node.
|
||||||
}
|
if err = ipt.AppendUnique("filter", "INPUT", "-i", config.WeaveBridgeName, "-j", npc.EgressChain); err != nil {
|
||||||
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-j", "DROP"); err != nil {
|
|
||||||
return err
|
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 {
|
} else {
|
||||||
// Work around the situation where there are no rules allowing traffic
|
// Work around the situation where there are no rules allowing traffic
|
||||||
// across our bridge. E.g. ufw
|
// across our bridge. E.g. ufw
|
||||||
if err = ipt.AppendUnique("filter", "FORWARD", "-i", config.WeaveBridgeName, "-o", config.WeaveBridgeName, "-j", "ACCEPT"); err != nil {
|
fwdRules = append(fwdRules, []string{"-i", config.WeaveBridgeName, "-o", config.WeaveBridgeName, "-j", "ACCEPT"})
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.NPC {
|
if !config.NPC {
|
||||||
// Create a chain for allowing ingress traffic when the bridge is exposed
|
// Create/Flush a chain for allowing ingress traffic when the bridge is exposed
|
||||||
_ = ipt.NewChain("filter", "WEAVE-EXPOSE")
|
if err := ipt.ClearChain("filter", "WEAVE-EXPOSE"); err != nil {
|
||||||
if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-j", "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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward from weave to the rest of the world
|
return nil
|
||||||
if err = ipt.AppendUnique("filter", "FORWARD", "-i", config.WeaveBridgeName, "!", "-o", config.WeaveBridgeName, "-j", "ACCEPT"); err != nil {
|
}
|
||||||
return err
|
|
||||||
|
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
|
prev, curr := tracker.RemoveCommon(
|
||||||
if err = ipt.ClearChain("nat", "WEAVE"); err != nil {
|
address.NewCIDRs(tracker.Merge(prevRanges)),
|
||||||
return errors.Wrap(err, "clearing WEAVE chain")
|
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 {
|
func linkSetUpByName(linkName string) error {
|
||||||
@@ -487,3 +583,29 @@ func linkSetUpByName(linkName string) error {
|
|||||||
}
|
}
|
||||||
return netlink.LinkSetUp(link)
|
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
@@ -12,9 +12,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"golang.org/x/crypto/hkdf"
|
"golang.org/x/crypto/hkdf"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
package ipset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Name string
|
||||||
|
|
||||||
|
type Type string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ListSet = Type("list:set")
|
||||||
|
HashIP = Type("hash:ip")
|
||||||
|
HashNet = Type("hash:net")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Interface interface {
|
||||||
|
Create(ipsetName Name, ipsetType Type) error
|
||||||
|
AddEntry(user types.UID, ipsetName Name, entry string, comment string) error
|
||||||
|
DelEntry(user types.UID, ipsetName Name, entry string) error
|
||||||
|
Exist(user types.UID, ipsetName Name, entry string) bool
|
||||||
|
Flush(ipsetName Name) error
|
||||||
|
Destroy(ipsetName Name) error
|
||||||
|
|
||||||
|
List(prefix string) ([]Name, error)
|
||||||
|
|
||||||
|
FlushAll() error
|
||||||
|
DestroyAll() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type entryKey struct {
|
||||||
|
ipsetName Name
|
||||||
|
entry string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ipset struct {
|
||||||
|
*log.Logger
|
||||||
|
enableComments bool
|
||||||
|
maxListSize int
|
||||||
|
// List of users per ipset entry. User is either a namespace or a pod.
|
||||||
|
// There might be multiple users for the same ipset & entry pair because
|
||||||
|
// events from k8s API server might be out of order causing duplicate IPs:
|
||||||
|
// https://github.com/weaveworks/weave/issues/2792.
|
||||||
|
users map[entryKey]map[types.UID]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(logger *log.Logger, maxListSize int) Interface {
|
||||||
|
ips := &ipset{
|
||||||
|
Logger: logger,
|
||||||
|
enableComments: true,
|
||||||
|
maxListSize: maxListSize,
|
||||||
|
users: make(map[entryKey]map[types.UID]struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for comment support
|
||||||
|
|
||||||
|
// To prevent from a race when more than one process check for the support
|
||||||
|
// we append a random nonce to the test ipset name. The final name is
|
||||||
|
// shorter than 31 chars (max ipset name).
|
||||||
|
nonce := make([]byte, 4)
|
||||||
|
rand.Read(nonce)
|
||||||
|
testIpsetName := Name("weave-test-comment" + hex.EncodeToString(nonce))
|
||||||
|
|
||||||
|
// Clear it out if it already exists
|
||||||
|
_ = ips.Destroy(testIpsetName)
|
||||||
|
// Test for comment support
|
||||||
|
if err := ips.Create(testIpsetName, HashIP); err != nil {
|
||||||
|
ips.Logger.Printf("failed to create %s; disabling comment support", testIpsetName)
|
||||||
|
ips.enableComments = false
|
||||||
|
}
|
||||||
|
// If it was created, destroy it
|
||||||
|
_ = ips.Destroy(testIpsetName)
|
||||||
|
|
||||||
|
return ips
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) Create(ipsetName Name, ipsetType Type) error {
|
||||||
|
args := []string{"create", string(ipsetName), string(ipsetType)}
|
||||||
|
if ipsetType == ListSet && i.maxListSize > 0 {
|
||||||
|
args = append(args, "size", fmt.Sprintf("%d", i.maxListSize))
|
||||||
|
}
|
||||||
|
if i.enableComments {
|
||||||
|
args = append(args, "comment")
|
||||||
|
}
|
||||||
|
return doExec(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) AddEntry(user types.UID, ipsetName Name, entry string, comment string) error {
|
||||||
|
i.Logger.Printf("adding entry %s to %s of %s", entry, ipsetName, user)
|
||||||
|
|
||||||
|
if !i.addUser(user, ipsetName, entry) { // already in the set
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
i.Logger.Printf("added entry %s to %s of %s", entry, ipsetName, user)
|
||||||
|
|
||||||
|
args := []string{"add", string(ipsetName), entry}
|
||||||
|
if i.enableComments {
|
||||||
|
args = append(args, "comment", comment)
|
||||||
|
}
|
||||||
|
return doExec(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) DelEntry(user types.UID, ipsetName Name, entry string) error {
|
||||||
|
i.Logger.Printf("deleting entry %s from %s of %s", entry, ipsetName, user)
|
||||||
|
|
||||||
|
if !i.delUser(user, ipsetName, entry) { // still needed
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
i.Logger.Printf("deleted entry %s from %s of %s", entry, ipsetName, user)
|
||||||
|
|
||||||
|
return doExec("del", string(ipsetName), entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) Exist(user types.UID, ipsetName Name, entry string) bool {
|
||||||
|
return i.existUser(user, ipsetName, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) Flush(ipsetName Name) error {
|
||||||
|
i.removeSetFromUsers(ipsetName)
|
||||||
|
return doExec("flush", string(ipsetName))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) FlushAll() error {
|
||||||
|
i.users = make(map[entryKey]map[types.UID]struct{})
|
||||||
|
return doExec("flush")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) Destroy(ipsetName Name) error {
|
||||||
|
i.removeSetFromUsers(ipsetName)
|
||||||
|
return doExec("destroy", string(ipsetName))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) DestroyAll() error {
|
||||||
|
i.users = make(map[entryKey]map[types.UID]struct{})
|
||||||
|
return doExec("destroy")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch a list of all existing sets with a given prefix
|
||||||
|
func (i *ipset) List(prefix string) ([]Name, error) {
|
||||||
|
output, err := exec.Command("ipset", "list", "-name", "-output", "plain").Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected []Name
|
||||||
|
sets := strings.Split(string(output), "\n")
|
||||||
|
for _, v := range sets {
|
||||||
|
if strings.HasPrefix(v, prefix) {
|
||||||
|
selected = append(selected, Name(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if entry does not exist in ipset (entry has to be inserted into ipset).
|
||||||
|
func (i *ipset) addUser(user types.UID, ipsetName Name, entry string) bool {
|
||||||
|
k := entryKey{ipsetName, entry}
|
||||||
|
add := false
|
||||||
|
|
||||||
|
if i.users[k] == nil {
|
||||||
|
i.users[k] = make(map[types.UID]struct{})
|
||||||
|
}
|
||||||
|
if len(i.users[k]) == 0 {
|
||||||
|
add = true
|
||||||
|
}
|
||||||
|
i.users[k][user] = struct{}{}
|
||||||
|
|
||||||
|
return add
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if user is the last owner of entry (entry has to be removed from ipset).
|
||||||
|
func (i *ipset) delUser(user types.UID, ipsetName Name, entry string) bool {
|
||||||
|
k := entryKey{ipsetName, entry}
|
||||||
|
|
||||||
|
oneLeft := len(i.users[k]) == 1
|
||||||
|
delete(i.users[k], user)
|
||||||
|
|
||||||
|
if len(i.users[k]) == 0 {
|
||||||
|
delete(i.users, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oneLeft && (len(i.users[k]) == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) existUser(user types.UID, ipsetName Name, entry string) bool {
|
||||||
|
_, ok := i.users[entryKey{ipsetName, entry}][user]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipset) removeSetFromUsers(ipsetName Name) {
|
||||||
|
for k := range i.users {
|
||||||
|
if k.ipsetName == ipsetName {
|
||||||
|
delete(i.users, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doExec(args ...string) error {
|
||||||
|
if output, err := exec.Command("ipset", args...).CombinedOutput(); err != nil {
|
||||||
|
return errors.Wrapf(err, "ipset %v failed: %s", args, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+106
@@ -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
@@ -1,11 +1,9 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"github.com/vishvananda/netns"
|
"github.com/vishvananda/netns"
|
||||||
@@ -17,7 +15,7 @@ type Dev struct {
|
|||||||
CIDRs []*net.IPNet `json:"CIDRs,omitempty"`
|
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)
|
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Dev{}, err
|
return Dev{}, err
|
||||||
@@ -90,16 +88,30 @@ func GetNetDevsByVethPeerIds(processID int, peerIDs []int) ([]Dev, error) {
|
|||||||
return nil, nil
|
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
|
var netdevs []Dev
|
||||||
peersStr := make([]string, len(peerIDs))
|
err = WithNetNS(netnsContainer, func() error {
|
||||||
for i, id := range peerIDs {
|
links, err := netlink.LinkList()
|
||||||
peersStr[i] = strconv.Itoa(id)
|
if err != nil {
|
||||||
}
|
return err
|
||||||
nds, err := WithNetNSByPid(processID, "list-netdevs", peersStr...)
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("list-netdevs failed: %s", err)
|
for _, link := range links {
|
||||||
}
|
if _, found := indexes[link.Attrs().Index]; found {
|
||||||
err = json.Unmarshal(nds, &netdevs)
|
netdev, err := linkToNetDev(link)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
netdevs = append(netdevs, netdev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
return netdevs, err
|
return netdevs, err
|
||||||
}
|
}
|
||||||
@@ -112,5 +124,5 @@ func GetBridgeNetDev(bridgeName string) (Dev, error) {
|
|||||||
return Dev{}, err
|
return Dev{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return LinkToNetDev(link)
|
return linkToNetDev(link)
|
||||||
}
|
}
|
||||||
@@ -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
@@ -1,10 +1,10 @@
|
|||||||
|
// +build go1.10
|
||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
@@ -14,19 +14,7 @@ import (
|
|||||||
|
|
||||||
var ErrLinkNotFound = errors.New("Link not found")
|
var ErrLinkNotFound = errors.New("Link not found")
|
||||||
|
|
||||||
// NB: The following function is unsafe, because:
|
func WithNetNS(ns netns.NsHandle, work func() error) error {
|
||||||
// - It changes a network namespace (netns) of an OS thread which runs
|
|
||||||
// the function. During execution, the Go runtime might clone a new OS thread
|
|
||||||
// for scheduling other go-routines, thus they might end up running in
|
|
||||||
// a "wrong" netns.
|
|
||||||
// - runtime.LockOSThread does not guarantee that a spawned go-routine on
|
|
||||||
// the locked thread will be run by it. Thus, the work function is
|
|
||||||
// not allowed to spawn any go-routine which is dependent on the given netns.
|
|
||||||
|
|
||||||
// Please see https://github.com/weaveworks/weave/issues/2388#issuecomment-228365069
|
|
||||||
// for more details and make sure that you understand the implications before
|
|
||||||
// using the function!
|
|
||||||
func WithNetNSUnsafe(ns netns.NsHandle, work func() error) error {
|
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
@@ -45,8 +33,8 @@ func WithNetNSUnsafe(ns netns.NsHandle, work func() error) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithNetNSLinkUnsafe(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error {
|
func WithNetNSLink(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error {
|
||||||
return WithNetNSUnsafe(ns, func() error {
|
return WithNetNS(ns, func() error {
|
||||||
link, err := netlink.LinkByName(ifName)
|
link, err := netlink.LinkByName(ifName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == errors.New("Link not found").Error() {
|
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"
|
func WithNetNSByPath(path string, work func() error) error {
|
||||||
|
ns, err := netns.GetFromPath(path)
|
||||||
// A safe version of WithNetNS* which creates a process executing
|
if err != nil {
|
||||||
// "nsenter --net=<ns-path> weaveutil <cmd> [args]".
|
return err
|
||||||
func WithNetNS(nsPath string, cmd string, args ...string) ([]byte, error) {
|
|
||||||
var stdout, stderr bytes.Buffer
|
|
||||||
|
|
||||||
args = append([]string{"--net=" + nsPath, WeaveUtilCmd, cmd}, args...)
|
|
||||||
c := exec.Command("nsenter", args...)
|
|
||||||
c.Stdout = &stdout
|
|
||||||
c.Stderr = &stderr
|
|
||||||
if err := c.Run(); err != nil {
|
|
||||||
return nil, fmt.Errorf("%s: %s", string(stderr.Bytes()), err)
|
|
||||||
}
|
}
|
||||||
|
return WithNetNS(ns, work)
|
||||||
return stdout.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithNetNSByPid(pid int, cmd string, args ...string) ([]byte, error) {
|
|
||||||
return WithNetNS(NSPathByPid(pid), cmd, args...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NSPathByPid(pid int) string {
|
func NSPathByPid(pid int) string {
|
||||||
|
|||||||
+44
-20
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// create and attach a veth to the Weave bridge
|
// 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)
|
bridge, err := netlink.LinkByName(bridgeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(`bridge "%s" not present; did you launch weave?`, bridgeName)
|
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},
|
MTU: mtu},
|
||||||
PeerName: peerName,
|
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)
|
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 {
|
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
|
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
|
id = id[:maxIDLen] // trim passed ID if too long
|
||||||
}
|
}
|
||||||
name, peerName := vethPrefix+"pl"+id, vethPrefix+"pg"+id
|
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 {
|
if err := netlink.LinkSetNsFd(veth, int(ns)); err != nil {
|
||||||
return fmt.Errorf("failed to move veth to container netns: %s", err)
|
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 fmt.Errorf("error setting up interface: %s", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -134,19 +144,16 @@ func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMult
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args := []string{ifName, fmt.Sprintf("%t", withMulticastRoute)}
|
if err := WithNetNSLink(ns, ifName, func(veth netlink.Link) error {
|
||||||
for _, cidr := range cidrs {
|
return setupIfaceAddrs(veth, withMulticastRoute, cidrs)
|
||||||
args = append(args, cidr.String())
|
}); err != nil {
|
||||||
}
|
|
||||||
if _, err := WithNetNS(netNSPath, "setup-iface-addrs", args...); err != nil {
|
|
||||||
return fmt.Errorf("error setting up interface addresses: %s", err)
|
return fmt.Errorf("error setting up interface addresses: %s", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupIfaceAddrs is the implementation of the 'setup-iface-addrs' call above,
|
// setupIfaceAddrs expects to be called in the container's netns
|
||||||
// running in another process in the container's netns
|
func setupIfaceAddrs(veth netlink.Link, withMulticastRoute bool, cidrs []*net.IPNet) error {
|
||||||
func SetupIfaceAddrs(veth netlink.Link, withMulticastRoute bool, cidrs []*net.IPNet) error {
|
|
||||||
newAddresses, err := AddAddresses(veth, cidrs)
|
newAddresses, err := AddAddresses(veth, cidrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -198,9 +205,8 @@ func SetupIfaceAddrs(veth netlink.Link, withMulticastRoute bool, cidrs []*net.IP
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupIface is the implementation of the 'setup-iface' call above,
|
// setupIface expects to be called in the container's netns
|
||||||
// running in another process in the container's netns
|
func setupIface(ifaceName, newIfName string) error {
|
||||||
func SetupIface(ifaceName, newIfName string) error {
|
|
||||||
ipt, err := iptables.New()
|
ipt, err := iptables.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -214,14 +220,32 @@ func SetupIface(ifaceName, newIfName string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// This is only called by AttachContainer which is only called in host pid namespace
|
// 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 err
|
||||||
}
|
}
|
||||||
return ipt.Append("filter", "INPUT", "-i", newIfName, "-d", "224.0.0.0/4", "-j", "DROP")
|
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
|
// configureARP is a helper for the Docker plugin which doesn't set the addresses itself
|
||||||
// after calling the function as it changes netns via WithNetNSLinkUnsafe.
|
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 {
|
func DetachContainer(netNSPath, id, ifName string, cidrs []*net.IPNet) error {
|
||||||
ns, err := netns.GetFromPath(netNSPath)
|
ns, err := netns.GetFromPath(netNSPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -234,7 +258,7 @@ func DetachContainer(netNSPath, id, ifName string, cidrs []*net.IPNet) error {
|
|||||||
return err
|
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)
|
existingAddrs, err := netlink.AddrList(veth, netlink.FAMILY_V4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get IP address for %q: %v", veth.Attrs().Name, err)
|
return fmt.Errorf("failed to get IP address for %q: %v", veth.Attrs().Name, err)
|
||||||
|
|||||||
+124
-134
@@ -4,173 +4,163 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
extnapi "k8s.io/api/extensions/v1beta1"
|
|
||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkingv1 "k8s.io/api/networking/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"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) (
|
func (ns *ns) analysePolicy(policy *networkingv1.NetworkPolicy) (
|
||||||
rules map[string]*ruleSpec,
|
rules map[string]*ruleSpec,
|
||||||
nsSelectors, podSelectors map[string]*selectorSpec,
|
nsSelectors, podSelectors map[string]*selectorSpec,
|
||||||
|
ipBlocks map[string]*ipBlockSpec,
|
||||||
err error) {
|
err error) {
|
||||||
|
|
||||||
nsSelectors = make(map[string]*selectorSpec)
|
nsSelectors = make(map[string]*selectorSpec)
|
||||||
podSelectors = make(map[string]*selectorSpec)
|
podSelectors = make(map[string]*selectorSpec)
|
||||||
|
ipBlocks = make(map[string]*ipBlockSpec)
|
||||||
rules = make(map[string]*ruleSpec)
|
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
|
// 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 {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ingressRule := range policy.Spec.Ingress {
|
// To prevent targetSelector being overwritten by a subsequent selector with
|
||||||
// If Ports is empty or missing, this rule matches all ports
|
// the same key, addIfNotExist MUST be used when adding to podSelectors.
|
||||||
allPorts := ingressRule.Ports == nil || len(ingressRule.Ports) == 0
|
// Otherwise, policyTypes of the selector might be lost resulting in
|
||||||
// If From is empty or missing, this rule matches all sources
|
// an invalid content in any "default-allow" ipset.
|
||||||
allSources := ingressRule.From == nil || len(ingressRule.From) == 0
|
addIfNotExist(targetSelector, podSelectors)
|
||||||
|
|
||||||
if allSources {
|
// If ingress is empty then this NetworkPolicy does not allow any ingress traffic
|
||||||
if allPorts {
|
if policy.Spec.Ingress != nil && len(policy.Spec.Ingress) != 0 {
|
||||||
rule := newRuleSpec(nil, nil, dstSelector, nil)
|
for _, ingressRule := range policy.Spec.Ingress {
|
||||||
rules[rule.key] = rule
|
// If Ports is empty or missing, this rule matches all ports
|
||||||
} else {
|
allPorts := ingressRule.Ports == nil || len(ingressRule.Ports) == 0
|
||||||
withNormalisedProtoAndPort(ingressRule.Ports, func(proto, port string) {
|
// If From is empty or missing, this rule matches all sources
|
||||||
rule := newRuleSpec(&proto, nil, dstSelector, &port)
|
allSources := ingressRule.From == nil || len(ingressRule.From) == 0
|
||||||
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 allSources {
|
||||||
if allPorts {
|
if allPorts {
|
||||||
rule := newRuleSpec(nil, srcSelector, dstSelector, nil)
|
rule := newRuleSpec(policyTypeIngress, nil, nil, targetSelector, nil)
|
||||||
rules[rule.key] = rule
|
rules[rule.key] = rule
|
||||||
} else {
|
} else {
|
||||||
withNormalisedProtoAndPort(ingressRule.Ports, func(proto, port string) {
|
withNormalisedProtoAndPort(ingressRule.Ports, func(proto, port string) {
|
||||||
rule := newRuleSpec(&proto, srcSelector, dstSelector, &port)
|
rule := newRuleSpec(policyTypeIngress, &proto, nil, targetSelector, &port)
|
||||||
rules[rule.key] = rule
|
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)) {
|
func addIfNotExist(s *selectorSpec, ss map[string]*selectorSpec) {
|
||||||
for _, npp := range npps {
|
if _, ok := ss[s.key]; !ok {
|
||||||
f(proto(npp.Protocol), port(npp.Port))
|
ss[s.key] = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ const (
|
|||||||
DefaultChain = "WEAVE-NPC-DEFAULT"
|
DefaultChain = "WEAVE-NPC-DEFAULT"
|
||||||
IngressChain = "WEAVE-NPC-INGRESS"
|
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-"
|
IpsetNamePrefix = "weave-"
|
||||||
|
|
||||||
LocalIpset = IpsetNamePrefix + "local-pods"
|
LocalIpset = IpsetNamePrefix + "local-pods"
|
||||||
|
|||||||
+5
-8
@@ -9,7 +9,7 @@ import (
|
|||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkingv1 "k8s.io/api/networking/v1"
|
||||||
|
|
||||||
"github.com/weaveworks/weave/common"
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/net/ipset"
|
||||||
"github.com/weaveworks/weave/npc/iptables"
|
"github.com/weaveworks/weave/npc/iptables"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,19 +37,16 @@ type controller struct {
|
|||||||
|
|
||||||
nss map[string]*ns // ns name -> ns struct
|
nss map[string]*ns // ns name -> ns struct
|
||||||
nsSelectors *selectorSet // selector string -> nsSelector
|
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{
|
c := &controller{
|
||||||
nodeName: nodeName,
|
nodeName: nodeName,
|
||||||
legacy: legacy,
|
|
||||||
ipt: ipt,
|
ipt: ipt,
|
||||||
ips: ips,
|
ips: ips,
|
||||||
nss: make(map[string]*ns)}
|
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)
|
c.nsSelectors = newSelectorSet(ips, c.onNewNsSelector, doNothing, doNothing)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
@@ -59,7 +56,7 @@ func (npc *controller) onNewNsSelector(selector *selector) error {
|
|||||||
for _, ns := range npc.nss {
|
for _, ns := range npc.nss {
|
||||||
if ns.namespace != nil {
|
if ns.namespace != nil {
|
||||||
if selector.matches(ns.namespace.ObjectMeta.Labels) {
|
if selector.matches(ns.namespace.ObjectMeta.Labels) {
|
||||||
if err := selector.addEntry(string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
|
if err := selector.addEntry(ns.namespace.ObjectMeta.UID, string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +68,7 @@ func (npc *controller) onNewNsSelector(selector *selector) error {
|
|||||||
func (npc *controller) withNS(name string, f func(ns *ns) error) error {
|
func (npc *controller) withNS(name string, f func(ns *ns) error) error {
|
||||||
ns, found := npc.nss[name]
|
ns, found := npc.nss[name]
|
||||||
if !found {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+371
-87
@@ -1,22 +1,25 @@
|
|||||||
package npc
|
package npc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/net/ipset"
|
||||||
coreapi "k8s.io/api/core/v1"
|
coreapi "k8s.io/api/core/v1"
|
||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkingv1 "k8s.io/api/networking/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockSet struct {
|
type mockSet struct {
|
||||||
name ipset.Name
|
name ipset.Name
|
||||||
setType ipset.Type
|
setType ipset.Type
|
||||||
subSets map[string]bool
|
subSets map[string]map[types.UID]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockIPSet struct {
|
type mockIPSet struct {
|
||||||
@@ -24,70 +27,57 @@ type mockIPSet struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newMockIPSet() mockIPSet {
|
func newMockIPSet() mockIPSet {
|
||||||
i := mockIPSet{
|
return mockIPSet{sets: make(map[string]mockSet)}
|
||||||
sets: make(map[string]mockSet),
|
|
||||||
}
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *mockIPSet) Create(ipsetName ipset.Name, ipsetType ipset.Type) error {
|
func (i *mockIPSet) Create(ipsetName ipset.Name, ipsetType ipset.Type) error {
|
||||||
if _, ok := i.sets[string(ipsetName)]; ok {
|
if _, ok := i.sets[string(ipsetName)]; ok {
|
||||||
return errors.Errorf("ipset %s already exists", ipsetName)
|
return errors.Errorf("ipset %s already exists", ipsetName)
|
||||||
}
|
}
|
||||||
i.sets[string(ipsetName)] = mockSet{name: ipsetName, setType: ipsetType, subSets: make(map[string]bool)}
|
i.sets[string(ipsetName)] = mockSet{name: ipsetName, setType: ipsetType, subSets: make(map[string]map[types.UID]bool)}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *mockIPSet) AddEntry(ipsetName ipset.Name, entry string, comment string) error {
|
func (i *mockIPSet) AddEntry(user types.UID, ipsetName ipset.Name, entry string, comment string) error {
|
||||||
return i.addEntry(ipsetName, entry, comment, true)
|
log.Printf("adding entry %s to %s for %s", entry, ipsetName, user)
|
||||||
}
|
|
||||||
|
|
||||||
func (i *mockIPSet) AddEntryIfNotExist(ipsetName ipset.Name, entry string, comment string) error {
|
|
||||||
return i.addEntry(ipsetName, entry, comment, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *mockIPSet) addEntry(ipsetName ipset.Name, entry string, comment string, checkIfExists bool) error {
|
|
||||||
log.Printf("adding entry %s to %s", entry, ipsetName)
|
|
||||||
if _, ok := i.sets[string(ipsetName)]; !ok {
|
if _, ok := i.sets[string(ipsetName)]; !ok {
|
||||||
return errors.Errorf("ipset %s does not exist", entry)
|
return errors.Errorf("%s does not exist", entry)
|
||||||
}
|
}
|
||||||
if checkIfExists {
|
if i.sets[string(ipsetName)].subSets[entry] == nil {
|
||||||
if _, ok := i.sets[string(ipsetName)].subSets[entry]; ok {
|
i.sets[string(ipsetName)].subSets[entry] = make(map[types.UID]bool)
|
||||||
return errors.Errorf("ipset %s is already a member of %s", entry, ipsetName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
i.sets[string(ipsetName)].subSets[entry] = true
|
if _, ok := i.sets[string(ipsetName)].subSets[entry][user]; ok {
|
||||||
|
return errors.Errorf("user %s already owns entry %s", user, entry)
|
||||||
|
}
|
||||||
|
i.sets[string(ipsetName)].subSets[entry][user] = true
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *mockIPSet) DelEntry(ipsetName ipset.Name, entry string) error {
|
func (i *mockIPSet) DelEntry(user types.UID, ipsetName ipset.Name, entry string) error {
|
||||||
return i.delEntry(ipsetName, entry, true)
|
log.Printf("deleting entry %s from %s for %s", entry, ipsetName, user)
|
||||||
}
|
|
||||||
|
|
||||||
func (i *mockIPSet) DelEntryIfExists(ipsetName ipset.Name, entry string) error {
|
|
||||||
return i.delEntry(ipsetName, entry, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *mockIPSet) delEntry(ipsetName ipset.Name, entry string, checkIfExists bool) error {
|
|
||||||
log.Printf("deleting entry %s from %s", entry, ipsetName)
|
|
||||||
if _, ok := i.sets[string(ipsetName)]; !ok {
|
if _, ok := i.sets[string(ipsetName)]; !ok {
|
||||||
return errors.Errorf("ipset %s does not exist", ipsetName)
|
return errors.Errorf("ipset %s does not exist", ipsetName)
|
||||||
}
|
}
|
||||||
if checkIfExists {
|
if _, ok := i.sets[string(ipsetName)].subSets[entry][user]; !ok {
|
||||||
if _, ok := i.sets[string(ipsetName)].subSets[entry]; !ok {
|
return errors.Errorf("user %s does not own entry %s", user, entry)
|
||||||
return errors.Errorf("ipset %s is not a member of %s", entry, ipsetName)
|
}
|
||||||
}
|
delete(i.sets[string(ipsetName)].subSets[entry], user)
|
||||||
|
|
||||||
|
if len(i.sets[string(ipsetName)].subSets[entry]) == 0 {
|
||||||
|
delete(i.sets[string(ipsetName)].subSets, entry)
|
||||||
}
|
}
|
||||||
delete(i.sets[string(ipsetName)].subSets, entry)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *mockIPSet) Exist(ipsetName ipset.Name, entry string) bool {
|
func (i *mockIPSet) Exist(user types.UID, ipsetName ipset.Name, entry string) bool {
|
||||||
_, found := i.sets[string(ipsetName)].subSets[entry]
|
_, ok := i.sets[string(ipsetName)].subSets[entry][user]
|
||||||
return found
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *mockIPSet) entryExists(ipsetName ipset.Name, entry string) bool {
|
||||||
|
return len(i.sets[string(ipsetName)].subSets[entry]) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *mockIPSet) Flush(ipsetName ipset.Name) error {
|
func (i *mockIPSet) Flush(ipsetName ipset.Name) error {
|
||||||
@@ -115,18 +105,46 @@ func (i *mockIPSet) List(prefix string) ([]ipset.Name, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type mockIPTables struct {
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ipt *mockIPTables) Delete(table, chain string, rulespec ...string) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ipt *mockIPTables) Insert(table, chain string, pos int, rulespec ...string) error {
|
func (ipt *mockIPTables) Insert(table, chain string, pos int, rulespec ...string) error {
|
||||||
return nil
|
return errors.New("Not Implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
|
func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
|
||||||
@@ -156,6 +174,7 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
|
|||||||
Namespace: "destination",
|
Namespace: "destination",
|
||||||
},
|
},
|
||||||
Spec: networkingv1.NetworkPolicySpec{
|
Spec: networkingv1.NetworkPolicySpec{
|
||||||
|
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
|
||||||
Ingress: []networkingv1.NetworkPolicyIngressRule{
|
Ingress: []networkingv1.NetworkPolicyIngressRule{
|
||||||
{
|
{
|
||||||
From: []networkingv1.NetworkPolicyPeer{
|
From: []networkingv1.NetworkPolicyPeer{
|
||||||
@@ -179,7 +198,7 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
|
|||||||
|
|
||||||
// Namespaces first
|
// Namespaces first
|
||||||
m := newMockIPSet()
|
m := newMockIPSet()
|
||||||
controller := New("foo", false, &mockIPTables{}, &m)
|
controller := New("foo", newMockIPTables(), &m)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
selectorIPSetName = "weave-I239Zp%sCvoVt*D6u=A!2]YEk"
|
selectorIPSetName = "weave-I239Zp%sCvoVt*D6u=A!2]YEk"
|
||||||
@@ -191,32 +210,32 @@ func TestRegressionPolicyNamespaceOrdering3059(t *testing.T) {
|
|||||||
|
|
||||||
controller.AddNetworkPolicy(networkPolicy)
|
controller.AddNetworkPolicy(networkPolicy)
|
||||||
|
|
||||||
require.Equal(t, true, m.sets[selectorIPSetName].subSets[sourceIPSetName])
|
require.Equal(t, true, len(m.sets[selectorIPSetName].subSets[sourceIPSetName]) > 0)
|
||||||
|
|
||||||
// NetworkPolicy first
|
// NetworkPolicy first
|
||||||
m = newMockIPSet()
|
m = newMockIPSet()
|
||||||
controller = New("foo", false, &mockIPTables{}, &m)
|
controller = New("foo", newMockIPTables(), &m)
|
||||||
|
|
||||||
controller.AddNetworkPolicy(networkPolicy)
|
controller.AddNetworkPolicy(networkPolicy)
|
||||||
|
|
||||||
controller.AddNamespace(sourceNamespace)
|
controller.AddNamespace(sourceNamespace)
|
||||||
controller.AddNamespace(destinationNamespace)
|
controller.AddNamespace(destinationNamespace)
|
||||||
|
|
||||||
require.Equal(t, true, m.sets[selectorIPSetName].subSets[sourceIPSetName])
|
require.Equal(t, true, len(m.sets[selectorIPSetName].subSets[sourceIPSetName]) > 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests default-allow ipset behavior when running in non-legacy mode.
|
// Tests default-allow ipset behavior
|
||||||
func TestDefaultAllow(t *testing.T) {
|
func TestDefaultAllow(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
defaultAllowIPSetName = "weave-E.1.0W^NGSp]0_t5WwH/]gX@L"
|
ingressDefaultAllowIPSetName = "weave-;rGqyMIl1HN^cfDki~Z$3]6!N"
|
||||||
fooPodIP = "10.32.0.10"
|
egressDefaultAllowIPSetName = "weave-s_+ChJId4Uy_$}G;WdH|~TK)I"
|
||||||
barPodIP = "10.32.0.11"
|
fooPodIP = "10.32.0.10"
|
||||||
barPodNewIP = "10.32.0.12"
|
barPodIP = "10.32.0.11"
|
||||||
|
barPodNewIP = "10.32.0.12"
|
||||||
)
|
)
|
||||||
|
|
||||||
m := newMockIPSet()
|
m := newMockIPSet()
|
||||||
controller := New("bar", false, &mockIPTables{}, &m)
|
controller := New("bar", newMockIPTables(), &m)
|
||||||
|
|
||||||
defaultNamespace := &coreapi.Namespace{
|
defaultNamespace := &coreapi.Namespace{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@@ -226,7 +245,8 @@ func TestDefaultAllow(t *testing.T) {
|
|||||||
controller.AddNamespace(defaultNamespace)
|
controller.AddNamespace(defaultNamespace)
|
||||||
|
|
||||||
// Should create an ipset for default-allow
|
// 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{
|
podFoo := &coreapi.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@@ -238,7 +258,8 @@ func TestDefaultAllow(t *testing.T) {
|
|||||||
controller.AddPod(podFoo)
|
controller.AddPod(podFoo)
|
||||||
|
|
||||||
// Should add the foo pod to default-allow
|
// Should add the foo pod to default-allow
|
||||||
require.True(t, m.Exist(defaultAllowIPSetName, fooPodIP))
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
require.True(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
|
||||||
podBar := &coreapi.Pod{
|
podBar := &coreapi.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@@ -249,10 +270,12 @@ func TestDefaultAllow(t *testing.T) {
|
|||||||
Status: coreapi.PodStatus{PodIP: barPodIP}}
|
Status: coreapi.PodStatus{PodIP: barPodIP}}
|
||||||
podBarNoIP := &coreapi.Pod{ObjectMeta: podBar.ObjectMeta}
|
podBarNoIP := &coreapi.Pod{ObjectMeta: podBar.ObjectMeta}
|
||||||
controller.AddPod(podBarNoIP)
|
controller.AddPod(podBarNoIP)
|
||||||
|
|
||||||
controller.UpdatePod(podBarNoIP, podBar)
|
controller.UpdatePod(podBarNoIP, podBar)
|
||||||
|
|
||||||
// Should add the bar pod to default-allow
|
// Should add the bar pod to default-allow
|
||||||
require.True(t, m.Exist(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
|
// Allow access from the bar pod to the foo pod
|
||||||
netpol := &networkingv1.NetworkPolicy{
|
netpol := &networkingv1.NetworkPolicy{
|
||||||
@@ -261,6 +284,113 @@ func TestDefaultAllow(t *testing.T) {
|
|||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
},
|
},
|
||||||
Spec: networkingv1.NetworkPolicySpec{
|
Spec: networkingv1.NetworkPolicySpec{
|
||||||
|
PolicyTypes: []networkingv1.PolicyType{
|
||||||
|
networkingv1.PolicyTypeIngress,
|
||||||
|
networkingv1.PolicyTypeEgress,
|
||||||
|
},
|
||||||
|
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "foo"}},
|
||||||
|
Ingress: []networkingv1.NetworkPolicyIngressRule{{
|
||||||
|
From: []networkingv1.NetworkPolicyPeer{{
|
||||||
|
PodSelector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{"run": "bar"},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
Egress: []networkingv1.NetworkPolicyEgressRule{{
|
||||||
|
To: []networkingv1.NetworkPolicyPeer{{
|
||||||
|
IPBlock: &networkingv1.IPBlock{CIDR: "192.168.48.0/24"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
controller.AddNetworkPolicy(netpol)
|
||||||
|
|
||||||
|
// Should remove the foo pod from default-allow as the netpol selects it
|
||||||
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
require.False(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, barPodIP))
|
||||||
|
require.True(t, m.entryExists(egressDefaultAllowIPSetName, barPodIP))
|
||||||
|
|
||||||
|
podBarWithNewIP := *podBar
|
||||||
|
podBarWithNewIP.Status.PodIP = barPodNewIP
|
||||||
|
controller.UpdatePod(podBar, &podBarWithNewIP)
|
||||||
|
|
||||||
|
// Should update IP addr of the bar pod in default-allow
|
||||||
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, barPodIP))
|
||||||
|
require.False(t, m.entryExists(egressDefaultAllowIPSetName, barPodIP))
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, barPodNewIP))
|
||||||
|
require.True(t, m.entryExists(egressDefaultAllowIPSetName, barPodNewIP))
|
||||||
|
|
||||||
|
controller.UpdatePod(&podBarWithNewIP, podBarNoIP)
|
||||||
|
// Should remove the bar pod from default-allow as it does not have any IP addr
|
||||||
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, barPodNewIP))
|
||||||
|
require.False(t, m.entryExists(egressDefaultAllowIPSetName, barPodNewIP))
|
||||||
|
|
||||||
|
podFooWithNewLabel := *podFoo
|
||||||
|
podFooWithNewLabel.ObjectMeta.Labels = map[string]string{"run": "new-foo"}
|
||||||
|
controller.UpdatePod(podFoo, &podFooWithNewLabel)
|
||||||
|
|
||||||
|
// Should bring back the foo pod to default-allow as it does not match dst of any netpol
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
require.True(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
|
||||||
|
controller.UpdatePod(&podFooWithNewLabel, podFoo)
|
||||||
|
// Should remove from default-allow as it matches the netpol after the update
|
||||||
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
require.False(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
|
||||||
|
controller.DeleteNetworkPolicy(netpol)
|
||||||
|
// Should bring back the foo pod to default-allow as no netpol selects it
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
require.True(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
|
||||||
|
controller.DeletePod(podFoo)
|
||||||
|
// Should remove foo pod from default-allow
|
||||||
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
require.False(t, m.entryExists(egressDefaultAllowIPSetName, fooPodIP))
|
||||||
|
|
||||||
|
controller.DeleteNamespace(defaultNamespace)
|
||||||
|
// Should remove default ipset
|
||||||
|
require.NotContains(t, m.sets, ingressDefaultAllowIPSetName)
|
||||||
|
require.NotContains(t, m.sets, egressDefaultAllowIPSetName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOutOfOrderPodEvents(t *testing.T) {
|
||||||
|
const (
|
||||||
|
ingressDefaultAllowIPSetName = "weave-;rGqyMIl1HN^cfDki~Z$3]6!N"
|
||||||
|
runBarIPSetName = "weave-bZ~x=yBgzH)Ht()K*Uv3z{M]Y"
|
||||||
|
podIP = "10.32.0.10"
|
||||||
|
)
|
||||||
|
|
||||||
|
m := newMockIPSet()
|
||||||
|
controller := New("qux", newMockIPTables(), &m)
|
||||||
|
|
||||||
|
defaultNamespace := &coreapi.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
controller.AddNamespace(defaultNamespace)
|
||||||
|
|
||||||
|
podFoo := &coreapi.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
UID: "foo",
|
||||||
|
Namespace: "default",
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{"run": "foo"}},
|
||||||
|
Status: coreapi.PodStatus{PodIP: podIP}}
|
||||||
|
controller.AddPod(podFoo)
|
||||||
|
|
||||||
|
// Should be in default-allow as no netpol selects podFoo
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
|
|
||||||
|
netpol := &networkingv1.NetworkPolicy{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "allow-from-bar-to-foo",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: networkingv1.NetworkPolicySpec{
|
||||||
|
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
|
||||||
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "foo"}},
|
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "foo"}},
|
||||||
Ingress: []networkingv1.NetworkPolicyIngressRule{{
|
Ingress: []networkingv1.NetworkPolicyIngressRule{{
|
||||||
From: []networkingv1.NetworkPolicyPeer{{
|
From: []networkingv1.NetworkPolicyPeer{{
|
||||||
@@ -273,38 +403,192 @@ func TestDefaultAllow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
controller.AddNetworkPolicy(netpol)
|
controller.AddNetworkPolicy(netpol)
|
||||||
|
|
||||||
// Should remove the foo pod from default-allow as the netpol selects it
|
// Shouldn't be in default-allow as netpol above selects podFoo
|
||||||
require.False(t, m.Exist(defaultAllowIPSetName, fooPodIP))
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
require.True(t, m.Exist(defaultAllowIPSetName, barPodIP))
|
|
||||||
|
|
||||||
podBarWithNewIP := *podBar
|
podBar := &coreapi.Pod{
|
||||||
podBarWithNewIP.Status.PodIP = barPodNewIP
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
controller.UpdatePod(podBar, &podBarWithNewIP)
|
UID: "bar",
|
||||||
|
Namespace: "default",
|
||||||
|
Name: "bar",
|
||||||
|
Labels: map[string]string{"run": "bar"}},
|
||||||
|
Status: coreapi.PodStatus{PodIP: podIP}}
|
||||||
|
controller.AddPod(podBar)
|
||||||
|
|
||||||
// Should update IP addr of the bar pod in default-allow
|
// Should be in default-allow as no netpol selects podBar
|
||||||
require.False(t, m.Exist(defaultAllowIPSetName, barPodIP))
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
require.True(t, m.Exist(defaultAllowIPSetName, barPodNewIP))
|
require.True(t, m.Exist(podBar.ObjectMeta.UID, ingressDefaultAllowIPSetName, podIP))
|
||||||
|
// Should be in run=bar ipset
|
||||||
controller.UpdatePod(&podBarWithNewIP, podBarNoIP)
|
require.True(t, m.entryExists(runBarIPSetName, podIP))
|
||||||
// Should remove the bar pod from default-allow as it does not have any IP addr
|
|
||||||
require.False(t, m.Exist(defaultAllowIPSetName, 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.Exist(defaultAllowIPSetName, fooPodIP))
|
|
||||||
|
|
||||||
controller.UpdatePod(&podFooWithNewLabel, podFoo)
|
|
||||||
// Should remove from default-allow as it matches the netpol after the update
|
|
||||||
require.False(t, m.Exist(defaultAllowIPSetName, fooPodIP))
|
|
||||||
|
|
||||||
controller.DeleteNetworkPolicy(netpol)
|
|
||||||
// Should bring back the foo pod to default-allow as no netpol selects it
|
|
||||||
require.True(t, m.Exist(defaultAllowIPSetName, fooPodIP))
|
|
||||||
|
|
||||||
controller.DeletePod(podFoo)
|
controller.DeletePod(podFoo)
|
||||||
// Should remove foo pod from default-allow
|
// Multiple duplicate events should not affect npc state
|
||||||
require.False(t, m.Exist(defaultAllowIPSetName, fooPodIP))
|
controller.DeletePod(podFoo)
|
||||||
|
controller.DeletePod(podFoo)
|
||||||
|
|
||||||
|
// Should be in default-allow as no netpol selects podBar and podFoo removal
|
||||||
|
// should not affect podBar in default-allow
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
|
|
||||||
|
controller.DeletePod(podBar)
|
||||||
|
|
||||||
|
// Should remove from default-allow and run=bar ipsets
|
||||||
|
require.Equal(t, 0, len(m.sets[ingressDefaultAllowIPSetName].subSets))
|
||||||
|
require.False(t, m.entryExists(runBarIPSetName, podIP))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case for https://github.com/weaveworks/weave/issues/3222
|
||||||
|
func TestNewTargetSelector(t *testing.T) {
|
||||||
|
const (
|
||||||
|
ingressDefaultAllowIPSetName = "weave-;rGqyMIl1HN^cfDki~Z$3]6!N"
|
||||||
|
podIP = "10.32.0.10"
|
||||||
|
)
|
||||||
|
|
||||||
|
m := newMockIPSet()
|
||||||
|
controller := New("baz", newMockIPTables(), &m)
|
||||||
|
|
||||||
|
defaultNamespace := &coreapi.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
controller.AddNamespace(defaultNamespace)
|
||||||
|
|
||||||
|
podFoo := &coreapi.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
UID: "foo",
|
||||||
|
Namespace: "default",
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{"run": "foo"}},
|
||||||
|
Status: coreapi.PodStatus{PodIP: podIP}}
|
||||||
|
controller.AddPod(podFoo)
|
||||||
|
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
|
|
||||||
|
netpolBar := &networkingv1.NetworkPolicy{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
UID: "netpol-bar",
|
||||||
|
Name: "allow-from-default-1",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: networkingv1.NetworkPolicySpec{
|
||||||
|
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
|
||||||
|
PodSelector: metav1.LabelSelector{},
|
||||||
|
Ingress: []networkingv1.NetworkPolicyIngressRule{{
|
||||||
|
From: []networkingv1.NetworkPolicyPeer{{
|
||||||
|
PodSelector: &metav1.LabelSelector{},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
controller.AddNetworkPolicy(netpolBar)
|
||||||
|
|
||||||
|
// netpolBar target selector selects podFoo
|
||||||
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
|
|
||||||
|
netpolFoo := &networkingv1.NetworkPolicy{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
UID: "netpol-foo",
|
||||||
|
Name: "allow-from-default-2",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: networkingv1.NetworkPolicySpec{
|
||||||
|
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
|
||||||
|
PodSelector: metav1.LabelSelector{},
|
||||||
|
Ingress: []networkingv1.NetworkPolicyIngressRule{{
|
||||||
|
From: []networkingv1.NetworkPolicyPeer{{
|
||||||
|
PodSelector: &metav1.LabelSelector{},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
controller.AddNetworkPolicy(netpolFoo)
|
||||||
|
|
||||||
|
controller.DeleteNetworkPolicy(netpolBar)
|
||||||
|
// netpolFoo target-selects podFoo
|
||||||
|
require.False(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
|
controller.DeleteNetworkPolicy(netpolFoo)
|
||||||
|
// No netpol target-selects podFoo
|
||||||
|
require.True(t, m.entryExists(ingressDefaultAllowIPSetName, podIP))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEgressPolicyWithIPBlock(t *testing.T) {
|
||||||
|
const (
|
||||||
|
fooPodIP = "10.32.0.10"
|
||||||
|
exceptIPSetName = "weave-j:W$5om!$8JS})buYAD7q^#sX"
|
||||||
|
exceptIPSetNameInNonDefault = "weave-|*P{aL2C@#N/1IZ!IvQItv_pt"
|
||||||
|
)
|
||||||
|
|
||||||
|
m := newMockIPSet()
|
||||||
|
ipt := newMockIPTables()
|
||||||
|
controller := New("foo", ipt, &m)
|
||||||
|
|
||||||
|
netpolFoo := &networkingv1.NetworkPolicy{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
UID: "netpol-foo",
|
||||||
|
Name: "allow-from-bar-to-foo",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: networkingv1.NetworkPolicySpec{
|
||||||
|
PolicyTypes: []networkingv1.PolicyType{
|
||||||
|
networkingv1.PolicyTypeEgress,
|
||||||
|
},
|
||||||
|
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "bar"}},
|
||||||
|
Egress: []networkingv1.NetworkPolicyEgressRule{{
|
||||||
|
To: []networkingv1.NetworkPolicyPeer{{
|
||||||
|
IPBlock: &networkingv1.IPBlock{
|
||||||
|
CIDR: "192.168.48.0/24",
|
||||||
|
Except: []string{
|
||||||
|
"192.168.48.1/32",
|
||||||
|
"192.168.48.2/32",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := controller.AddNetworkPolicy(netpolFoo)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 2, len(m.sets[exceptIPSetName].subSets))
|
||||||
|
require.True(t, m.entryExists(exceptIPSetName, "192.168.48.1/32"))
|
||||||
|
require.True(t, m.entryExists(exceptIPSetName, "192.168.48.2/32"))
|
||||||
|
|
||||||
|
// Each egress rule is represented as two iptables rules (-J MARK and -J RETURN).
|
||||||
|
require.Equal(t, 2, len(ipt.rules[EgressCustomChain]))
|
||||||
|
for rule := range ipt.rules[EgressCustomChain] {
|
||||||
|
require.Contains(t, rule, "-d 192.168.48.0/24 -m set ! --match-set "+exceptIPSetName+" dst")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we create a new ipset for the ipBlock bellow. An ipset with the
|
||||||
|
// same content already exists (created by netpolFoo), but we need to create
|
||||||
|
// a new one, as netpolBar is in a different namespace and weave-npc does
|
||||||
|
// object refcounting only within namespace boundaries.
|
||||||
|
netpolBar := &networkingv1.NetworkPolicy{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
UID: "netpol-foo-bar",
|
||||||
|
Name: "allow-from-bar-to-foo-in-non-default",
|
||||||
|
Namespace: "non-default",
|
||||||
|
},
|
||||||
|
Spec: networkingv1.NetworkPolicySpec{
|
||||||
|
PolicyTypes: []networkingv1.PolicyType{
|
||||||
|
networkingv1.PolicyTypeEgress,
|
||||||
|
},
|
||||||
|
PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"run": "bar"}},
|
||||||
|
Egress: []networkingv1.NetworkPolicyEgressRule{{
|
||||||
|
To: []networkingv1.NetworkPolicyPeer{{
|
||||||
|
IPBlock: &networkingv1.IPBlock{
|
||||||
|
CIDR: "192.168.48.0/24",
|
||||||
|
Except: []string{
|
||||||
|
"192.168.48.1/32",
|
||||||
|
"192.168.48.2/32",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = controller.AddNetworkPolicy(netpolBar)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(m.sets[exceptIPSetNameInNonDefault].subSets))
|
||||||
}
|
}
|
||||||
+116
@@ -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
|
||||||
|
}
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
package ipset
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Name string
|
|
||||||
|
|
||||||
type Type string
|
|
||||||
|
|
||||||
const (
|
|
||||||
ListSet = Type("list:set")
|
|
||||||
HashIP = Type("hash:ip")
|
|
||||||
)
|
|
||||||
|
|
||||||
type Interface interface {
|
|
||||||
Create(ipsetName Name, ipsetType Type) error
|
|
||||||
AddEntry(ipsetName Name, entry string, comment string) error
|
|
||||||
AddEntryIfNotExist(ipsetName Name, entry string, comment string) error
|
|
||||||
DelEntry(ipsetName Name, entry string) error
|
|
||||||
DelEntryIfExists(ipsetName Name, entry string) error
|
|
||||||
Exist(ipsetName Name, entry string) bool
|
|
||||||
Flush(ipsetName Name) error
|
|
||||||
Destroy(ipsetName Name) error
|
|
||||||
|
|
||||||
List(prefix string) ([]Name, error)
|
|
||||||
|
|
||||||
FlushAll() error
|
|
||||||
DestroyAll() error
|
|
||||||
}
|
|
||||||
|
|
||||||
type ipset struct {
|
|
||||||
refCount
|
|
||||||
*log.Logger
|
|
||||||
enableComments bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(logger *log.Logger) Interface {
|
|
||||||
ips := &ipset{refCount: newRefCount(), Logger: logger, enableComments: true}
|
|
||||||
|
|
||||||
// Check for comment support
|
|
||||||
testIpsetName := Name("weave-test-comment")
|
|
||||||
// Clear it out if it already exists
|
|
||||||
_ = ips.Destroy(testIpsetName)
|
|
||||||
// Test for comment support
|
|
||||||
if err := ips.Create(testIpsetName, HashIP); err != nil {
|
|
||||||
ips.Logger.Printf("failed to create %s; disabling comment support", testIpsetName)
|
|
||||||
ips.enableComments = false
|
|
||||||
}
|
|
||||||
// If it was created, destroy it
|
|
||||||
_ = ips.Destroy(testIpsetName)
|
|
||||||
|
|
||||||
return ips
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) Create(ipsetName Name, ipsetType Type) error {
|
|
||||||
args := []string{"create", string(ipsetName), string(ipsetType)}
|
|
||||||
if i.enableComments {
|
|
||||||
args = append(args, "comment")
|
|
||||||
}
|
|
||||||
return doExec(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) AddEntry(ipsetName Name, entry string, comment string) error {
|
|
||||||
i.Logger.Printf("adding entry %s to %s", entry, ipsetName)
|
|
||||||
if i.inc(ipsetName, entry) > 1 { // already in the set
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
args := []string{"add", string(ipsetName), entry}
|
|
||||||
if i.enableComments {
|
|
||||||
args = append(args, "comment", comment)
|
|
||||||
}
|
|
||||||
return doExec(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddEntryIfNotExist does the same as AddEntry but bypasses the ref counting.
|
|
||||||
// Should be used only with "default-allow" ipsets.
|
|
||||||
func (i *ipset) AddEntryIfNotExist(ipsetName Name, entry string, comment string) error {
|
|
||||||
if i.count(ipsetName, entry) == 1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return i.AddEntry(ipsetName, entry, comment)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) DelEntry(ipsetName Name, entry string) error {
|
|
||||||
i.Logger.Printf("deleting entry %s from %s", entry, ipsetName)
|
|
||||||
if i.dec(ipsetName, entry) > 0 { // still needed
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return doExec("del", string(ipsetName), entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelEntryIfExists does the same as DelEntry but bypasses the ref counting.
|
|
||||||
// Should be used only with "default-allow" ipsets.
|
|
||||||
func (i *ipset) DelEntryIfExists(ipsetName Name, entry string) error {
|
|
||||||
if i.count(ipsetName, entry) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return i.DelEntry(ipsetName, entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) Exist(ipsetName Name, entry string) bool {
|
|
||||||
return i.count(ipsetName, entry) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) Flush(ipsetName Name) error {
|
|
||||||
i.removeSet(ipsetName)
|
|
||||||
return doExec("flush", string(ipsetName))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) FlushAll() error {
|
|
||||||
i.refCount = newRefCount()
|
|
||||||
return doExec("flush")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) Destroy(ipsetName Name) error {
|
|
||||||
i.removeSet(ipsetName)
|
|
||||||
return doExec("destroy", string(ipsetName))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipset) DestroyAll() error {
|
|
||||||
i.refCount = newRefCount()
|
|
||||||
return doExec("destroy")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch a list of all existing sets with a given prefix
|
|
||||||
func (i *ipset) List(prefix string) ([]Name, error) {
|
|
||||||
output, err := exec.Command("ipset", "list", "-name", "-output", "plain").Output()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var selected []Name
|
|
||||||
sets := strings.Split(string(output), "\n")
|
|
||||||
for _, v := range sets {
|
|
||||||
if strings.HasPrefix(v, prefix) {
|
|
||||||
selected = append(selected, Name(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return selected, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func doExec(args ...string) error {
|
|
||||||
if output, err := exec.Command("ipset", args...).CombinedOutput(); err != nil {
|
|
||||||
return errors.Wrapf(err, "ipset %v failed: %s", args, output)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reference-counting
|
|
||||||
type key struct {
|
|
||||||
ipsetName Name
|
|
||||||
entry string
|
|
||||||
}
|
|
||||||
|
|
||||||
// note no locking is required as all operations are serialised in the controller
|
|
||||||
type refCount struct {
|
|
||||||
ref map[key]int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRefCount() refCount {
|
|
||||||
return refCount{ref: make(map[key]int)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *refCount) inc(ipsetName Name, entry string) int {
|
|
||||||
k := key{ipsetName, entry}
|
|
||||||
rc.ref[k]++
|
|
||||||
return rc.ref[k]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *refCount) dec(ipsetName Name, entry string) int {
|
|
||||||
k := key{ipsetName, entry}
|
|
||||||
rc.ref[k]--
|
|
||||||
return rc.ref[k]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *refCount) count(ipsetName Name, entry string) int {
|
|
||||||
return rc.ref[key{ipsetName, entry}]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *refCount) removeSet(ipsetName Name) {
|
|
||||||
for k := range rc.ref {
|
|
||||||
if k.ipsetName == ipsetName {
|
|
||||||
delete(rc.ref, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+49
@@ -4,7 +4,56 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Return JSON suitable for logging an API object.
|
||||||
func js(v interface{}) string {
|
func js(v interface{}) string {
|
||||||
|
// Get the raw JSON
|
||||||
a, _ := json.Marshal(v)
|
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)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+196
-164
@@ -1,7 +1,6 @@
|
|||||||
package npc
|
package npc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@@ -13,7 +12,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
|
|
||||||
"github.com/weaveworks/weave/common"
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/net/ipset"
|
||||||
"github.com/weaveworks/weave/npc/iptables"
|
"github.com/weaveworks/weave/npc/iptables"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,20 +31,20 @@ type ns struct {
|
|||||||
uid types.UID // surrogate UID to own allPods selector
|
uid types.UID // surrogate UID to own allPods selector
|
||||||
allPods *selectorSpec // hash:ip ipset of all pod IPs in this namespace
|
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
|
// stores IP addrs of pods which are not selected by any target podSelector of
|
||||||
// any netpol; used only in non-legacy mode and is used as a dst in
|
// any netpol; used as a target in the WEAVE-NPC-{INGRESS,EGRESS}-DEFAULT
|
||||||
// the WEAVE-NPC-DEFAULT iptables chain.
|
// iptables chains.
|
||||||
defaultAllowIPSet ipset.Name
|
ingressDefaultAllowIPSet ipset.Name
|
||||||
|
egressDefaultAllowIPSet ipset.Name
|
||||||
|
|
||||||
nsSelectors *selectorSet
|
nsSelectors *selectorSet
|
||||||
podSelectors *selectorSet
|
podSelectors *selectorSet
|
||||||
|
ipBlocks *ipBlockSet
|
||||||
rules *ruleSet
|
rules *ruleSet
|
||||||
|
|
||||||
legacy bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNS(name, nodeName string, legacy bool, ipt iptables.Interface, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
|
func newNS(name, nodeName string, ipt iptables.Interface, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
|
||||||
allPods, err := newSelectorSpec(&metav1.LabelSelector{}, false, name, ipset.HashIP)
|
allPods, err := newSelectorSpec(&metav1.LabelSelector{}, nil, name, ipset.HashIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -60,19 +59,24 @@ func newNS(name, nodeName string, legacy bool, ipt iptables.Interface, ips ipset
|
|||||||
uid: uuid.NewUUID(),
|
uid: uuid.NewUUID(),
|
||||||
allPods: allPods,
|
allPods: allPods,
|
||||||
nsSelectors: nsSelectors,
|
nsSelectors: nsSelectors,
|
||||||
|
ipBlocks: newIPBlockSet(ips),
|
||||||
rules: newRuleSet(ipt),
|
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 {
|
if err := ns.podSelectors.provision(ns.uid, nil, map[string]*selectorSpec{ns.allPods.key: ns.allPods}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -92,7 +96,7 @@ func (ns *ns) onNewPodSelector(selector *selector) error {
|
|||||||
for _, pod := range ns.pods {
|
for _, pod := range ns.pods {
|
||||||
if hasIP(pod) {
|
if hasIP(pod) {
|
||||||
if selector.matches(pod.ObjectMeta.Labels) {
|
if selector.matches(pod.ObjectMeta.Labels) {
|
||||||
if err := selector.addEntry(pod.Status.PodIP, podComment(pod)); err != nil {
|
if err := selector.addEntry(pod.ObjectMeta.UID, pod.Status.PodIP, podComment(pod)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,16 +106,13 @@ func (ns *ns) onNewPodSelector(selector *selector) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *ns) onNewDstPodSelector(selector *selector) error {
|
func (ns *ns) onNewTargetPodSelector(selector *selector, policyType policyType) error {
|
||||||
if ns.legacy {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pod := range ns.pods {
|
for _, pod := range ns.pods {
|
||||||
if hasIP(pod) {
|
if hasIP(pod) {
|
||||||
// Remove the pod from default-allow if dst podselector matches the pod
|
// Remove the pod from default-allow if dst podselector matches the pod
|
||||||
|
ipset := ns.defaultAllowIPSetName(policyType)
|
||||||
if selector.matches(pod.ObjectMeta.Labels) {
|
if selector.matches(pod.ObjectMeta.Labels) {
|
||||||
if err := ns.ips.DelEntryIfExists(ns.defaultAllowIPSet, pod.Status.PodIP); err != nil {
|
if err := ns.ips.DelEntry(pod.ObjectMeta.UID, ipset, pod.Status.PodIP); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,15 +122,11 @@ func (ns *ns) onNewDstPodSelector(selector *selector) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *ns) onDestroyDstPodSelector(selector *selector) error {
|
func (ns *ns) onDestroyTargetPodSelector(selector *selector, policyType policyType) error {
|
||||||
if ns.legacy {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pod := range ns.pods {
|
for _, pod := range ns.pods {
|
||||||
if hasIP(pod) {
|
if hasIP(pod) {
|
||||||
if selector.matches(pod.ObjectMeta.Labels) {
|
if selector.matches(pod.ObjectMeta.Labels) {
|
||||||
if err := ns.addToDefaultAllowIfNoMatching(pod); err != nil {
|
if err := ns.addToDefaultAllowIfNoMatching(pod, policyType); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,18 +136,19 @@ func (ns *ns) onDestroyDstPodSelector(selector *selector) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add pod IP addr to default-allow ipset if there are no matching dst selectors
|
// Add pod IP addr to default-allow ipset if there are no matching target selectors
|
||||||
func (ns *ns) addToDefaultAllowIfNoMatching(pod *coreapi.Pod) error {
|
func (ns *ns) addToDefaultAllowIfNoMatching(pod *coreapi.Pod, policyType policyType) error {
|
||||||
found := false
|
found := false
|
||||||
// TODO(mp) optimize (avoid iterating over selectors) by ref counting IP addrs.
|
// TODO(mp) optimize (avoid iterating over selectors) by ref counting IP addrs.
|
||||||
for _, s := range ns.podSelectors.entries {
|
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
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
if err := ns.ips.AddEntryIfNotExist(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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,16 +170,21 @@ func (ns *ns) addPod(obj *coreapi.Pod) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ns.checkLocalPod(obj) {
|
if ns.checkLocalPod(obj) {
|
||||||
ns.ips.AddEntry(LocalIpset, obj.Status.PodIP, podComment(obj))
|
ns.ips.AddEntry(obj.ObjectMeta.UID, LocalIpset, obj.Status.PodIP, podComment(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
found, err := ns.podSelectors.addToMatching(obj.ObjectMeta.Labels, obj.Status.PodIP, podComment(obj))
|
foundIngress, foundEgress, err := ns.podSelectors.addToMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, obj.Status.PodIP, podComment(obj))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// If there are no matching dst selectors, add the pod to default-allow
|
// If there are no matching target selectors, add the pod to default-allow
|
||||||
if !ns.legacy && !found {
|
if !foundIngress {
|
||||||
if err := ns.ips.AddEntryIfNotExist(ns.defaultAllowIPSet, obj.Status.PodIP, podComment(obj)); err != nil {
|
if err := ns.ips.AddEntry(obj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, obj.Status.PodIP, podComment(obj)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundEgress {
|
||||||
|
if err := ns.ips.AddEntry(obj.ObjectMeta.UID, ns.egressDefaultAllowIPSet, obj.Status.PodIP, podComment(obj)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,29 +202,35 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
|
|||||||
|
|
||||||
if hasIP(oldObj) && !hasIP(newObj) {
|
if hasIP(oldObj) && !hasIP(newObj) {
|
||||||
if ns.checkLocalPod(oldObj) {
|
if ns.checkLocalPod(oldObj) {
|
||||||
ns.ips.DelEntry(LocalIpset, oldObj.Status.PodIP)
|
ns.ips.DelEntry(oldObj.ObjectMeta.UID, LocalIpset, oldObj.Status.PodIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ns.legacy {
|
if err := ns.ips.DelEntry(oldObj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, oldObj.Status.PodIP); err != nil {
|
||||||
if err := ns.ips.DelEntryIfExists(ns.defaultAllowIPSet, oldObj.Status.PodIP); err != nil {
|
return err
|
||||||
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.Labels, oldObj.Status.PodIP)
|
return ns.podSelectors.delFromMatching(oldObj.ObjectMeta.UID, oldObj.ObjectMeta.Labels, oldObj.Status.PodIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasIP(oldObj) && hasIP(newObj) {
|
if !hasIP(oldObj) && hasIP(newObj) {
|
||||||
if ns.checkLocalPod(newObj) {
|
if ns.checkLocalPod(newObj) {
|
||||||
ns.ips.AddEntry(LocalIpset, newObj.Status.PodIP, podComment(newObj))
|
ns.ips.AddEntry(newObj.ObjectMeta.UID, LocalIpset, newObj.Status.PodIP, podComment(newObj))
|
||||||
}
|
}
|
||||||
found, err := ns.podSelectors.addToMatching(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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ns.legacy && !found {
|
if !foundIngress {
|
||||||
if err := ns.ips.AddEntryIfNotExist(ns.defaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
|
if err := ns.ips.AddEntry(newObj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundEgress {
|
||||||
|
if err := ns.ips.AddEntry(newObj.ObjectMeta.UID, ns.egressDefaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,14 +238,11 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ns.legacy &&
|
if oldObj.Status.PodIP != newObj.Status.PodIP {
|
||||||
oldObj.Status.PodIP != newObj.Status.PodIP &&
|
if err := ns.updateDefaultAllowIPSetEntry(oldObj, newObj, ns.ingressDefaultAllowIPSet); err != nil {
|
||||||
ns.ips.Exist(ns.defaultAllowIPSet, oldObj.Status.PodIP) {
|
|
||||||
|
|
||||||
if err := ns.ips.DelEntryIfExists(ns.defaultAllowIPSet, oldObj.Status.PodIP); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ns.ips.AddEntryIfNotExist(ns.defaultAllowIPSet, newObj.Status.PodIP, podComment(newObj)); err != nil {
|
if err := ns.updateDefaultAllowIPSetEntry(oldObj, newObj, ns.egressDefaultAllowIPSet); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,27 +257,21 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if oldMatch {
|
if oldMatch {
|
||||||
if err := ps.delEntry(oldObj.Status.PodIP); err != nil {
|
if err := ps.delEntry(oldObj.ObjectMeta.UID, oldObj.Status.PodIP); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if newMatch {
|
if newMatch {
|
||||||
if err := ps.addEntry(newObj.Status.PodIP, podComment(newObj)); err != nil {
|
if err := ps.addEntry(newObj.ObjectMeta.UID, newObj.Status.PodIP, podComment(newObj)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ns.legacy && ns.podSelectors.dstSelectorExist(ps) {
|
if err := ns.addOrRemoveToDefaultAllowIPSet(ps, oldObj, newObj, oldMatch, newMatch, policyTypeIngress); err != nil {
|
||||||
switch {
|
return err
|
||||||
case !oldMatch && newMatch:
|
}
|
||||||
if err := ns.ips.DelEntryIfExists(ns.defaultAllowIPSet, oldObj.Status.PodIP); err != nil {
|
if err := ns.addOrRemoveToDefaultAllowIPSet(ps, oldObj, newObj, oldMatch, newMatch, policyTypeEgress); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
case oldMatch && !newMatch:
|
|
||||||
if err := ns.addToDefaultAllowIfNoMatching(newObj); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,6 +279,23 @@ func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
|
|||||||
return nil
|
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 {
|
func (ns *ns) deletePod(obj *coreapi.Pod) error {
|
||||||
delete(ns.pods, obj.ObjectMeta.UID)
|
delete(ns.pods, obj.ObjectMeta.UID)
|
||||||
|
|
||||||
@@ -287,22 +304,23 @@ func (ns *ns) deletePod(obj *coreapi.Pod) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ns.checkLocalPod(obj) {
|
if ns.checkLocalPod(obj) {
|
||||||
ns.ips.DelEntry(LocalIpset, obj.Status.PodIP)
|
ns.ips.DelEntry(obj.ObjectMeta.UID, LocalIpset, obj.Status.PodIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ns.legacy {
|
if err := ns.ips.DelEntry(obj.ObjectMeta.UID, ns.ingressDefaultAllowIPSet, obj.Status.PodIP); err != nil {
|
||||||
if err := ns.ips.DelEntryIfExists(ns.defaultAllowIPSet, obj.Status.PodIP); err != nil {
|
return err
|
||||||
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.Labels, obj.Status.PodIP)
|
return ns.podSelectors.delFromMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, obj.Status.PodIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *ns) addNetworkPolicy(obj interface{}) error {
|
func (ns *ns) addNetworkPolicy(obj interface{}) error {
|
||||||
// Analyse policy, determine which rules and ipsets are required
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -314,16 +332,19 @@ func (ns *ns) addNetworkPolicy(obj interface{}) error {
|
|||||||
if err := ns.podSelectors.provision(uid, nil, podSelectors); err != nil {
|
if err := ns.podSelectors.provision(uid, nil, podSelectors); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := ns.ipBlocks.provision(uid, nil, ipBlocks); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return ns.rules.provision(uid, nil, rules)
|
return ns.rules.provision(uid, nil, rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *ns) updateNetworkPolicy(oldObj, newObj interface{}) error {
|
func (ns *ns) updateNetworkPolicy(oldObj, newObj interface{}) error {
|
||||||
// Analyse the old and the new policy so we can determine differences
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
newUID, newRules, newNsSelectors, newPodSelectors, err := ns.analyse(newObj)
|
newUID, newRules, newNsSelectors, newPodSelectors, newIPBlocks, err := ns.analyse(newObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -341,18 +362,24 @@ func (ns *ns) updateNetworkPolicy(oldObj, newObj interface{}) error {
|
|||||||
if err := ns.podSelectors.deprovision(oldUID, oldPodSelectors, newPodSelectors); err != nil {
|
if err := ns.podSelectors.deprovision(oldUID, oldPodSelectors, newPodSelectors); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := ns.ipBlocks.deprovision(oldUID, oldIPBlocks, newIPBlocks); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := ns.nsSelectors.provision(oldUID, oldNsSelectors, newNsSelectors); err != nil {
|
if err := ns.nsSelectors.provision(oldUID, oldNsSelectors, newNsSelectors); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ns.podSelectors.provision(oldUID, oldPodSelectors, newPodSelectors); err != nil {
|
if err := ns.podSelectors.provision(oldUID, oldPodSelectors, newPodSelectors); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := ns.ipBlocks.provision(oldUID, oldIPBlocks, newIPBlocks); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return ns.rules.provision(oldUID, oldRules, newRules)
|
return ns.rules.provision(oldUID, oldRules, newRules)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *ns) deleteNetworkPolicy(obj interface{}) error {
|
func (ns *ns) deleteNetworkPolicy(obj interface{}) error {
|
||||||
// Analyse network policy to free resources
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -366,73 +393,89 @@ func (ns *ns) deleteNetworkPolicy(obj interface{}) error {
|
|||||||
if err := ns.nsSelectors.deprovision(uid, nsSelectors, nil); err != nil {
|
if err := ns.nsSelectors.deprovision(uid, nsSelectors, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ns.podSelectors.deprovision(uid, podSelectors, nil)
|
if err := ns.podSelectors.deprovision(uid, podSelectors, nil); err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
func bypassRule(nsIpsetName ipset.Name, namespace string) []string {
|
if err := ns.ipBlocks.deprovision(uid, ipBlocks, nil); err != nil {
|
||||||
return []string{"-m", "set", "--match-set", string(nsIpsetName), "dst", "-j", "ACCEPT", "-m", "comment", "--comment", "DefaultAllow isolation for namespace: " + namespace}
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
func (ns *ns) ensureBypassRule() error {
|
|
||||||
var ipset ipset.Name
|
|
||||||
if ns.legacy {
|
|
||||||
ipset = ns.allPods.ipsetName
|
|
||||||
} else {
|
|
||||||
ipset = ns.defaultAllowIPSet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
common.Log.Debugf("ensuring rule for DefaultAllow in namespace: %s, set %s", ns.name, ipset)
|
return nil
|
||||||
return ns.ipt.Append(TableFilter, DefaultChain, bypassRule(ipset, ns.name)...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *ns) deleteBypassRule() error {
|
func (ns *ns) updateDefaultAllowIPSetEntry(oldObj, newObj *coreapi.Pod, ipsetName ipset.Name) error {
|
||||||
var ipset ipset.Name
|
// Instead of iterating over all selectors we check whether old pod IP
|
||||||
if ns.legacy {
|
// has been inserted into default-allow ipset to decide whether the IP
|
||||||
ipset = ns.allPods.ipsetName
|
// in the ipset has to be updated.
|
||||||
} else {
|
if ns.ips.Exist(oldObj.ObjectMeta.UID, ipsetName, oldObj.Status.PodIP) {
|
||||||
ipset = ns.defaultAllowIPSet
|
|
||||||
|
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 nil
|
||||||
return ns.ipt.Delete(TableFilter, DefaultChain, bypassRule(ipset, ns.name)...)
|
}
|
||||||
|
|
||||||
|
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 {
|
func (ns *ns) addNamespace(obj *coreapi.Namespace) error {
|
||||||
ns.namespace = obj
|
ns.namespace = obj
|
||||||
|
|
||||||
// Insert a rule to bypass policies if namespace is DefaultAllow
|
// Insert a rule to bypass policies
|
||||||
if !ns.isDefaultDeny(obj) {
|
if err := ns.ensureBypassRules(); err != nil {
|
||||||
if err := ns.ensureBypassRule(); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add namespace ipset to matching namespace selectors
|
// Add namespace ipset to matching namespace selectors
|
||||||
_, err := ns.nsSelectors.addToMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName), namespaceComment(ns))
|
_, _, err := ns.nsSelectors.addToMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, string(ns.allPods.ipsetName), namespaceComment(ns))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *ns) updateNamespace(oldObj, newObj *coreapi.Namespace) error {
|
func (ns *ns) updateNamespace(oldObj, newObj *coreapi.Namespace) error {
|
||||||
ns.namespace = newObj
|
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
|
// Re-evaluate namespace selector membership if labels have changed
|
||||||
if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) {
|
if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) {
|
||||||
for _, selector := range ns.nsSelectors.entries {
|
for _, selector := range ns.nsSelectors.entries {
|
||||||
@@ -442,12 +485,12 @@ func (ns *ns) updateNamespace(oldObj, newObj *coreapi.Namespace) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if oldMatch {
|
if oldMatch {
|
||||||
if err := selector.delEntry(string(ns.allPods.ipsetName)); err != nil {
|
if err := selector.delEntry(ns.namespace.ObjectMeta.UID, string(ns.allPods.ipsetName)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if newMatch {
|
if newMatch {
|
||||||
if err := selector.addEntry(string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
|
if err := selector.addEntry(ns.namespace.ObjectMeta.UID, string(ns.allPods.ipsetName), namespaceComment(ns)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -461,37 +504,24 @@ func (ns *ns) deleteNamespace(obj *coreapi.Namespace) error {
|
|||||||
ns.namespace = nil
|
ns.namespace = nil
|
||||||
|
|
||||||
// Remove bypass rule
|
// Remove bypass rule
|
||||||
if !ns.isDefaultDeny(obj) {
|
if err := ns.deleteBypassRules(); err != nil {
|
||||||
if err := ns.deleteBypassRule(); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove namespace ipset from any matching namespace selectors
|
// Remove namespace ipset from any matching namespace selectors
|
||||||
return ns.nsSelectors.delFromMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
|
err := ns.nsSelectors.delFromMatching(obj.ObjectMeta.UID, obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
func (ns *ns) isDefaultDeny(namespace *coreapi.Namespace) bool {
|
|
||||||
nnpJSON, found := namespace.ObjectMeta.Annotations["net.beta.kubernetes.io/network-policy"]
|
|
||||||
if !found {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ns.legacy {
|
if err := ns.ips.Destroy(ns.ingressDefaultAllowIPSet); err != nil {
|
||||||
common.Log.Warn("DefaultDeny annotation is supported only in legacy mode (--use-legacy-netpol)")
|
return err
|
||||||
return false
|
}
|
||||||
|
if err := ns.ips.Destroy(ns.egressDefaultAllowIPSet); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var nnp NamespaceNetworkPolicy
|
return nil
|
||||||
if err := json.Unmarshal([]byte(nnpJSON), &nnp); err != nil {
|
|
||||||
common.Log.Warn("Ignoring network policy annotation: unmarshal failed:", err)
|
|
||||||
// If we can't understand the annotation, behave as if it isn't present
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return nnp.Ingress != nil &&
|
|
||||||
nnp.Ingress.Isolation != nil &&
|
|
||||||
*(nnp.Ingress.Isolation) == DefaultDeny
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasIP(pod *coreapi.Pod) bool {
|
func hasIP(pod *coreapi.Pod) bool {
|
||||||
@@ -520,10 +550,19 @@ func podComment(pod *coreapi.Pod) string {
|
|||||||
return fmt.Sprintf("namespace: %s, pod: %s", pod.ObjectMeta.Namespace, pod.ObjectMeta.Name)
|
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{}) (
|
func (ns *ns) analyse(obj interface{}) (
|
||||||
uid types.UID,
|
uid types.UID,
|
||||||
rules map[string]*ruleSpec,
|
rules map[string]*ruleSpec,
|
||||||
nsSelectors, podSelectors map[string]*selectorSpec,
|
nsSelectors, podSelectors map[string]*selectorSpec,
|
||||||
|
ipBlocks map[string]*ipBlockSpec,
|
||||||
err error) {
|
err error) {
|
||||||
|
|
||||||
switch p := obj.(type) {
|
switch p := obj.(type) {
|
||||||
@@ -538,16 +577,9 @@ func (ns *ns) analyse(obj interface{}) (
|
|||||||
ns.policies[uid] = obj
|
ns.policies[uid] = obj
|
||||||
|
|
||||||
// Analyse policy, determine which rules and ipsets are required
|
// Analyse policy, determine which rules and ipsets are required
|
||||||
if ns.legacy {
|
rules, nsSelectors, podSelectors, ipBlocks, err = ns.analysePolicy(obj.(*networkingv1.NetworkPolicy))
|
||||||
rules, nsSelectors, podSelectors, err = ns.analysePolicyLegacy(obj.(*extnapi.NetworkPolicy))
|
if err != nil {
|
||||||
if err != nil {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rules, nsSelectors, podSelectors, err = ns.analysePolicy(obj.(*networkingv1.NetworkPolicy))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
+64
-23
@@ -2,6 +2,7 @@ package npc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
@@ -10,38 +11,71 @@ import (
|
|||||||
"github.com/weaveworks/weave/npc/iptables"
|
"github.com/weaveworks/weave/npc/iptables"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ruleSpec struct {
|
type ruleHost interface {
|
||||||
key string
|
// getRuleSpec returns source or destination specification and comment which
|
||||||
args []string
|
// 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{}
|
args := []string{}
|
||||||
if proto != nil {
|
if proto != nil {
|
||||||
args = append(args, "-p", *proto)
|
args = append(args, "-p", *proto)
|
||||||
}
|
}
|
||||||
srcComment := "anywhere"
|
srcComment := "anywhere"
|
||||||
if srcHost != nil {
|
if srcHost != nil && !reflect.ValueOf(srcHost).IsNil() {
|
||||||
args = append(args, "-m", "set", "--match-set", string(srcHost.ipsetName), "src")
|
rule, comment := srcHost.getRuleSpec(true)
|
||||||
if srcHost.nsName != "" {
|
args = append(args, rule...)
|
||||||
srcComment = fmt.Sprintf("pods: namespace: %s, selector: %s", srcHost.nsName, srcHost.key)
|
srcComment = comment
|
||||||
} else {
|
|
||||||
srcComment = fmt.Sprintf("namespaces: selector: %s", srcHost.key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dstComment := "anywhere"
|
dstComment := "anywhere"
|
||||||
if dstHost != nil {
|
if dstHost != nil && !reflect.ValueOf(dstHost).IsNil() {
|
||||||
args = append(args, "-m", "set", "--match-set", string(dstHost.ipsetName), "dst")
|
rule, comment := dstHost.getRuleSpec(false)
|
||||||
dstComment = fmt.Sprintf("pods: namespace: %s, selector: %s", dstHost.nsName, dstHost.key)
|
args = append(args, rule...)
|
||||||
|
dstComment = comment
|
||||||
}
|
}
|
||||||
if dstPort != nil {
|
if dstPort != nil {
|
||||||
args = append(args, "--dport", *dstPort)
|
args = append(args, "--dport", *dstPort)
|
||||||
}
|
}
|
||||||
args = append(args, "-j", "ACCEPT")
|
// NOTE: if you remove the comment bellow, then embed `policyType` into `key`.
|
||||||
args = append(args, "-m", "comment", "--comment", fmt.Sprintf("%s -> %s", srcComment, dstComment))
|
// 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, " ")
|
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 {
|
type ruleSet struct {
|
||||||
@@ -58,10 +92,14 @@ func (rs *ruleSet) deprovision(user types.UID, current, desired map[string]*rule
|
|||||||
if _, found := desired[key]; !found {
|
if _, found := desired[key]; !found {
|
||||||
delete(rs.users[key], user)
|
delete(rs.users[key], user)
|
||||||
if len(rs.users[key]) == 0 {
|
if len(rs.users[key]) == 0 {
|
||||||
common.Log.Infof("deleting rule: %v", spec.args)
|
chain := spec.iptChain()
|
||||||
if err := rs.ipt.Delete(TableFilter, IngressChain, spec.args...); err != nil {
|
for _, rule := range spec.iptRuleSpecs() {
|
||||||
return err
|
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)
|
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 {
|
for key, spec := range desired {
|
||||||
if _, found := current[key]; !found {
|
if _, found := current[key]; !found {
|
||||||
if _, found := rs.users[key]; !found {
|
if _, found := rs.users[key]; !found {
|
||||||
common.Log.Infof("adding rule: %v", spec.args)
|
chain := spec.iptChain()
|
||||||
if err := rs.ipt.Append(TableFilter, IngressChain, spec.args...); err != nil {
|
for _, rule := range spec.iptRuleSpecs() {
|
||||||
return err
|
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{})
|
rs.users[key] = make(map[types.UID]struct{})
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ func TestRegressionHandleNil3095(t *testing.T) {
|
|||||||
// Test for handling nil values
|
// Test for handling nil values
|
||||||
// https://github.com/weaveworks/weave/issues/3095
|
// 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, "")
|
require.NotEqual(t, rs.key, "")
|
||||||
|
|
||||||
|
|||||||
+73
-45
@@ -1,34 +1,36 @@
|
|||||||
package npc
|
package npc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
"github.com/weaveworks/weave/common"
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/net/ipset"
|
||||||
)
|
)
|
||||||
|
|
||||||
type selectorSpec struct {
|
type selectorSpec struct {
|
||||||
key string // string representation (for hash keying/equality comparison)
|
key string // string representation (for hash keying/equality comparison)
|
||||||
selector labels.Selector // k8s Selector object (for matching)
|
selector labels.Selector // k8s Selector object (for matching)
|
||||||
dst bool // destination selector
|
policyTypes []policyType // If non-empty, then selectorSpec is a target selector for given policyTypes.
|
||||||
|
|
||||||
ipsetType ipset.Type // type of ipset to provision
|
ipsetType ipset.Type // type of ipset to provision
|
||||||
ipsetName ipset.Name // generated ipset name
|
ipsetName ipset.Name // generated ipset name
|
||||||
nsName string // Namespace 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)
|
selector, err := metav1.LabelSelectorAsSelector(json)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
key := selector.String()
|
key := selector.String()
|
||||||
return &selectorSpec{
|
return &selectorSpec{
|
||||||
key: key,
|
key: key,
|
||||||
selector: selector,
|
selector: selector,
|
||||||
dst: dst,
|
policyTypes: policyType,
|
||||||
// We prefix the selector string with the namespace name when generating
|
// We prefix the selector string with the namespace name when generating
|
||||||
// the shortname because you can specify the same selector in multiple
|
// the shortname because you can specify the same selector in multiple
|
||||||
// namespaces - we need those to map to distinct ipsets
|
// 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
|
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 {
|
type selector struct {
|
||||||
ips ipset.Interface
|
ips ipset.Interface
|
||||||
spec *selectorSpec
|
spec *selectorSpec
|
||||||
@@ -46,64 +65,69 @@ func (s *selector) matches(labelMap map[string]string) bool {
|
|||||||
return s.spec.selector.Matches(labels.Set(labelMap))
|
return s.spec.selector.Matches(labels.Set(labelMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selector) addEntry(entry string, comment string) error {
|
func (s *selector) addEntry(user types.UID, entry string, comment string) error {
|
||||||
return s.ips.AddEntry(s.spec.ipsetName, entry, comment)
|
return s.ips.AddEntry(user, s.spec.ipsetName, entry, comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selector) delEntry(entry string) error {
|
func (s *selector) delEntry(user types.UID, entry string) error {
|
||||||
return s.ips.DelEntry(s.spec.ipsetName, entry)
|
return s.ips.DelEntry(user, s.spec.ipsetName, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
type selectorFn func(selector *selector) error
|
type selectorFn func(selector *selector) error
|
||||||
|
type selectorWithPolicyTypeFn func(selector *selector, policyType policyType) error
|
||||||
|
|
||||||
type selectorSet struct {
|
type selectorSet struct {
|
||||||
ips ipset.Interface
|
ips ipset.Interface
|
||||||
onNewSelector selectorFn
|
onNewSelector selectorFn
|
||||||
|
|
||||||
// invoked after dst selector has been provisioned for the first time
|
// invoked after target selector has been provisioned for the first time
|
||||||
onNewDstSelector selectorFn
|
onNewTargetSelector selectorWithPolicyTypeFn
|
||||||
// invoked after the last instance of dst selector has been deprovisioned
|
// invoked after the last instance of target selector has been deprovisioned
|
||||||
onDestroyDstSelector selectorFn
|
onDestroyTargetSelector selectorWithPolicyTypeFn
|
||||||
|
|
||||||
users map[string]map[types.UID]struct{} // list of users per selector
|
users map[string]map[types.UID]struct{} // list of users per selector
|
||||||
entries map[string]*selector
|
entries map[string]*selector
|
||||||
|
|
||||||
// We need to keep track of dst selector instances to be able to invoke
|
// We need to keep track of target selector instances to be able to invoke
|
||||||
// onNewDstSelector and onDestroyDstSelector callbacks at the right time;
|
// onNewTargetSelector and onDestroyTargetSelector callbacks at the right time;
|
||||||
// selectorSpec.Key -> count
|
// selectorSpec.Key -> policyType -> count
|
||||||
dstSelectorsCount map[string]int
|
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{
|
return &selectorSet{
|
||||||
ips: ips,
|
ips: ips,
|
||||||
onNewSelector: onNewSelector,
|
onNewSelector: onNewSelector,
|
||||||
onNewDstSelector: onNewDstSelector,
|
onNewTargetSelector: onNewTargetSelector,
|
||||||
onDestroyDstSelector: onDestroyDstSelector,
|
onDestroyTargetSelector: onDestroyTargetSelector,
|
||||||
users: make(map[string]map[types.UID]struct{}),
|
users: make(map[string]map[types.UID]struct{}),
|
||||||
entries: make(map[string]*selector),
|
entries: make(map[string]*selector),
|
||||||
dstSelectorsCount: make(map[string]int)}
|
targetSelectorsCount: make(map[string]map[policyType]int)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *selectorSet) addToMatching(labelMap map[string]string, entry string, comment string) (bool, error) {
|
func (ss *selectorSet) addToMatching(user types.UID, labelMap map[string]string, entry string, comment string) (bool, bool, error) {
|
||||||
found := false
|
foundIngress := false
|
||||||
|
foundEgress := false
|
||||||
for _, s := range ss.entries {
|
for _, s := range ss.entries {
|
||||||
if s.matches(labelMap) {
|
if s.matches(labelMap) {
|
||||||
if ss.dstSelectorExist(s) {
|
if ss.targetSelectorExist(s, policyTypeIngress) {
|
||||||
found = true
|
foundIngress = true
|
||||||
}
|
}
|
||||||
if err := s.addEntry(entry, comment); err != nil {
|
if ss.targetSelectorExist(s, policyTypeEgress) {
|
||||||
return found, err
|
foundEgress = true
|
||||||
|
}
|
||||||
|
if err := s.addEntry(user, entry, comment); err != nil {
|
||||||
|
return foundIngress, foundEgress, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return found, nil
|
return foundIngress, foundEgress, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *selectorSet) delFromMatching(labelMap map[string]string, entry string) error {
|
func (ss *selectorSet) delFromMatching(user types.UID, labelMap map[string]string, entry string) error {
|
||||||
for _, s := range ss.entries {
|
for _, s := range ss.entries {
|
||||||
if s.matches(labelMap) {
|
if s.matches(labelMap) {
|
||||||
if err := s.delEntry(entry); err != nil {
|
if err := s.delEntry(user, entry); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,8 +135,8 @@ func (ss *selectorSet) delFromMatching(labelMap map[string]string, entry string)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *selectorSet) dstSelectorExist(s *selector) bool {
|
func (ss *selectorSet) targetSelectorExist(s *selector, policyType policyType) bool {
|
||||||
return ss.dstSelectorsCount[s.spec.key] > 0
|
return ss.targetSelectorsCount[s.spec.key][policyType] > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *selectorSet) deprovision(user types.UID, current, desired map[string]*selectorSpec) error {
|
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)
|
delete(ss.users, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.dst {
|
for _, policyType := range spec.policyTypes {
|
||||||
ss.dstSelectorsCount[key]--
|
ss.targetSelectorsCount[key][policyType]--
|
||||||
if ss.dstSelectorsCount[key] == 0 {
|
if ss.targetSelectorsCount[key][policyType] == 0 {
|
||||||
if err := ss.onDestroyDstSelector(&selector{ss.ips, spec}); err != nil {
|
if err := ss.onDestroyTargetSelector(&selector{ss.ips, spec}, policyType); err != nil {
|
||||||
return err
|
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{}{}
|
ss.users[key][user] = struct{}{}
|
||||||
|
|
||||||
if spec.dst {
|
for _, pt := range spec.policyTypes {
|
||||||
ss.dstSelectorsCount[key]++
|
if _, found := ss.targetSelectorsCount[key]; !found {
|
||||||
if ss.dstSelectorsCount[key] == 1 {
|
ss.targetSelectorsCount[key] = make(map[policyType]int)
|
||||||
if err := ss.onNewDstSelector(selector); err != nil {
|
}
|
||||||
|
ss.targetSelectorsCount[key][pt]++
|
||||||
|
if ss.targetSelectorsCount[key][pt] == 1 {
|
||||||
|
if err := ss.onNewTargetSelector(selector, pt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -110,6 +110,10 @@ func (i *Ipam) ReleaseAddress(poolID string, address net.IP) error {
|
|||||||
return i.weave.ReleaseIPsFor(address.String())
|
return i.weave.ReleaseIPsFor(address.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Ipam) IsBuiltIn() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Functions required by ipamapi "contract" but not actually used.
|
// Functions required by ipamapi "contract" but not actually used.
|
||||||
|
|
||||||
func (i *Ipam) DiscoverNew(discoverapi.DiscoveryType, interface{}) error {
|
func (i *Ipam) DiscoverNew(discoverapi.DiscoveryType, interface{}) error {
|
||||||
|
|||||||
+18
-2
@@ -117,6 +117,16 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
defer ns.Close()
|
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
|
id := args.ContainerID
|
||||||
if len(id) < 5 {
|
if len(id) < 5 {
|
||||||
data := make([]byte, 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 {
|
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
|
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)
|
return setupRoutes(link, args.IfName, ip.Address, ip.Gateway, result.Routes)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("error setting up routes: %s", err)
|
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
|
// As of CNI 0.3 spec, runtimes can send blank if they just want the address deallocated
|
||||||
if args.Netns != "" {
|
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.
|
// 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))
|
logOnStderr(fmt.Errorf("error removing interface %q: %s", args.IfName, err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// create veths. note we assume endpoint IDs are unique in the first 9 chars
|
||||||
name, peerName := vethPair(create.EndpointID)
|
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)
|
return nil, driver.error("JoinEndpoint", "%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ func (w *watcher) ContainerStarted(id string) {
|
|||||||
rootDir = "/host"
|
rootDir = "/host"
|
||||||
}
|
}
|
||||||
netNSPath := weavenet.NSPathByPidWithRoot(rootDir, info.State.Pid)
|
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)
|
w.driver.warn("ContainerStarted", "unable to configure interfaces: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,8 +73,10 @@ const (
|
|||||||
retryPeriod = time.Second * 2
|
retryPeriod = time.Second * 2
|
||||||
jitterFactor = 1.0
|
jitterFactor = 1.0
|
||||||
|
|
||||||
|
// Prefix all our annotation keys with this string so they don't clash with anyone else's
|
||||||
|
KubePeersPrefix = "kube-peers.weave.works/"
|
||||||
// KubePeersAnnotationKey is the default annotation key
|
// KubePeersAnnotationKey is the default annotation key
|
||||||
KubePeersAnnotationKey = "kube-peers.weave.works/peers"
|
KubePeersAnnotationKey = KubePeersPrefix + "peers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cml *configMapAnnotations) Init() error {
|
func (cml *configMapAnnotations) Init() error {
|
||||||
@@ -130,46 +132,59 @@ func (cml *configMapAnnotations) UpdatePeerList(list peerList) error {
|
|||||||
return cml.UpdateAnnotation(KubePeersAnnotationKey, string(recordBytes))
|
return cml.UpdateAnnotation(KubePeersAnnotationKey, string(recordBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cml *configMapAnnotations) UpdateAnnotation(key, value string) error {
|
// Clean up a string so it meets the Kubernetes requiremements for Annotation keys:
|
||||||
|
// name part must consist of alphanumeric characters, '-', '_' or '.', and must
|
||||||
|
// start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc')
|
||||||
|
func cleanKey(key string) string {
|
||||||
|
buf := []byte(key)
|
||||||
|
for i, c := range buf {
|
||||||
|
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '/' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf[i] = '_'
|
||||||
|
}
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cml *configMapAnnotations) GetAnnotation(key string) (string, bool) {
|
||||||
|
value, ok := cml.cm.Annotations[cleanKey(key)]
|
||||||
|
return value, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cml *configMapAnnotations) UpdateAnnotation(key, value string) (err error) {
|
||||||
if cml.cm == nil {
|
if cml.cm == nil {
|
||||||
return errors.New("endpoint not initialized, call Init first")
|
return errors.New("endpoint not initialized, call Init first")
|
||||||
}
|
}
|
||||||
cm := cml.cm
|
// speculatively change the state, then replace with whatever comes back
|
||||||
cm.Annotations[key] = value
|
// from Update(), which will be the latest on the server whatever happened
|
||||||
cm, err := cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
|
cml.cm.Annotations[cleanKey(key)] = value
|
||||||
if err == nil {
|
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
|
||||||
cml.cm = cm
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cml *configMapAnnotations) RemoveAnnotation(key string) error {
|
func (cml *configMapAnnotations) RemoveAnnotation(key string) (err error) {
|
||||||
if cml.cm == nil {
|
if cml.cm == nil {
|
||||||
return errors.New("endpoint not initialized, call Init first")
|
return errors.New("endpoint not initialized, call Init first")
|
||||||
}
|
}
|
||||||
cm := cml.cm
|
// speculatively change the state, then replace with whatever comes back
|
||||||
delete(cm.Annotations, key)
|
// from Update(), which will be the latest on the server whatever happened
|
||||||
cm, err := cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
|
delete(cml.cm.Annotations, cleanKey(key))
|
||||||
if err == nil {
|
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
|
||||||
cml.cm = cm
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cml *configMapAnnotations) RemoveAnnotationsWithValue(valueToRemove string) error {
|
func (cml *configMapAnnotations) RemoveAnnotationsWithValue(valueToRemove string) (err error) {
|
||||||
if cml.cm == nil {
|
if cml.cm == nil {
|
||||||
return errors.New("endpoint not initialized, call Init first")
|
return errors.New("endpoint not initialized, call Init first")
|
||||||
}
|
}
|
||||||
cm := cml.cm
|
// speculatively change the state, then replace with whatever comes back
|
||||||
for key, value := range cm.Annotations {
|
// from Update(), which will be the latest on the server whatever happened
|
||||||
|
for key, value := range cml.cm.Annotations {
|
||||||
if value == valueToRemove {
|
if value == valueToRemove {
|
||||||
delete(cm.Annotations, key)
|
delete(cml.cm.Annotations, key) // don't need to clean this key as it came from the map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cm, err := cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
|
cml.cm, err = cml.Client.ConfigMaps(cml.Namespace).Update(cml.cm)
|
||||||
if err == nil {
|
|
||||||
cml.cm = cm
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,10 @@ func checkIamInPeerList(cml *configMapAnnotations, c *kubernetes.Clientset, peer
|
|||||||
// For each of those peers that is no longer listed as a node by
|
// For each of those peers that is no longer listed as a node by
|
||||||
// Kubernetes, remove it from Weave IPAM
|
// Kubernetes, remove it from Weave IPAM
|
||||||
func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, nodes []nodeInfo, myPeerName string) error {
|
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
|
||||||
|
}
|
||||||
// 1. Compare peers stored in the peerList against all peers reported by k8s now.
|
// 1. Compare peers stored in the peerList against all peers reported by k8s now.
|
||||||
storedPeerList, err := cml.GetPeerList()
|
storedPeerList, err := cml.GetPeerList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -116,10 +119,14 @@ 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
|
// 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 {
|
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)
|
common.Log.Debugln("[kube-peers] Preparing to remove disappeared peer", peer)
|
||||||
okToRemove := false
|
okToRemove := false
|
||||||
// 3. Check if there is an existing annotation with key X
|
// 3. Check if there is an existing annotation with key X
|
||||||
if existingAnnotation, found := cml.cm.Annotations[peer.PeerName]; found {
|
if existingAnnotation, found := cml.GetAnnotation(KubePeersPrefix + peer.PeerName); found {
|
||||||
common.Log.Debugln("[kube-peers] Existing annotation", existingAnnotation)
|
common.Log.Debugln("[kube-peers] Existing annotation", existingAnnotation)
|
||||||
// 4. If annotation already contains my identity, ok;
|
// 4. If annotation already contains my identity, ok;
|
||||||
if existingAnnotation == myPeerName {
|
if existingAnnotation == myPeerName {
|
||||||
@@ -128,17 +135,20 @@ func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, node
|
|||||||
} else {
|
} else {
|
||||||
// 5. If non-existent, write an annotation with key X and contents "my identity"
|
// 5. If non-existent, write an annotation with key X and contents "my identity"
|
||||||
common.Log.Debugln("[kube-peers] Noting I plan to remove ", peer.PeerName)
|
common.Log.Debugln("[kube-peers] Noting I plan to remove ", peer.PeerName)
|
||||||
if err := cml.UpdateAnnotation(peer.PeerName, myPeerName); err == nil {
|
if err := cml.UpdateAnnotation(KubePeersPrefix+peer.PeerName, myPeerName); err == nil {
|
||||||
okToRemove = true
|
okToRemove = true
|
||||||
|
} else {
|
||||||
|
common.Log.Debugln("[kube-peers] error from UpdateAnnotation: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if okToRemove {
|
if okToRemove {
|
||||||
// 6. If step 4 or 5 succeeded, rmpeer X
|
// 6. If step 4 or 5 succeeded, rmpeer X
|
||||||
result, err := weave.RmPeer(peer.PeerName)
|
result, err := weave.RmPeer(peer.PeerName)
|
||||||
common.Log.Infoln("[kube-peers] rmpeer of", peer.PeerName, ":", result)
|
common.Log.Infof("[kube-peers] rmpeer of %s: %s", peer.PeerName, result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
loopsWhenNothingChanged = 0
|
||||||
cml.LoopUpdate(func() error {
|
cml.LoopUpdate(func() error {
|
||||||
// 7aa. Remove any annotations Z* that have contents X
|
// 7aa. Remove any annotations Z* that have contents X
|
||||||
if err := cml.RemoveAnnotationsWithValue(peer.PeerName); err != nil {
|
if err := cml.RemoveAnnotationsWithValue(peer.PeerName); err != nil {
|
||||||
@@ -146,15 +156,12 @@ func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, node
|
|||||||
}
|
}
|
||||||
// 7a. Remove X from peerList
|
// 7a. Remove X from peerList
|
||||||
storedPeerList.remove(peer.PeerName)
|
storedPeerList.remove(peer.PeerName)
|
||||||
common.Log.Infoln("[kube-peers] Removing peer ", peer.PeerName, ". Expecting to remove linked annotation next.")
|
|
||||||
if err := cml.UpdatePeerList(*storedPeerList); err != nil {
|
if err := cml.UpdatePeerList(*storedPeerList); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
common.Log.Infoln("[kube-peers] Removing annotation ", peer.PeerName)
|
|
||||||
// 7b. Remove annotation with key X
|
// 7b. Remove annotation with key X
|
||||||
return cml.RemoveAnnotation(peer.PeerName)
|
return cml.RemoveAnnotation(KubePeersPrefix + peer.PeerName)
|
||||||
})
|
})
|
||||||
common.Log.Debugln("[kube-peers] Finished removal of ", peer.PeerName)
|
|
||||||
}
|
}
|
||||||
// 8. If step 5 failed due to optimistic lock conflict, stop: someone else is handling X
|
// 8. If step 5 failed due to optimistic lock conflict, stop: someone else is handling X
|
||||||
|
|
||||||
@@ -166,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
|
// 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?
|
// 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
|
// i.e. If peer X owns any address space and is marked unreachable, we want to rmpeer X
|
||||||
@@ -174,14 +182,16 @@ func reclaimRemovedPeers(weave *weaveapi.Client, cml *configMapAnnotations, node
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
justReclaim bool
|
justReclaim bool
|
||||||
justCheck bool
|
justCheck bool
|
||||||
peerName string
|
justSetNodeStatus bool
|
||||||
nodeName string
|
peerName string
|
||||||
logLevel string
|
nodeName string
|
||||||
|
logLevel string
|
||||||
)
|
)
|
||||||
flag.BoolVar(&justReclaim, "reclaim", false, "reclaim IP space from dead peers")
|
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(&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(&peerName, "peer-name", "unknown", "name of this Weave Net peer")
|
||||||
flag.StringVar(&nodeName, "node-name", "unknown", "name of this Kubernetes node")
|
flag.StringVar(&nodeName, "node-name", "unknown", "name of this Kubernetes node")
|
||||||
flag.StringVar(&logLevel, "log-level", "info", "logging level (debug, info, warning, error)")
|
flag.StringVar(&logLevel, "log-level", "info", "logging level (debug, info, warning, error)")
|
||||||
@@ -208,6 +218,13 @@ func main() {
|
|||||||
os.Exit(0)
|
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)
|
peers, err := getKubePeers(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Fatalf("[kube-peers] Could not get peers: %v", err)
|
common.Log.Fatalf("[kube-peers] Could not get peers: %v", err)
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -50,6 +50,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"env": [
|
"env": [
|
||||||
|
{
|
||||||
|
"description": "Log level",
|
||||||
|
"name": "LOG_LEVEL",
|
||||||
|
"settable": [
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Extra args to `weaver` and `plugin`",
|
"description": "Extra args to `weaver` and `plugin`",
|
||||||
"name": "EXTRA_ARGS",
|
"name": "EXTRA_ARGS",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ IPALLOC_RANGE=${IPALLOC_RANGE:-10.32.0.0/12}
|
|||||||
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
|
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
|
||||||
STATUS_ADDR=${WEAVE_STATUS_ADDR:-0.0.0.0:6782}
|
STATUS_ADDR=${WEAVE_STATUS_ADDR:-0.0.0.0:6782}
|
||||||
HOST_ROOT=${HOST_ROOT:-/host}
|
HOST_ROOT=${HOST_ROOT:-/host}
|
||||||
|
LOG_LEVEL=${LOG_LEVEL:-info}
|
||||||
WEAVE_DIR="/host/var/lib/weave"
|
WEAVE_DIR="/host/var/lib/weave"
|
||||||
|
|
||||||
mkdir $WEAVE_DIR || true
|
mkdir $WEAVE_DIR || true
|
||||||
@@ -44,7 +45,7 @@ exec /home/weave/weaver $EXTRA_ARGS --port=6783 $(router_bridge_opts) \
|
|||||||
--no-dns \
|
--no-dns \
|
||||||
--ipalloc-range=$IPALLOC_RANGE \
|
--ipalloc-range=$IPALLOC_RANGE \
|
||||||
--nickname "$(hostname)" \
|
--nickname "$(hostname)" \
|
||||||
--log-level=debug \
|
--log-level=$LOG_LEVEL \
|
||||||
--db-prefix="$WEAVE_DIR/weave" \
|
--db-prefix="$WEAVE_DIR/weave" \
|
||||||
--plugin-v2 \
|
--plugin-v2 \
|
||||||
$(multicast_opt) \
|
$(multicast_opt) \
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
FROM DOCKERHUB_USER/weaveARCH_EXT
|
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"]
|
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}"
|
||||||
@@ -27,9 +27,9 @@ xt_set_exists() {
|
|||||||
# Default if not supplied - same as weave net default
|
# Default if not supplied - same as weave net default
|
||||||
IPALLOC_RANGE=${IPALLOC_RANGE:-10.32.0.0/12}
|
IPALLOC_RANGE=${IPALLOC_RANGE:-10.32.0.0/12}
|
||||||
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
|
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}
|
HOST_ROOT=${HOST_ROOT:-/host}
|
||||||
CONN_LIMIT=${CONN_LIMIT:-30}
|
CONN_LIMIT=${CONN_LIMIT:-100}
|
||||||
DB_PREFIX=${DB_PREFIX:-/weavedb/weave-net}
|
DB_PREFIX=${DB_PREFIX:-/weavedb/weave-net}
|
||||||
|
|
||||||
# Check if the IP range overlaps anything existing on the host
|
# Check if the IP range overlaps anything existing on the host
|
||||||
@@ -54,12 +54,23 @@ else
|
|||||||
fi
|
fi
|
||||||
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
|
# Default is that npc will be running; allow caller to override
|
||||||
WEAVE_NPC_OPTS="--expect-npc"
|
WEAVE_NPC_OPTS="--expect-npc"
|
||||||
if [ "${EXPECT_NPC}" = "0" ]; then
|
if [ "${EXPECT_NPC}" = "0" ]; then
|
||||||
WEAVE_NPC_OPTS=""
|
WEAVE_NPC_OPTS=""
|
||||||
fi
|
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
|
# Kubernetes sets HOSTNAME to the host's hostname
|
||||||
# when running a pod in host namespace.
|
# when running a pod in host namespace.
|
||||||
NICKNAME_ARG=""
|
NICKNAME_ARG=""
|
||||||
@@ -74,7 +85,7 @@ router_bridge_opts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if [ -z "$KUBE_PEERS" ]; then
|
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
|
echo Failed to get peers >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -99,7 +110,7 @@ fi
|
|||||||
if [ -f ${DB_PREFIX}data.db ]; then
|
if [ -f ${DB_PREFIX}data.db ]; then
|
||||||
if /usr/bin/weaveutil get-db-flag "$DB_PREFIX" peer-reclaim >/dev/null ; 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 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
|
# In order to avoid a CRDT clash, clean up
|
||||||
echo "Peer not in list; removing persisted data" >&2
|
echo "Peer not in list; removing persisted data" >&2
|
||||||
rm -f ${DB_PREFIX}data.db
|
rm -f ${DB_PREFIX}data.db
|
||||||
@@ -133,10 +144,13 @@ post_start_actions() {
|
|||||||
/home/weave/weave --local setup-cni
|
/home/weave/weave --local setup-cni
|
||||||
|
|
||||||
# Attempt to run the reclaim process, but don't halt the script if it fails
|
# 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
|
# Expose the weave network so host processes can communicate with pods
|
||||||
/home/weave/weave --local expose $WEAVE_EXPOSE_IP
|
/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 &
|
post_start_actions &
|
||||||
@@ -144,11 +158,12 @@ post_start_actions &
|
|||||||
/home/weave/weaver $EXTRA_ARGS --port=6783 $(router_bridge_opts) \
|
/home/weave/weaver $EXTRA_ARGS --port=6783 $(router_bridge_opts) \
|
||||||
--name="$PEERNAME" \
|
--name="$PEERNAME" \
|
||||||
--host-root=$HOST_ROOT \
|
--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" \
|
--db-prefix="$DB_PREFIX" \
|
||||||
--ipalloc-range=$IPALLOC_RANGE $NICKNAME_ARG \
|
--ipalloc-range=$IPALLOC_RANGE $NICKNAME_ARG \
|
||||||
--ipalloc-init $IPALLOC_INIT \
|
--ipalloc-init $IPALLOC_INIT \
|
||||||
--conn-limit=$CONN_LIMIT \
|
--conn-limit=$CONN_LIMIT \
|
||||||
$WEAVE_NPC_OPTS \
|
$WEAVE_NPC_OPTS \
|
||||||
|
$NO_MASQ_LOCAL_OPT \
|
||||||
"$@" \
|
"$@" \
|
||||||
$KUBE_PEERS
|
$KUBE_PEERS
|
||||||
@@ -25,14 +25,6 @@ items:
|
|||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
- apiGroups:
|
|
||||||
- extensions
|
|
||||||
resources:
|
|
||||||
- networkpolicies
|
|
||||||
verbs:
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- 'networking.k8s.io'
|
- 'networking.k8s.io'
|
||||||
resources:
|
resources:
|
||||||
@@ -41,6 +33,13 @@ items:
|
|||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- ''
|
||||||
|
resources:
|
||||||
|
- nodes/status
|
||||||
|
verbs:
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
metadata:
|
metadata:
|
||||||
@@ -101,6 +100,8 @@ items:
|
|||||||
name: weave-net
|
name: weave-net
|
||||||
namespace: kube-system
|
namespace: kube-system
|
||||||
spec:
|
spec:
|
||||||
|
# Wait 5 seconds to let pod connect before rolling next pod
|
||||||
|
minReadySeconds: 5
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
@@ -154,7 +155,6 @@ items:
|
|||||||
fieldPath: spec.nodeName
|
fieldPath: spec.nodeName
|
||||||
image: 'weaveworks/weave-npc:latest'
|
image: 'weaveworks/weave-npc:latest'
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
#npc-args
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 10m
|
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
|
||||||
@@ -1,17 +1,24 @@
|
|||||||
FROM ALPINE_BASEIMAGE
|
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
|
# These labels are pretty static, and can therefore be added early on:
|
||||||
# If we're building normally, for amd64, CROSS_BUILD lines are removed
|
LABEL works.weave.role="system" \
|
||||||
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
|
maintainer="Weaveworks <help@weave.works>" \
|
||||||
|
org.opencontainers.image.title="Weave Net" \
|
||||||
LABEL maintainer "Weaveworks Inc <help@weave.works>"
|
org.opencontainers.image.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
|
||||||
LABEL works.weave.role=system \
|
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.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.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.url="https://weave.works" \
|
||||||
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
|
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
|
||||||
org.label-schema.vendor="Weaveworks"
|
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 \
|
RUN apk add --update \
|
||||||
iptables \
|
iptables \
|
||||||
ipset \
|
ipset \
|
||||||
@@ -21,3 +28,8 @@ RUN apk add --update \
|
|||||||
COPY ./weave-npc /usr/bin/weave-npc
|
COPY ./weave-npc /usr/bin/weave-npc
|
||||||
COPY ./ulogd.conf /etc/ulogd.conf
|
COPY ./ulogd.conf /etc/ulogd.conf
|
||||||
ENTRYPOINT ["/usr/bin/weave-npc"]
|
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
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
coreapi "k8s.io/api/core/v1"
|
coreapi "k8s.io/api/core/v1"
|
||||||
extnapi "k8s.io/api/extensions/v1beta1"
|
|
||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkingv1 "k8s.io/api/networking/v1"
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@@ -18,8 +17,9 @@ import (
|
|||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
|
|
||||||
"github.com/weaveworks/weave/common"
|
"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"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
|
||||||
"github.com/weaveworks/weave/npc/metrics"
|
"github.com/weaveworks/weave/npc/metrics"
|
||||||
"github.com/weaveworks/weave/npc/ulogd"
|
"github.com/weaveworks/weave/npc/ulogd"
|
||||||
)
|
)
|
||||||
@@ -30,7 +30,7 @@ var (
|
|||||||
logLevel string
|
logLevel string
|
||||||
allowMcast bool
|
allowMcast bool
|
||||||
nodeName string
|
nodeName string
|
||||||
legacy bool
|
maxList int
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleError(err error) { common.CheckFatal(err) }
|
func handleError(err error) { common.CheckFatal(err) }
|
||||||
@@ -52,11 +52,31 @@ func resetIPTables(ipt *iptables.IPTables) error {
|
|||||||
return err
|
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 {
|
func resetIPSets(ips ipset.Interface) error {
|
||||||
// Remove ipsets prefixed `weave-` only
|
// Remove ipsets prefixed `weave-` only.
|
||||||
|
|
||||||
sets, err := ips.List(npc.IpsetNamePrefix)
|
sets, err := ips.List(npc.IpsetNamePrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -76,6 +96,11 @@ func resetIPSets(ips ipset.Interface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range sets {
|
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))
|
common.Log.Debugf("Destroying ipset '%s'", string(s))
|
||||||
if err := ips.Destroy(s); err != nil {
|
if err := ips.Destroy(s); err != nil {
|
||||||
common.Log.Errorf("Failed to destroy ipset '%s'", string(s))
|
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 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 err
|
||||||
}
|
}
|
||||||
return ipt.Append(npc.TableFilter, npc.MainChain,
|
if !found {
|
||||||
"-m", "set", "!", "--match-set", npc.LocalIpset, "dst", "-j", "ACCEPT")
|
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) {
|
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)
|
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 {
|
if err := metrics.Start(metricsAddr); err != nil {
|
||||||
common.Log.Fatalf("Failed to start metrics: %v", err)
|
common.Log.Fatalf("Failed to start metrics: %v", err)
|
||||||
}
|
}
|
||||||
@@ -152,13 +243,13 @@ func root(cmd *cobra.Command, args []string) {
|
|||||||
ipt, err := iptables.New()
|
ipt, err := iptables.New()
|
||||||
handleError(err)
|
handleError(err)
|
||||||
|
|
||||||
ips := ipset.New(common.LogLogger())
|
ips := ipset.New(common.LogLogger(), maxList)
|
||||||
|
|
||||||
handleError(resetIPTables(ipt))
|
handleError(resetIPTables(ipt))
|
||||||
handleError(resetIPSets(ips))
|
handleError(resetIPSets(ips))
|
||||||
handleError(createBaseRules(ipt, 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{},
|
nsController := makeController(client.Core().RESTClient(), "namespaces", &coreapi.Namespace{},
|
||||||
cache.ResourceEventHandlerFuncs{
|
cache.ResourceEventHandlerFuncs{
|
||||||
@@ -219,11 +310,7 @@ func root(cmd *cobra.Command, args []string) {
|
|||||||
handleError(npc.UpdateNetworkPolicy(old, new))
|
handleError(npc.UpdateNetworkPolicy(old, new))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if legacy {
|
npController = makeController(client.NetworkingV1().RESTClient(), "networkpolicies", &networkingv1.NetworkPolicy{}, npHandlers)
|
||||||
npController = makeController(client.Extensions().RESTClient(), "networkpolicies", &extnapi.NetworkPolicy{}, npHandlers)
|
|
||||||
} else {
|
|
||||||
npController = makeController(client.NetworkingV1().RESTClient(), "networkpolicies", &networkingv1.NetworkPolicy{}, npHandlers)
|
|
||||||
}
|
|
||||||
|
|
||||||
go nsController.Run(wait.NeverStop)
|
go nsController.Run(wait.NeverStop)
|
||||||
go podController.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().StringVar(&logLevel, "log-level", "debug", "logging level (debug, info, warning, error)")
|
||||||
rootCmd.PersistentFlags().BoolVar(&allowMcast, "allow-mcast", true, "allow all multicast traffic")
|
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().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())
|
handleError(rootCmd.Execute())
|
||||||
}
|
}
|
||||||
+12
-2
@@ -1,7 +1,17 @@
|
|||||||
# This is a nearly-empty image that we use to create a data-only container for persistence
|
# This is a nearly-empty image that we use to create a data-only container for persistence
|
||||||
FROM scratch
|
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"]
|
ENTRYPOINT ["data-only"]
|
||||||
# Work round Docker refusing to save an empty image
|
# Work round Docker refusing to save an empty image
|
||||||
COPY Dockerfile /
|
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}"
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
FROM DOCKERHUB_USER/weaveARCH_EXT
|
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"]
|
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
|
||||||
|
|
||||||
ADD ./sigproxy ./symlink /home/weave/
|
ADD ./sigproxy ./symlink /home/weave/
|
||||||
@@ -7,3 +13,7 @@ ADD ./weavewait /w/w
|
|||||||
ADD ./weavewait_noop /w-noop/w
|
ADD ./weavewait_noop /w-noop/w
|
||||||
ADD ./weavewait_nomcast /w-nomcast/w
|
ADD ./weavewait_nomcast /w-nomcast/w
|
||||||
WORKDIR /home/weave
|
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}"
|
||||||
@@ -1,17 +1,24 @@
|
|||||||
FROM ALPINE_BASEIMAGE
|
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
|
# These labels are pretty static, and can therefore be added early on:
|
||||||
# If we're building normally, for amd64, CROSS_BUILD lines are removed
|
LABEL works.weave.role="system" \
|
||||||
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
|
maintainer="Weaveworks <help@weave.works>" \
|
||||||
|
org.opencontainers.image.title="Weave Net" \
|
||||||
LABEL maintainer "Weaveworks Inc <help@weave.works>"
|
org.opencontainers.image.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
|
||||||
LABEL works.weave.role=system \
|
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.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.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.url="https://weave.works" \
|
||||||
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
|
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
|
||||||
org.label-schema.vendor="Weaveworks"
|
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 \
|
RUN apk add --update \
|
||||||
curl \
|
curl \
|
||||||
ethtool \
|
ethtool \
|
||||||
@@ -21,11 +28,16 @@ RUN apk add --update \
|
|||||||
util-linux \
|
util-linux \
|
||||||
conntrack-tools \
|
conntrack-tools \
|
||||||
bind-tools \
|
bind-tools \
|
||||||
|
ca-certificates \
|
||||||
&& rm -rf /var/cache/apk/*
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
ADD ./weave ./weaver /home/weave/
|
ADD ./weave ./weaver /home/weave/
|
||||||
ADD ./weaveutil /usr/bin/
|
ADD ./weaveutil /usr/bin/
|
||||||
ADD weavedata.db /weavedb/
|
ADD weavedata.db /weavedb/
|
||||||
COPY ca-certificates.crt /etc/ssl/certs/
|
|
||||||
ENTRYPOINT ["/home/weave/weaver"]
|
ENTRYPOINT ["/home/weave/weaver"]
|
||||||
WORKDIR /home/weave
|
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
@@ -329,7 +329,7 @@ func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRout
|
|||||||
w.Write(json)
|
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) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
funcs := template.FuncMap{
|
funcs := template.FuncMap{
|
||||||
"json": func(v interface{}) string {
|
"json": func(v interface{}) string {
|
||||||
@@ -337,7 +337,12 @@ func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRout
|
|||||||
return string(a)
|
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 {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
|||||||
+43
-20
@@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/weaveworks/weave/nameserver"
|
"github.com/weaveworks/weave/nameserver"
|
||||||
weavenet "github.com/weaveworks/weave/net"
|
weavenet "github.com/weaveworks/weave/net"
|
||||||
"github.com/weaveworks/weave/net/address"
|
"github.com/weaveworks/weave/net/address"
|
||||||
|
"github.com/weaveworks/weave/net/ipset"
|
||||||
"github.com/weaveworks/weave/plugin"
|
"github.com/weaveworks/weave/plugin"
|
||||||
weaveproxy "github.com/weaveworks/weave/proxy"
|
weaveproxy "github.com/weaveworks/weave/proxy"
|
||||||
weave "github.com/weaveworks/weave/router"
|
weave "github.com/weaveworks/weave/router"
|
||||||
@@ -45,12 +46,20 @@ type ipamConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type dnsConfig struct {
|
type dnsConfig struct {
|
||||||
Domain string
|
Domain string
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
TTL int
|
TTL int
|
||||||
ClientTimeout time.Duration
|
ClientTimeout time.Duration
|
||||||
EffectiveListenAddress string
|
ResolvConf string
|
||||||
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 {
|
func (c *ipamConfig) Enabled() bool {
|
||||||
@@ -147,6 +156,7 @@ func main() {
|
|||||||
noDiscovery bool
|
noDiscovery bool
|
||||||
httpAddr string
|
httpAddr string
|
||||||
statusAddr string
|
statusAddr string
|
||||||
|
metricsAddr string
|
||||||
ipamConfig ipamConfig
|
ipamConfig ipamConfig
|
||||||
dockerAPI string
|
dockerAPI string
|
||||||
peers []string
|
peers []string
|
||||||
@@ -178,12 +188,13 @@ func main() {
|
|||||||
mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)")
|
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.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.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.BoolVar(&noDiscovery, []string{"-no-discovery"}, false, "disable peer discovery")
|
||||||
mflag.IntVar(&bufSzMB, []string{"-bufsz"}, 8, "capture buffer size in MB")
|
mflag.IntVar(&bufSzMB, []string{"-bufsz"}, 8, "capture buffer size in MB")
|
||||||
mflag.IntVar(&bridgeConfig.MTU, []string{"-mtu"}, 0, "MTU size")
|
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(&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(&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.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.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")
|
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.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.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.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(&dnsConfig.ResolvConf, []string{"-resolv-conf"}, "", "path to resolver configuration for fallback DNS lookups")
|
||||||
mflag.StringVar(&bridgeConfig.DatapathName, []string{"-datapath"}, "", "ODP datapath name")
|
mflag.StringVar(&bridgeConfig.DatapathName, []string{"-datapath"}, "", "ODP datapath name")
|
||||||
mflag.BoolVar(&bridgeConfig.NoFastdp, []string{"-no-fastdp"}, false, "Disable Fast Datapath")
|
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(&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(&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")
|
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.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.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.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()
|
proxyConfig := newProxyConfig()
|
||||||
|
|
||||||
@@ -263,6 +275,8 @@ func main() {
|
|||||||
var proxy *weaveproxy.Proxy
|
var proxy *weaveproxy.Proxy
|
||||||
var err error
|
var err error
|
||||||
if proxyConfig.Enabled {
|
if proxyConfig.Enabled {
|
||||||
|
proxyConfig.DNSListenAddress = dnsConfig.addressOnly()
|
||||||
|
proxyConfig.DNSDomain = dnsConfig.Domain
|
||||||
if noDNS {
|
if noDNS {
|
||||||
proxyConfig.WithoutDNS = true
|
proxyConfig.WithoutDNS = true
|
||||||
}
|
}
|
||||||
@@ -293,7 +307,8 @@ func main() {
|
|||||||
|
|
||||||
bridgeConfig.Mac = name.String()
|
bridgeConfig.Mac = name.String()
|
||||||
bridgeConfig.Port = config.Port
|
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)
|
checkFatal(err)
|
||||||
Log.Println("Bridge type is", bridgeType)
|
Log.Println("Bridge type is", bridgeType)
|
||||||
|
|
||||||
@@ -324,6 +339,9 @@ func main() {
|
|||||||
if bridgeConfig.AWSVPC && !ipamConfig.Enabled() {
|
if bridgeConfig.AWSVPC && !ipamConfig.Enabled() {
|
||||||
Log.Fatalf("--awsvpc mode requires IPAM 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)
|
db, err := db.NewBoltDB(dbPrefix)
|
||||||
checkFatal(err)
|
checkFatal(err)
|
||||||
@@ -383,17 +401,19 @@ func main() {
|
|||||||
var (
|
var (
|
||||||
allocator *ipam.Allocator
|
allocator *ipam.Allocator
|
||||||
defaultSubnet address.CIDR
|
defaultSubnet address.CIDR
|
||||||
trackerName string
|
|
||||||
)
|
)
|
||||||
if ipamConfig.Enabled() {
|
if ipamConfig.Enabled() {
|
||||||
var t tracker.LocalRangeTracker
|
var t tracker.LocalRangeTracker
|
||||||
if bridgeConfig.AWSVPC {
|
if bridgeConfig.AWSVPC {
|
||||||
Log.Infoln("Creating AWSVPC LocalRangeTracker")
|
|
||||||
t, err = tracker.NewAWSVPCTracker(bridgeConfig.WeaveBridgeName)
|
t, err = tracker.NewAWSVPCTracker(bridgeConfig.WeaveBridgeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Fatalf("Cannot create AWSVPC LocalRangeTracker: %s", err)
|
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)
|
preClaims, err := findExistingAddresses(dockerCli, bridgeConfig.WeaveBridgeName)
|
||||||
@@ -441,7 +461,7 @@ func main() {
|
|||||||
if httpAddr != "" {
|
if httpAddr != "" {
|
||||||
muxRouter := mux.NewRouter()
|
muxRouter := mux.NewRouter()
|
||||||
if allocator != nil {
|
if allocator != nil {
|
||||||
allocator.HandleHTTP(muxRouter, defaultSubnet, trackerName, dockerCli)
|
allocator.HandleHTTP(muxRouter, defaultSubnet, dockerCli)
|
||||||
}
|
}
|
||||||
if ns != nil {
|
if ns != nil {
|
||||||
ns.HandleHTTP(muxRouter, dockerCli)
|
ns.HandleHTTP(muxRouter, dockerCli)
|
||||||
@@ -464,10 +484,17 @@ func main() {
|
|||||||
muxRouter.Methods("GET").Path("/metrics").Handler(metricsHandler(router, allocator, ns, dnsserver))
|
muxRouter.Methods("GET").Path("/metrics").Handler(metricsHandler(router, allocator, ns, dnsserver))
|
||||||
statusMux := http.NewServeMux()
|
statusMux := http.NewServeMux()
|
||||||
statusMux.Handle("/", muxRouter)
|
statusMux.Handle("/", muxRouter)
|
||||||
Log.Println("Listening for metrics requests on", statusAddr)
|
Log.Println("Listening for status+metrics requests on", statusAddr)
|
||||||
go listenAndServeHTTP(statusAddr, statusMux)
|
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 {
|
if plugin != nil {
|
||||||
go plugin.Start(httpAddr, dockerCli, waitReady.Add())
|
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)
|
gossip, err := router.NewGossip("nameserver", ns)
|
||||||
checkFatal(err)
|
checkFatal(err)
|
||||||
ns.SetGossip(gossip)
|
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,
|
dnsserver, err := nameserver.NewDNSServer(ns, config.Domain, config.ListenAddress,
|
||||||
upstream, uint32(config.TTL), config.ClientTimeout)
|
upstream, uint32(config.TTL), config.ClientTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Fatal("Unable to start dns server: ", err)
|
Log.Fatal("Unable to start dns server: ", err)
|
||||||
}
|
}
|
||||||
listenAddr := config.ListenAddress
|
Log.Println("Listening for DNS queries on", config.ListenAddress)
|
||||||
if config.EffectiveListenAddress != "" {
|
|
||||||
listenAddr = config.EffectiveListenAddress
|
|
||||||
}
|
|
||||||
Log.Println("Listening for DNS queries on", listenAddr)
|
|
||||||
return ns, dnsserver
|
return ns, dnsserver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@@ -15,8 +14,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func attach(args []string) error {
|
func attach(args []string) error {
|
||||||
if len(args) < 4 {
|
if len(args) < 3 {
|
||||||
cmdUsage("attach-container", "[--no-multicast-route] [--keep-tx-on] [--hairpin-mode=true|false] <container-id> <bridge-name> <mtu> <cidr>...")
|
cmdUsage("attach-container", "[--no-multicast-route] [--keep-tx-on] [--hairpin-mode=true|false] <container-id> <bridge-name> <cidr>...")
|
||||||
}
|
}
|
||||||
|
|
||||||
keepTXOn := false
|
keepTXOn := false
|
||||||
@@ -52,16 +51,12 @@ func attach(args []string) error {
|
|||||||
} else if nsHost.Equal(nsContainer) {
|
} 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")
|
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])
|
cidrs, err := parseCIDRs(args[2:])
|
||||||
if err != nil && args[3] != "" {
|
|
||||||
return fmt.Errorf("unable to parse mtu %q: %s", args[2], err)
|
|
||||||
}
|
|
||||||
cidrs, err := parseCIDRs(args[3:])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 we detected an error but the container has died, tell the user that instead.
|
||||||
if err != nil && !processExists(pid) {
|
if err != nil && !processExists(pid) {
|
||||||
err = fmt.Errorf("Container %s died", args[0])
|
err = fmt.Errorf("Container %s died", args[0])
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/weaveworks/weave/common"
|
|
||||||
weavenet "github.com/weaveworks/weave/net"
|
weavenet "github.com/weaveworks/weave/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,36 +20,3 @@ func detectBridgeType(args []string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
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
|
|
||||||
}
|
|
||||||
@@ -4,10 +4,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
weavenet "github.com/weaveworks/weave/net"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var commands map[string]func([]string) error
|
var commands map[string]func([]string) error
|
||||||
@@ -17,7 +14,6 @@ func init() {
|
|||||||
"help": help,
|
"help": help,
|
||||||
"netcheck": netcheck,
|
"netcheck": netcheck,
|
||||||
"docker-tls-args": dockerTLSArgs,
|
"docker-tls-args": dockerTLSArgs,
|
||||||
"create-bridge": createBridge,
|
|
||||||
"detect-bridge-type": detectBridgeType,
|
"detect-bridge-type": detectBridgeType,
|
||||||
"create-datapath": createDatapath,
|
"create-datapath": createDatapath,
|
||||||
"delete-datapath": deleteDatapath,
|
"delete-datapath": deleteDatapath,
|
||||||
@@ -37,12 +33,6 @@ func init() {
|
|||||||
"create-volume-container": createVolumeContainer,
|
"create-volume-container": createVolumeContainer,
|
||||||
"attach-container": attach,
|
"attach-container": attach,
|
||||||
"detach-container": detach,
|
"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-net": cniNet,
|
||||||
"cni-ipam": cniIPAM,
|
"cni-ipam": cniIPAM,
|
||||||
"bridge-ip": bridgeIP,
|
"bridge-ip": bridgeIP,
|
||||||
@@ -56,14 +46,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
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
|
// If no args passed, act as CNI plugin based on executable name
|
||||||
switch {
|
switch {
|
||||||
case len(os.Args) == 1 && strings.HasSuffix(os.Args[0], "weave-ipam"):
|
case len(os.Args) == 1 && strings.HasSuffix(os.Args[0], "weave-ipam"):
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
docker "github.com/fsouza/go-dockerclient"
|
docker "github.com/fsouza/go-dockerclient"
|
||||||
)
|
)
|
||||||
@@ -58,7 +59,7 @@ func isDockerPluginEnabled(args []string) error {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
plugins, err := c.PluginList(ctx)
|
plugins, err := c.PluginList(ctx, filters.Args{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,11 +68,11 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
|
if !i.proxy.WithoutDNS {
|
||||||
if err := i.setHostname(container, hostname, dnsDomain); err != nil {
|
if err := i.setHostname(container, hostname, i.proxy.DNSDomain); err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-19
@@ -61,6 +61,8 @@ type Config struct {
|
|||||||
NoRewriteHosts bool
|
NoRewriteHosts bool
|
||||||
TLSConfig TLSConfig
|
TLSConfig TLSConfig
|
||||||
WithoutDNS bool
|
WithoutDNS bool
|
||||||
|
DNSListenAddress string
|
||||||
|
DNSDomain string
|
||||||
NoMulticastRoute bool
|
NoMulticastRoute bool
|
||||||
KeepTXOn bool
|
KeepTXOn bool
|
||||||
DockerBridge string
|
DockerBridge string
|
||||||
@@ -78,7 +80,6 @@ type Proxy struct {
|
|||||||
Config
|
Config
|
||||||
client *weavedocker.Client
|
client *weavedocker.Client
|
||||||
weave *weaveapi.Client
|
weave *weaveapi.Client
|
||||||
dockerBridgeIP string
|
|
||||||
hostnameMatchRegexp *regexp.Regexp
|
hostnameMatchRegexp *regexp.Regexp
|
||||||
weaveWaitVolume string
|
weaveWaitVolume string
|
||||||
weaveWaitNoopVolume string
|
weaveWaitNoopVolume string
|
||||||
@@ -158,15 +159,6 @@ func NewProxy(c Config) (*Proxy, error) {
|
|||||||
|
|
||||||
Log.Info(p.client.Info())
|
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)
|
p.hostnameMatchRegexp, err = regexp.Compile(c.HostnameMatch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Incorrect hostname match '%s': %s", c.HostnameMatch, err.Error())
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hostConfig["Dns"] = append(dns, proxy.dockerBridgeIP)
|
hostConfig["Dns"] = append(dns, proxy.DNSListenAddress)
|
||||||
|
|
||||||
dnsSearch, err := hostConfig.StringArray("DnsSearch")
|
dnsSearch, err := hostConfig.StringArray("DnsSearch")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -612,14 +604,6 @@ func (proxy *Proxy) setWeaveDNS(hostConfig jsonObject, hostname, dnsDomain strin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (proxy *Proxy) getDNSDomain() string {
|
|
||||||
if proxy.WithoutDNS {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
domain, _ := proxy.weave.DNSDomain()
|
|
||||||
return domain
|
|
||||||
}
|
|
||||||
|
|
||||||
func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error {
|
func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error {
|
||||||
containerID, err := container.String("Id")
|
containerID, err := container.String("Id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
|
if !i.proxy.WithoutDNS {
|
||||||
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, dnsDomain); err != nil {
|
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, i.proxy.DNSDomain); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func NewNetworkRouter(config mesh.Config, networkConfig NetworkConfig, bridgeCon
|
|||||||
router.Routes.OnChange(overlay.InvalidateRoutes)
|
router.Routes.OnChange(overlay.InvalidateRoutes)
|
||||||
router.Macs = NewMacCache(macMaxAge,
|
router.Macs = NewMacCache(macMaxAge,
|
||||||
func(mac net.HardwareAddr, peer *mesh.Peer) {
|
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) })
|
router.Peers.OnGC(func(peer *mesh.Peer) { router.Macs.Delete(peer) })
|
||||||
return router, nil
|
return router, nil
|
||||||
@@ -92,7 +92,7 @@ func (router *NetworkRouter) handleCapturedPacket(key PacketKey) FlowOp {
|
|||||||
|
|
||||||
switch newSrcMac, conflictPeer := router.Macs.Add(srcMac, router.Ourself.Peer); {
|
switch newSrcMac, conflictPeer := router.Macs.Add(srcMac, router.Ourself.Peer); {
|
||||||
case newSrcMac:
|
case newSrcMac:
|
||||||
log.Println("Discovered local MAC", srcMac)
|
log.Debugln("Discovered local MAC", srcMac)
|
||||||
case conflictPeer != nil:
|
case conflictPeer != nil:
|
||||||
// The MAC cache has an entry for the source MAC
|
// The MAC cache has an entry for the source MAC
|
||||||
// associated with another peer. This probably means
|
// associated with another peer. This probably means
|
||||||
|
|||||||
+17
-15
@@ -6,27 +6,28 @@ search_type: Documentation
|
|||||||
You only need to build Weave Net if you want to work on the Weave Net codebase
|
You only need to build Weave Net if you want to work on the Weave Net codebase
|
||||||
(or you just enjoy building software).
|
(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
|
container images. There is no distribution-specific packaging, so in
|
||||||
principle it shouldn't matter which Linux distribution you build
|
principle it shouldn't matter which Linux distribution you build
|
||||||
under. But naturally, Docker is a prerequisite (version 1.6.0 or
|
under. But naturally, Docker is a prerequisite (version 1.6.0 or
|
||||||
later).
|
later).
|
||||||
|
|
||||||
The only way to build is by using the the build container; the
|
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
|
documented below, and can be run directly on your machine or using
|
||||||
a Vagrant VM.
|
a Vagrant VM.
|
||||||
|
|
||||||
## <a name="ubuntu"></a>Building directly on your machine
|
## <a name="ubuntu"></a>Building directly on your machine
|
||||||
|
|
||||||
The weave git repository should be cloned into
|
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):
|
workspace conventions](https://golang.org/doc/code.html#Workspaces):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ WEAVE=github.com/weaveworks/weave
|
$ WEAVE=github.com/weaveworks/weave
|
||||||
$ git clone https://$WEAVE $GOPATH/src/$WEAVE
|
$ git clone https://$WEAVE $GOPATH/src/$WEAVE
|
||||||
$ cd $GOPATH/src/$WEAVE
|
$ cd $GOPATH/src/$WEAVE
|
||||||
|
$ git submodule update --init
|
||||||
```
|
```
|
||||||
|
|
||||||
Next install Docker if you haven't already, by following the instructions
|
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
|
- build the weave components in the build container
|
||||||
- package them into two Docker images (`weaveworks/weave`,
|
- package them into two Docker images (`weaveworks/weave`,
|
||||||
`weaveworks/weaveexec`)
|
`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
|
The first two steps may take a while - don't worry, they are
|
||||||
are cached and should not need to be redone very often.
|
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
|
$ git clone https://github.com/weaveworks/weave
|
||||||
$ cd 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
|
* Docker installed
|
||||||
* go tools installed
|
* Go tools installed
|
||||||
* weave dependencies installed
|
* Weave's dependencies installed
|
||||||
* $GOPATH set to ~
|
* `$GOPATH` set to `~`
|
||||||
* the local working directory mapped as a synced folder into the
|
* 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
|
$ 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.
|
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
|
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
|
$ vagrant ssh
|
||||||
@@ -94,7 +96,7 @@ vm$ cd src/github.com/weaveworks/weave
|
|||||||
vm$ make
|
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
|
vm$ sudo ./weave launch
|
||||||
@@ -104,7 +106,7 @@ vm$ sudo docker ps
|
|||||||
and so on.
|
and so on.
|
||||||
|
|
||||||
If you are looking to just do a build and not run anything on this VM,
|
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'
|
$ 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
|
you should then find a `weave.tar.gz` container snapshot tarball in the
|
||||||
top-level directory. You can use that snapshot with `docker load`
|
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>
|
$ export DOCKER_HOST=tcp://<HOST:PORT>
|
||||||
|
|||||||
+14
-1
@@ -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).
|
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>
|
<a name="duplicate-ip"></a>
|
||||||
**Q: Why am I seeing the same IP address assigned to two different containers on different hosts?**
|
**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,
|
You must permit traffic to flow through TCP 6783 and UDP 6783/6784,
|
||||||
which are Weave’s control and data ports.
|
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
|
you would only need to open up this port if you wish to collect metrics
|
||||||
from another host.
|
from another host.
|
||||||
|
|
||||||
|
|||||||
@@ -7,19 +7,26 @@ search_type: Documentation
|
|||||||
The following topics are discussed:
|
The following topics are discussed:
|
||||||
|
|
||||||
* [Installation](#install)
|
* [Installation](#install)
|
||||||
* [Upgrading Kubernetes to version 1.6](#kube-1.6-upgrade)
|
* [Upgrading Kubernetes to version 1.6](#kube-1.6-upgrade)
|
||||||
* [Upgrading the Daemon Sets](#daemon-sets)
|
* [Upgrading the Daemon Sets](#daemon-sets)
|
||||||
* [CPU and Memory Requirements](#resources)
|
* [CPU and Memory Requirements](#resources)
|
||||||
* [Pod Eviction](#eviction)
|
* [Pod Eviction](#eviction)
|
||||||
* [Network Policy Controller](#npc)
|
* [Features](#features)
|
||||||
|
* [Pod Network](#pod-network)
|
||||||
|
* [Network Policy](#npc)
|
||||||
* [Troubleshooting](#troubleshooting)
|
* [Troubleshooting](#troubleshooting)
|
||||||
* [Troubleshooting Blocked Connections](#blocked-connections)
|
* [Reading the logs](#logs)
|
||||||
* [Things to watch out for](#key-points)
|
* [Troubleshooting Blocked Connections](#blocked-connections)
|
||||||
|
* [Things to watch out for](#key-points)
|
||||||
* [Changing Configuration Options](#configuration-options)
|
* [Changing Configuration Options](#configuration-options)
|
||||||
|
|
||||||
|
|
||||||
## <a name="install"></a> Installation
|
## <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
|
Weave Net can be installed onto your CNI-enabled Kubernetes cluster
|
||||||
with a single command:
|
with a single command:
|
||||||
|
|
||||||
@@ -147,16 +154,33 @@ mypod-09vkd 0/1 Evicted 0 1h <none> node-1
|
|||||||
If you see this in your cluster, consider some of the above steps to
|
If you see this in your cluster, consider some of the above steps to
|
||||||
reduce disruption.
|
reduce disruption.
|
||||||
|
|
||||||
## <a name="npc"></a>Network Policy Controller
|
## <a name="features"></a>Features
|
||||||
|
|
||||||
The addon also supports the [Kubernetes policy
|
### <a name="pod-network"></a>Pod Network
|
||||||
API](http://kubernetes.io/docs/user-guide/networkpolicies/) so that
|
|
||||||
you can securely isolate pods from each other based on namespaces and
|
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
|
labels. For more information on configuring network policies in
|
||||||
Kubernetes see the
|
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
|
and the [NetworkPolicy API object
|
||||||
definition](http://kubernetes.io/docs/api-reference/extensions/v1beta1/definitions/#_v1beta1_networkpolicy).
|
definition](https://v1-7.docs.kubernetes.io/docs/api-reference/v1.7/#networkpolicy-v1-networking)
|
||||||
|
|
||||||
**Note:** as of version 1.9 of Weave Net, the Network Policy
|
**Note:** as of version 1.9 of Weave Net, the Network Policy
|
||||||
Controller allows all multicast traffic. Since a single multicast
|
Controller allows all multicast traffic. Since a single multicast
|
||||||
@@ -167,7 +191,46 @@ definition](http://kubernetes.io/docs/api-reference/extensions/v1beta1/definitio
|
|||||||
|
|
||||||
## <a name="troubleshooting"></a> Troubleshooting
|
## <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:
|
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
|
impossible to correctly enforce network policies that restrict which
|
||||||
pods can talk.
|
pods can talk.
|
||||||
- If you do set the `--cluster-cidr` option on kube-proxy, make sure
|
- 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
|
## <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:
|
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`.
|
- `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:
|
Example:
|
||||||
|
|
||||||
$ echo "s3cr3tp4ssw0rd" > /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.txt
|
$ 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"
|
$ 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.
|
- `known-peers`: comma-separated list of hosts. Default: empty.
|
||||||
@@ -304,6 +375,8 @@ The list of variables you can set is:
|
|||||||
|
|
||||||
* `CHECKPOINT_DISABLE` - if set to 1, disable checking for new Weave Net
|
* `CHECKPOINT_DISABLE` - if set to 1, disable checking for new Weave Net
|
||||||
versions (default is blank, i.e. check is enabled)
|
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
|
* `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
|
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
|
kernel is one of those that can panic if hairpin is enabled, then you can disable it
|
||||||
@@ -319,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_EXPOSE_IP` - set the IP address used as a gateway from the
|
||||||
Weave network to the host network - this is useful if you are
|
Weave network to the host network - this is useful if you are
|
||||||
configuring the addon as a static pod.
|
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
|
* `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
|
smaller size if your underlying network has a tighter limit, or set
|
||||||
a larger size for better performance if your network supports jumbo
|
a larger size for better performance if your network supports jumbo
|
||||||
frames - see [here](/site/tasks/manage/fastdp.md#mtu) for more
|
frames - see [here](/site/tasks/manage/fastdp.md#mtu) for more
|
||||||
details.
|
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:
|
Example:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ peers and their reachability can be obtained with
|
|||||||
|
|
||||||
```
|
```
|
||||||
$ weave status ipam
|
$ 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:02(two) 349525 IPs (33.3% of total)
|
||||||
00:00:00:00:00:03(three) 349525 IPs (33.3% of total) - unreachable!
|
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
|
* Peer Name and Nickname
|
||||||
* Absolute quantity/percentage of allocation range managed by peer
|
* 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
|
* Indication of unreachability. This means that the peer is not
|
||||||
visible (directly or indirectly) to the peer on which `weave status
|
visible (directly or indirectly) to the peer on which `weave status
|
||||||
ipam` was run; whilst this could be a transient condition due to a
|
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
|
partition, it may be because the peer has failed and needs to be
|
||||||
removed administratively - see [Starting, Stopping and Removing
|
removed administratively - see [Starting, Stopping and Removing
|
||||||
Peers](/site/tasks/ipam/stop-remove-peers-ipam.md) for more details.
|
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.
|
||||||
@@ -10,9 +10,6 @@ controller](/site/kubernetes/kube-addon.md#npc).
|
|||||||
|
|
||||||
### Router Metrics
|
### Router Metrics
|
||||||
|
|
||||||
The endpoint address is `localhost:6782`; the following metrics are
|
|
||||||
exposed:
|
|
||||||
|
|
||||||
* `weave_connections` - Number of peer-to-peer connections.
|
* `weave_connections` - Number of peer-to-peer connections.
|
||||||
* `weave_connection_terminations_total` - Number of peer-to-peer
|
* `weave_connection_terminations_total` - Number of peer-to-peer
|
||||||
connections terminated.
|
connections terminated.
|
||||||
@@ -25,27 +22,35 @@ exposed:
|
|||||||
* `weave_ipam_pending_allocates` - Number of pending allocates.
|
* `weave_ipam_pending_allocates` - Number of pending allocates.
|
||||||
* `weave_ipam_pending_claims` - Number of pending claims.
|
* `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
|
### Kubernetes Network Policy Controller Metrics
|
||||||
|
|
||||||
The endpoint address is `localhost:6781`; the following metric is
|
The following metric is
|
||||||
exposed:
|
exposed:
|
||||||
|
|
||||||
* `weavenpc_blocked_connections_total` - Connection attempts blocked
|
* `weavenpc_blocked_connections_total` - Connection attempts blocked
|
||||||
by policy controller.
|
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
|
# Static Configuration for Weave Net
|
||||||
|
|
||||||
The following YAML fragment can be used in your Prometheus configuration to
|
The following YAML fragment can be used in your Prometheus configuration to
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ To disable an application container's use of weaveDNS, add the
|
|||||||
`--without-dns` option to `weave launch`. To
|
`--without-dns` option to `weave launch`. To
|
||||||
disable weaveDNS itself, launch weave with the `--no-dns` option.
|
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**
|
**See Also**
|
||||||
|
|
||||||
* [Integrating Docker via the API Proxy](/site/tasks/weave-docker-api/weave-docker-api.md)
|
* [Integrating Docker via the API Proxy](/site/tasks/weave-docker-api/weave-docker-api.md)
|
||||||
|
|||||||
@@ -157,6 +157,9 @@ The columns are as follows:
|
|||||||
the encryption mode, data transport method, remote peer name and
|
the encryption mode, data transport method, remote peer name and
|
||||||
nickname for pending and established connections, mtu if known
|
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
|
### <a name="weave-status-peers"></a>List Peers
|
||||||
|
|
||||||
Detailed information on peers can be obtained with `weave status
|
Detailed information on peers can be obtained with `weave status
|
||||||
@@ -329,5 +332,6 @@ and the container image versions as git hashes.
|
|||||||
|
|
||||||
**See Also**
|
**See Also**
|
||||||
|
|
||||||
|
* [Troubleshooting the Kubernetes Addon](/site/kubernetes/kube-addon/#troubleshooting)
|
||||||
* [Troubleshooting IPAM](/site/tasks/ipam/troubleshooting-ipam.md)
|
* [Troubleshooting IPAM](/site/tasks/ipam/troubleshooting-ipam.md)
|
||||||
* [Troubleshooting the Proxy](/site/tasks/weave-docker-api/using-proxy.md)
|
* [Troubleshooting the Proxy](/site/tasks/weave-docker-api/using-proxy.md)
|
||||||
Executable
+59
@@ -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
|
||||||
@@ -21,7 +21,7 @@ start_container_local_plugin $HOST1 --name=c3
|
|||||||
|
|
||||||
assert "show_multicast_route_on $HOST1 c1"
|
assert "show_multicast_route_on $HOST1 c1"
|
||||||
assert "show_multicast_route_on $HOST1 c2"
|
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
|
# Now try via docker network options
|
||||||
# using ssh rather than docker -H because CircleCI docker client is older
|
# 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"
|
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 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
|
$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
|
# Ensure current proxy options are obeyed on container start
|
||||||
docker_on $HOST1 stop -t 1 c2
|
docker_on $HOST1 stop -t 1 c2
|
||||||
@@ -39,7 +39,7 @@ weave_on $HOST1 launch
|
|||||||
|
|
||||||
proxy docker_on $HOST1 start c2
|
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
|
docker_on $HOST1 rm -f c3 c4 c5
|
||||||
$SSH $HOST1 docker network rm testmcasttrue testmcastfalse
|
$SSH $HOST1 docker network rm testmcasttrue testmcastfalse
|
||||||
|
|||||||
+155
-25
@@ -4,7 +4,11 @@
|
|||||||
|
|
||||||
tear_down_kubeadm() {
|
tear_down_kubeadm() {
|
||||||
for host in $HOSTS; do
|
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
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,6 +22,7 @@ NUM_HOSTS=$(howmany $HOSTS)
|
|||||||
SUCCESS="$(( $NUM_HOSTS * ($NUM_HOSTS-1) )) established"
|
SUCCESS="$(( $NUM_HOSTS * ($NUM_HOSTS-1) )) established"
|
||||||
KUBECTL="sudo kubectl --kubeconfig /etc/kubernetes/admin.conf"
|
KUBECTL="sudo kubectl --kubeconfig /etc/kubernetes/admin.conf"
|
||||||
KUBE_PORT=6443
|
KUBE_PORT=6443
|
||||||
|
WEAVE_NETWORK=10.32.0.0/12
|
||||||
IMAGE=weaveworks/network-tester:latest
|
IMAGE=weaveworks/network-tester:latest
|
||||||
DOMAIN=nettest.default.svc.cluster.local.
|
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:
|
# 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="$(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
|
for host in $HOSTS; do
|
||||||
if [ $host = $HOST1 ] ; then
|
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
|
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
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -n "$COVERAGE" ]; then
|
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
|
else
|
||||||
COVERAGE_ARGS="env:"
|
WEAVE_ENV_VARS="env:"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure Kubernetes uses locally built container images and inject code coverage environment variable (or do nothing depending on $COVERAGE):
|
# 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%" \
|
sed -e "s%imagePullPolicy: Always%imagePullPolicy: Never%" \
|
||||||
-e "s%env:%$COVERAGE_ARGS%" \
|
-e "s%env:%$WEAVE_ENV_VARS%" \
|
||||||
-e "s%#npc-args% args:\n - '--use-legacy-netpol'%" \
|
"$(dirname "$0")/../prog/weave-kube/weave-daemonset-k8s-1.8.yaml" | run_on "$HOST1" "$KUBECTL apply -n kube-system -f -"
|
||||||
"$(dirname "$0")/../prog/weave-kube/weave-daemonset-k8s-1.7.yaml" | run_on "$HOST1" "$KUBECTL apply -n kube-system -f -"
|
|
||||||
|
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ check_connections() {
|
|||||||
|
|
||||||
assert_raises 'wait_for_x check_connections "connections to establish"'
|
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)
|
HOST1EXPIP=$($SSH $HOST1 "weave expose" || true)
|
||||||
HOST2EXPIP=$($SSH $HOST2 "weave expose" || true)
|
HOST2EXPIP=$($SSH $HOST2 "weave expose" || true)
|
||||||
HOST3EXPIP=$($SSH $HOST3 "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 $HOST2 ps aux | grep -c '[d]efunct'" "0"
|
||||||
assert "run_on $HOST3 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
|
# Set up simple network policies 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\"}}'"
|
|
||||||
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
|
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
|
kind: NetworkPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: test840
|
name: test840
|
||||||
@@ -98,7 +110,7 @@ EOF
|
|||||||
|
|
||||||
# Another policy, this time with no 'from' section, just to check that doesn't cause a crash
|
# Another policy, this time with no 'from' section, just to check that doesn't cause a crash
|
||||||
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
|
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
|
||||||
apiVersion: extensions/v1beta1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: test840f
|
name: test840f
|
||||||
@@ -134,6 +146,22 @@ spec:
|
|||||||
run: nettest
|
run: nettest
|
||||||
EOF
|
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}}'")
|
podName=$($SSH $HOST1 "$KUBECTL get pods -l run=nettest -o go-template='{{(index .items 0).metadata.name}}'")
|
||||||
|
|
||||||
check_all_pods_communicate() {
|
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}}'")
|
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"
|
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
|
# check access via virtual IP
|
||||||
$SSH $HOST1 "$KUBECTL delete ds weave-net -n=kube-system"
|
VIRTUAL_IP=$($SSH $HOST1 $KUBECTL get service netvirt -o template --template={{.spec.clusterIP}})
|
||||||
sed -e "s%imagePullPolicy: Always%imagePullPolicy: Never%" \
|
assert_raises "$SSH $HOST1 $KUBECTL exec $podName -- curl -s -S -f -m 2 http://$VIRTUAL_IP/status >/dev/null"
|
||||||
-e "s%env:%$COVERAGE_ARGS%" \
|
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$VIRTUAL_IP/status >/dev/null"
|
||||||
"$(dirname "$0")/../prog/weave-kube/weave-daemonset-k8s-1.7.yaml" | run_on "$HOST1" "$KUBECTL apply -n kube-system -f -"
|
|
||||||
|
|
||||||
assert_raises 'wait_for_x check_all_pods_communicate pods'
|
# 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"
|
||||||
# nettest-deny should still not be able to reach nettest pods
|
assert_raises "! $SSH $HOST1 curl -s -S -f -m 2 http://$HOST2:31138/status >/dev/null"
|
||||||
assert_raises "! $SSH $HOST1 $KUBECTL exec $denyPodName -- curl -s -S -f -m 2 http://$DOMAIN:8080/status >/dev/null"
|
|
||||||
|
|
||||||
# allow access for nettest-deny
|
# allow access for nettest-deny
|
||||||
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
|
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
|
# 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"
|
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
|
run_on $HOST1 "$KUBECTL apply -f -" <<EOF
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
metadata:
|
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
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
podSelector: {}
|
podSelector: {}
|
||||||
@@ -209,8 +262,85 @@ spec:
|
|||||||
- {}
|
- {}
|
||||||
EOF
|
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"
|
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
|
tear_down_kubeadm
|
||||||
|
|
||||||
# Destroy our test ipset, and implicitly check it is still there
|
# Destroy our test ipset, and implicitly check it is still there
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ fi
|
|||||||
function teardown_kubernetes_cluster {
|
function teardown_kubernetes_cluster {
|
||||||
greyly echo "Tearing down kubernetes cluster"
|
greyly echo "Tearing down kubernetes cluster"
|
||||||
for host in $HOSTS; do
|
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
|
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:
|
# 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="$(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
|
for host in $HOSTS; do
|
||||||
if [ $host = $HOST1 ] ; then
|
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
|
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
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
+79
-1
@@ -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
|
> **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:
|
**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):
|
1. Start the build virtual machine (see above article for more details):
|
||||||
|
|
||||||
|
```
|
||||||
vagrant up
|
vagrant up
|
||||||
|
```
|
||||||
|
|
||||||
2. Start the three testing VMs:
|
2. Start the three testing VMs:
|
||||||
|
|
||||||
|
```
|
||||||
cd test
|
cd test
|
||||||
vagrant up
|
vagrant up
|
||||||
|
```
|
||||||
|
|
||||||
3. SSH into the build VM and go to Weave Net's sources:
|
3. SSH into the build VM and go to Weave Net's sources:
|
||||||
|
|
||||||
|
```
|
||||||
cd ..
|
cd ..
|
||||||
vagrant ssh
|
vagrant ssh
|
||||||
# you are now on the build VM:
|
# you are now on the build VM:
|
||||||
cd ~/weave
|
cd ~/weave
|
||||||
|
```
|
||||||
|
|
||||||
4. Compile all code and dependencies:
|
4. Compile all code and dependencies:
|
||||||
|
|
||||||
|
```
|
||||||
make
|
make
|
||||||
make testrunner
|
make testrunner
|
||||||
cd test
|
cd test
|
||||||
|
```
|
||||||
|
|
||||||
5. Upload the weave images from where the `Makefile` puts them (`weave.tar.gz`) to
|
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:
|
the three docker hosts, `docker load` these, and copies the `weave` script over:
|
||||||
|
|
||||||
|
```
|
||||||
./setup.sh
|
./setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
6. Run individual tests, e.g.:
|
6. Run individual tests, e.g.:
|
||||||
|
|
||||||
|
```
|
||||||
./200_dns_test.sh
|
./200_dns_test.sh
|
||||||
|
```
|
||||||
|
|
||||||
or run all tests (everything named `*_test.sh`):
|
or run all tests (everything named `*_test.sh`):
|
||||||
|
|
||||||
|
```
|
||||||
./run_all.sh
|
./run_all.sh
|
||||||
|
```
|
||||||
|
|
||||||
7. Stop all VMs:
|
7. Stop all VMs:
|
||||||
|
|
||||||
|
```
|
||||||
exit
|
exit
|
||||||
# you are now on your host machine
|
# you are now on your host machine
|
||||||
vagrant destroy -f
|
vagrant destroy -f
|
||||||
cd test
|
cd test
|
||||||
vagrant destroy -f
|
vagrant destroy -f
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Using other VMs
|
## 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.
|
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.
|
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.
|
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
|
||||||
|
```
|
||||||
Vendored
+1
-1
@@ -25,7 +25,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||||||
config.vm.define hostname do |host|
|
config.vm.define hostname do |host|
|
||||||
host.vm.provider :virtualbox do |vb|
|
host.vm.provider :virtualbox do |vb|
|
||||||
vb.name = hostname
|
vb.name = hostname
|
||||||
vb.memory = 384
|
vb.memory = 2048
|
||||||
configure_nat_dns(vb)
|
configure_nat_dns(vb)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM bash
|
FROM bash
|
||||||
RUN apk add --no-cache curl
|
RUN apk add --no-cache curl bind-tools
|
||||||
ADD webserver webserver
|
ADD webserver webserver
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
ENTRYPOINT ["/webserver"]
|
ENTRYPOINT ["/webserver"]
|
||||||
@@ -13,6 +13,8 @@
|
|||||||
// Visit /status to see pass/running/fail determination. (literally, it will
|
// Visit /status to see pass/running/fail determination. (literally, it will
|
||||||
// return one of those words.)
|
// 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.
|
// /write is used by other network test servers to register connectivity.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -78,6 +80,20 @@ func (s *State) serveStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprintf(w, "fail")
|
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
|
// serveRead writes our json encoded state
|
||||||
func (s *State) serveRead(w http.ResponseWriter, r *http.Request) {
|
func (s *State) serveRead(w http.ResponseWriter, r *http.Request) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
@@ -186,6 +202,7 @@ func main() {
|
|||||||
http.HandleFunc("/read", state.serveRead)
|
http.HandleFunc("/read", state.serveRead)
|
||||||
http.HandleFunc("/write", state.serveWrite)
|
http.HandleFunc("/write", state.serveWrite)
|
||||||
http.HandleFunc("/status", state.serveStatus)
|
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))
|
go log.Fatal(http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", *port), nil))
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -23,4 +23,4 @@ if [ -n "$CIRCLECI" -o -n "$PARALLEL" ]; then
|
|||||||
RUNNER_ARGS="$RUNNER_ARGS -parallel"
|
RUNNER_ARGS="$RUNNER_ARGS -parallel"
|
||||||
fi
|
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
@@ -41,15 +41,15 @@ func main() {
|
|||||||
log.Fatalf("The client key already exists. Please remove it or specify a different key/cert.")
|
log.Fatalf("The client key already exists. Please remove it or specify a different key/cert.")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cert.GenerateCert(
|
err = cert.GenerateCert(&cert.Options{
|
||||||
[]string{""},
|
Hosts: []string{""},
|
||||||
clientCertPath,
|
CertFile: clientCertPath,
|
||||||
clientKeyPath,
|
KeyFile: clientKeyPath,
|
||||||
caCertPath,
|
CAFile: caCertPath,
|
||||||
caKeyPath,
|
CAKeyFile: caKeyPath,
|
||||||
org,
|
Org: org,
|
||||||
bits,
|
Bits: bits,
|
||||||
)
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error generating client certificate: %s", err)
|
log.Fatalf("Error generating client certificate: %s", err)
|
||||||
}
|
}
|
||||||
@@ -64,15 +64,15 @@ func main() {
|
|||||||
|
|
||||||
if _, err := os.Stat(serverCertPath); os.IsNotExist(err) {
|
if _, err := os.Stat(serverCertPath); os.IsNotExist(err) {
|
||||||
log.Printf("Creating server certificate: %s", serverCertPath)
|
log.Printf("Creating server certificate: %s", serverCertPath)
|
||||||
err = cert.GenerateCert(
|
err = cert.GenerateCert(&cert.Options{
|
||||||
[]string{ip},
|
Hosts: []string{ip},
|
||||||
serverCertPath,
|
CertFile: serverCertPath,
|
||||||
serverKeyPath,
|
KeyFile: serverKeyPath,
|
||||||
caCertPath,
|
CAFile: caCertPath,
|
||||||
caKeyPath,
|
CAKeyFile: caKeyPath,
|
||||||
org,
|
Org: org,
|
||||||
bits,
|
Bits: bits,
|
||||||
)
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error generating server cert: %s", err)
|
log.Fatalf("error generating server cert: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
Submodule tools updated: 74dc626b6d...ca69607f79.
+1
-1
@@ -16,7 +16,7 @@ def ansibleize(h)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def get_go_version_from_build_dockerfile()
|
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'))
|
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
|
go_version = File.readlines(dockerfile_path).select { |line| line.match(go_regexp) }.first.match(go_regexp).captures.first
|
||||||
if go_version.nil?
|
if go_version.nil?
|
||||||
|
|||||||
Vendored
-26
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,7 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type ansiContext struct {
|
||||||
|
currentChar byte
|
||||||
|
paramBuffer []byte
|
||||||
|
interBuffer []byte
|
||||||
|
}
|
||||||
+49
@@ -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
|
||||||
|
}
|
||||||
Loaded 100 of 3010 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user