Merge pull request #537 from dcbw/100
Port plugins to CNI 1.0.0 and increase old verison test coverage
This commit is contained in:
commit
d385120175
4
go.mod
4
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/Microsoft/hcsshim v0.8.6
|
github.com/Microsoft/hcsshim v0.8.6
|
||||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae
|
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae
|
||||||
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44
|
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44
|
||||||
github.com/containernetworking/cni v0.8.1
|
github.com/containernetworking/cni v0.8.1-0.20201216164644-62e54113f44a
|
||||||
github.com/coreos/go-iptables v0.5.0
|
github.com/coreos/go-iptables v0.5.0
|
||||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7
|
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7
|
||||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c
|
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c
|
||||||
@ -17,7 +17,7 @@ require (
|
|||||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c
|
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c
|
||||||
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56
|
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56
|
||||||
github.com/mattn/go-shellwords v1.0.3
|
github.com/mattn/go-shellwords v1.0.3
|
||||||
github.com/onsi/ginkgo v1.12.1
|
github.com/onsi/ginkgo v1.13.0
|
||||||
github.com/onsi/gomega v1.10.3
|
github.com/onsi/gomega v1.10.3
|
||||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8
|
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8
|
||||||
github.com/sirupsen/logrus v1.0.6 // indirect
|
github.com/sirupsen/logrus v1.0.6 // indirect
|
||||||
|
15
go.sum
15
go.sum
@ -6,8 +6,8 @@ github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae h1:AMzIhMUq
|
|||||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
||||||
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44 h1:y853v6rXx+zefEcjET3JuKAqvhj+FKflQijjeaSv2iA=
|
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44 h1:y853v6rXx+zefEcjET3JuKAqvhj+FKflQijjeaSv2iA=
|
||||||
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||||
github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI=
|
github.com/containernetworking/cni v0.8.1-0.20201216164644-62e54113f44a h1:EDko/CXJ2CYF5pFdlTO/qHwkD0IxpSQY+FcTll6A/F4=
|
||||||
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
github.com/containernetworking/cni v0.8.1-0.20201216164644-62e54113f44a/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
|
||||||
github.com/coreos/go-iptables v0.5.0 h1:mw6SAibtHKZcNzAsOxjoHIG0gy5YFHhypWSSNc6EjbQ=
|
github.com/coreos/go-iptables v0.5.0 h1:mw6SAibtHKZcNzAsOxjoHIG0gy5YFHhypWSSNc6EjbQ=
|
||||||
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM=
|
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM=
|
||||||
@ -24,6 +24,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c h1:RBUpb2b14UnmRHNd2uHz20ZHLDK+SW5Us/vWF5IHRaY=
|
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c h1:RBUpb2b14UnmRHNd2uHz20ZHLDK+SW5Us/vWF5IHRaY=
|
||||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@ -48,13 +50,17 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
|
|||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
|
github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
|
||||||
|
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
|
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
|
||||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8qKWgHMH/fX2PkSabFc5mrVzfUNdg5U=
|
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8qKWgHMH/fX2PkSabFc5mrVzfUNdg5U=
|
||||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||||
|
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||||
github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s=
|
github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s=
|
||||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@ -69,6 +75,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnk
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
|
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
|
||||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -76,13 +83,17 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637 h1:O5hKNaGxIT4A8OTMnuh6UpmBdI3SAPxlZ3g0olDrJVM=
|
golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637 h1:O5hKNaGxIT4A8OTMnuh6UpmBdI3SAPxlZ3g0olDrJVM=
|
||||||
golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"github.com/Microsoft/hcsshim/hcn"
|
"github.com/Microsoft/hcsshim/hcn"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/errors"
|
"github.com/containernetworking/plugins/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -286,28 +286,20 @@ func ConstructResult(hnsNetwork *hcsshim.HNSNetwork, hnsEndpoint *hcsshim.HNSEnd
|
|||||||
return nil, errors.Annotatef(err, "failed to parse CIDR from %s", hnsNetwork.Subnets[0].AddressPrefix)
|
return nil, errors.Annotatef(err, "failed to parse CIDR from %s", hnsNetwork.Subnets[0].AddressPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ipVersion string
|
|
||||||
if ipv4 := hnsEndpoint.IPAddress.To4(); ipv4 != nil {
|
|
||||||
ipVersion = "4"
|
|
||||||
} else if ipv6 := hnsEndpoint.IPAddress.To16(); ipv6 != nil {
|
|
||||||
ipVersion = "6"
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("IPAddress of HNSEndpoint %s isn't a valid ipv4 or ipv6 Address", hnsEndpoint.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultIPConfig := ¤t.IPConfig{
|
resultIPConfig := ¤t.IPConfig{
|
||||||
Version: ipVersion,
|
|
||||||
Address: net.IPNet{
|
Address: net.IPNet{
|
||||||
IP: hnsEndpoint.IPAddress,
|
IP: hnsEndpoint.IPAddress,
|
||||||
Mask: ipSubnet.Mask},
|
Mask: ipSubnet.Mask},
|
||||||
Gateway: net.ParseIP(hnsEndpoint.GatewayAddress),
|
Gateway: net.ParseIP(hnsEndpoint.GatewayAddress),
|
||||||
}
|
}
|
||||||
result := ¤t.Result{}
|
result := ¤t.Result{
|
||||||
result.Interfaces = []*current.Interface{resultInterface}
|
CNIVersion: current.ImplementedSpecVersion,
|
||||||
result.IPs = []*current.IPConfig{resultIPConfig}
|
Interfaces: []*current.Interface{resultInterface},
|
||||||
result.DNS = types.DNS{
|
IPs: []*current.IPConfig{resultIPConfig},
|
||||||
Search: strings.Split(hnsEndpoint.DNSSuffix, ","),
|
DNS: types.DNS{
|
||||||
Nameservers: strings.Split(hnsEndpoint.DNSServerList, ","),
|
Search: strings.Split(hnsEndpoint.DNSSuffix, ","),
|
||||||
|
Nameservers: strings.Split(hnsEndpoint.DNSServerList, ","),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@ -341,29 +333,21 @@ func ConstructHcnResult(hcnNetwork *hcn.HostComputeNetwork, hcnEndpoint *hcn.Hos
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ipVersion string
|
|
||||||
ipAddress := net.ParseIP(hcnEndpoint.IpConfigurations[0].IpAddress)
|
ipAddress := net.ParseIP(hcnEndpoint.IpConfigurations[0].IpAddress)
|
||||||
if ipv4 := ipAddress.To4(); ipv4 != nil {
|
|
||||||
ipVersion = "4"
|
|
||||||
} else if ipv6 := ipAddress.To16(); ipv6 != nil {
|
|
||||||
ipVersion = "6"
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("[win-cni] The IPAddress of hnsEndpoint isn't a valid ipv4 or ipv6 Address.")
|
|
||||||
}
|
|
||||||
|
|
||||||
resultIPConfig := ¤t.IPConfig{
|
resultIPConfig := ¤t.IPConfig{
|
||||||
Version: ipVersion,
|
|
||||||
Address: net.IPNet{
|
Address: net.IPNet{
|
||||||
IP: ipAddress,
|
IP: ipAddress,
|
||||||
Mask: ipSubnet.Mask},
|
Mask: ipSubnet.Mask},
|
||||||
Gateway: net.ParseIP(hcnEndpoint.Routes[0].NextHop),
|
Gateway: net.ParseIP(hcnEndpoint.Routes[0].NextHop),
|
||||||
}
|
}
|
||||||
result := ¤t.Result{}
|
result := ¤t.Result{
|
||||||
result.Interfaces = []*current.Interface{resultInterface}
|
CNIVersion: current.ImplementedSpecVersion,
|
||||||
result.IPs = []*current.IPConfig{resultIPConfig}
|
Interfaces: []*current.Interface{resultInterface},
|
||||||
result.DNS = types.DNS{
|
IPs: []*current.IPConfig{resultIPConfig},
|
||||||
Search: hcnEndpoint.Dns.Search,
|
DNS: types.DNS{
|
||||||
Nameservers: hcnEndpoint.Dns.ServerList,
|
Search: hcnEndpoint.Dns.Search,
|
||||||
|
Nameservers: hcnEndpoint.Dns.ServerList,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
)
|
)
|
||||||
|
|
||||||
func EnableIP4Forward() error {
|
func EnableIP4Forward() error {
|
||||||
@ -36,12 +36,13 @@ func EnableForward(ips []*current.IPConfig) error {
|
|||||||
v6 := false
|
v6 := false
|
||||||
|
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
if ip.Version == "4" && !v4 {
|
isV4 := ip.Address.IP.To4() != nil
|
||||||
|
if isV4 && !v4 {
|
||||||
if err := EnableIP4Forward(); err != nil {
|
if err := EnableIP4Forward(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v4 = true
|
v4 = true
|
||||||
} else if ip.Version == "6" && !v6 {
|
} else if !isV4 && !v6 {
|
||||||
if err := EnableIP6Forward(); err != nil {
|
if err := EnableIP6Forward(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,15 +57,10 @@ func ValidateExpectedInterfaceIPs(ifName string, resultIPs []*current.IPConfig)
|
|||||||
|
|
||||||
findGwy := &netlink.Route{Dst: ourPrefix}
|
findGwy := &netlink.Route{Dst: ourPrefix}
|
||||||
routeFilter := netlink.RT_FILTER_DST
|
routeFilter := netlink.RT_FILTER_DST
|
||||||
var family int
|
|
||||||
|
|
||||||
switch {
|
family := netlink.FAMILY_V6
|
||||||
case ips.Version == "4":
|
if ips.Address.IP.To4() != nil {
|
||||||
family = netlink.FAMILY_V4
|
family = netlink.FAMILY_V4
|
||||||
case ips.Version == "6":
|
|
||||||
family = netlink.FAMILY_V6
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Invalid IP Version %v for interface %v", ips.Version, ifName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gwy, err := netlink.RouteListFiltered(family, findGwy, routeFilter)
|
gwy, err := netlink.RouteListFiltered(family, findGwy, routeFilter)
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
"github.com/containernetworking/plugins/pkg/utils/sysctl"
|
"github.com/containernetworking/plugins/pkg/utils/sysctl"
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ func ConfigureIface(ifName string, res *current.Result) error {
|
|||||||
|
|
||||||
// Make sure sysctl "disable_ipv6" is 0 if we are about to add
|
// Make sure sysctl "disable_ipv6" is 0 if we are about to add
|
||||||
// an IPv6 address to the interface
|
// an IPv6 address to the interface
|
||||||
if !has_enabled_ipv6 && ipc.Version == "6" {
|
if !has_enabled_ipv6 && ipc.Address.IP.To4() == nil {
|
||||||
// Enabled IPv6 for loopback "lo" and the interface
|
// Enabled IPv6 for loopback "lo" and the interface
|
||||||
// being configured
|
// being configured
|
||||||
for _, iface := range [2]string{"lo", ifName} {
|
for _, iface := range [2]string{"lo", ifName} {
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
@ -109,13 +109,11 @@ var _ = Describe("ConfigureIface", func() {
|
|||||||
},
|
},
|
||||||
IPs: []*current.IPConfig{
|
IPs: []*current.IPConfig{
|
||||||
{
|
{
|
||||||
Version: "4",
|
|
||||||
Interface: current.Int(0),
|
Interface: current.Int(0),
|
||||||
Address: *ipv4,
|
Address: *ipv4,
|
||||||
Gateway: ipgw4,
|
Gateway: ipgw4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Version: "6",
|
|
||||||
Interface: current.Int(0),
|
Interface: current.Int(0),
|
||||||
Address: *ipv6,
|
Address: *ipv6,
|
||||||
Gateway: ipgw6,
|
Gateway: ipgw6,
|
||||||
@ -281,12 +279,10 @@ var _ = Describe("ConfigureIface", func() {
|
|||||||
},
|
},
|
||||||
IPs: []*current.IPConfig{
|
IPs: []*current.IPConfig{
|
||||||
{
|
{
|
||||||
Version: "4",
|
|
||||||
Address: *ipv4,
|
Address: *ipv4,
|
||||||
Gateway: ipgw4,
|
Gateway: ipgw4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Version: "6",
|
|
||||||
Address: *ipv6,
|
Address: *ipv6,
|
||||||
Gateway: ipgw6,
|
Gateway: ipgw6,
|
||||||
},
|
},
|
||||||
|
@ -17,13 +17,24 @@ package testutils
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ping shells out to the `ping` command. Returns nil if successful.
|
// Ping shells out to the `ping` command. Returns nil if successful.
|
||||||
func Ping(saddr, daddr string, isV6 bool, timeoutSec int) error {
|
func Ping(saddr, daddr string, timeoutSec int) error {
|
||||||
|
ip := net.ParseIP(saddr)
|
||||||
|
if ip == nil {
|
||||||
|
return fmt.Errorf("failed to parse IP %q", saddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
bin := "ping6"
|
||||||
|
if ip.To4() != nil {
|
||||||
|
bin = "ping"
|
||||||
|
}
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"-c", "1",
|
"-c", "1",
|
||||||
"-W", strconv.Itoa(timeoutSec),
|
"-W", strconv.Itoa(timeoutSec),
|
||||||
@ -31,11 +42,6 @@ func Ping(saddr, daddr string, isV6 bool, timeoutSec int) error {
|
|||||||
daddr,
|
daddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
bin := "ping"
|
|
||||||
if isV6 {
|
|
||||||
bin = "ping6"
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command(bin, args...)
|
cmd := exec.Command(bin, args...)
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
|
54
pkg/testutils/testing.go
Normal file
54
pkg/testutils/testing.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2016 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package testutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AllSpecVersions contains all CNI spec version numbers
|
||||||
|
var AllSpecVersions = [...]string{"0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0", "1.0.0"}
|
||||||
|
|
||||||
|
// SpecVersionHasIPVersion returns true if the given CNI specification version
|
||||||
|
// includes the "version" field in the IP address elements
|
||||||
|
func SpecVersionHasIPVersion(ver string) bool {
|
||||||
|
for _, i := range []string{"0.3.0", "0.3.1", "0.4.0"} {
|
||||||
|
if ver == i {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpecVersionHasCHECK returns true if the given CNI specification version
|
||||||
|
// supports the CHECK command
|
||||||
|
func SpecVersionHasCHECK(ver string) bool {
|
||||||
|
ok, _ := version.GreaterThanOrEqualTo(ver, "0.4.0")
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpecVersionHasChaining returns true if the given CNI specification version
|
||||||
|
// supports plugin chaining
|
||||||
|
func SpecVersionHasChaining(ver string) bool {
|
||||||
|
ok, _ := version.GreaterThanOrEqualTo(ver, "0.3.0")
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpecVersionHasMultipleIPs returns true if the given CNI specification version
|
||||||
|
// supports more than one IP address of each family
|
||||||
|
func SpecVersionHasMultipleIPs(ver string) bool {
|
||||||
|
ok, _ := version.GreaterThanOrEqualTo(ver, "0.3.0")
|
||||||
|
return ok
|
||||||
|
}
|
@ -30,7 +30,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/coreos/go-systemd/activation"
|
"github.com/coreos/go-systemd/activation"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,13 +43,15 @@ type DHCP struct {
|
|||||||
leases map[string]*DHCPLease
|
leases map[string]*DHCPLease
|
||||||
hostNetnsPrefix string
|
hostNetnsPrefix string
|
||||||
clientTimeout time.Duration
|
clientTimeout time.Duration
|
||||||
|
clientResendMax time.Duration
|
||||||
broadcast bool
|
broadcast bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDHCP(clientTimeout time.Duration) *DHCP {
|
func newDHCP(clientTimeout, clientResendMax time.Duration) *DHCP {
|
||||||
return &DHCP{
|
return &DHCP{
|
||||||
leases: make(map[string]*DHCPLease),
|
leases: make(map[string]*DHCPLease),
|
||||||
clientTimeout: clientTimeout,
|
clientTimeout: clientTimeout,
|
||||||
|
clientResendMax: clientResendMax,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ func (d *DHCP) Allocate(args *skel.CmdArgs, result *current.Result) error {
|
|||||||
|
|
||||||
clientID := generateClientID(args.ContainerID, conf.Name, args.IfName)
|
clientID := generateClientID(args.ContainerID, conf.Name, args.IfName)
|
||||||
hostNetns := d.hostNetnsPrefix + args.Netns
|
hostNetns := d.hostNetnsPrefix + args.Netns
|
||||||
l, err := AcquireLease(clientID, hostNetns, args.IfName, d.clientTimeout, d.broadcast)
|
l, err := AcquireLease(clientID, hostNetns, args.IfName, d.clientTimeout, d.clientResendMax, d.broadcast)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -81,7 +83,6 @@ func (d *DHCP) Allocate(args *skel.CmdArgs, result *current.Result) error {
|
|||||||
d.setLease(clientID, l)
|
d.setLease(clientID, l)
|
||||||
|
|
||||||
result.IPs = []*current.IPConfig{{
|
result.IPs = []*current.IPConfig{{
|
||||||
Version: "4",
|
|
||||||
Address: *ipn,
|
Address: *ipn,
|
||||||
Gateway: l.Gateway(),
|
Gateway: l.Gateway(),
|
||||||
}}
|
}}
|
||||||
@ -162,7 +163,7 @@ func getListener(socketPath string) (net.Listener, error) {
|
|||||||
|
|
||||||
func runDaemon(
|
func runDaemon(
|
||||||
pidfilePath, hostPrefix, socketPath string,
|
pidfilePath, hostPrefix, socketPath string,
|
||||||
dhcpClientTimeout time.Duration, broadcast bool,
|
dhcpClientTimeout time.Duration, resendMax time.Duration, broadcast bool,
|
||||||
) error {
|
) error {
|
||||||
// since other goroutines (on separate threads) will change namespaces,
|
// since other goroutines (on separate threads) will change namespaces,
|
||||||
// ensure the RPC server does not get scheduled onto those
|
// ensure the RPC server does not get scheduled onto those
|
||||||
@ -183,7 +184,7 @@ func runDaemon(
|
|||||||
return fmt.Errorf("Error getting listener: %v", err)
|
return fmt.Errorf("Error getting listener: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dhcp := newDHCP(dhcpClientTimeout)
|
dhcp := newDHCP(dhcpClientTimeout, resendMax)
|
||||||
dhcp.hostNetnsPrefix = hostPrefix
|
dhcp.hostNetnsPrefix = hostPrefix
|
||||||
dhcp.broadcast = broadcast
|
dhcp.broadcast = broadcast
|
||||||
rpc.Register(dhcp)
|
rpc.Register(dhcp)
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -25,7 +27,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
@ -208,6 +210,11 @@ var _ = Describe("DHCP Operations", func() {
|
|||||||
dhcpPluginPath, err := exec.LookPath("dhcp")
|
dhcpPluginPath, err := exec.LookPath("dhcp")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
clientCmd = exec.Command(dhcpPluginPath, "daemon", "-socketpath", socketPath)
|
clientCmd = exec.Command(dhcpPluginPath, "daemon", "-socketpath", socketPath)
|
||||||
|
|
||||||
|
// copy dhcp client's stdout/stderr to test stdout
|
||||||
|
clientCmd.Stdout = os.Stdout
|
||||||
|
clientCmd.Stderr = os.Stderr
|
||||||
|
|
||||||
err = clientCmd.Start()
|
err = clientCmd.Start()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(clientCmd.Process).NotTo(BeNil())
|
Expect(clientCmd.Process).NotTo(BeNil())
|
||||||
@ -226,118 +233,127 @@ var _ = Describe("DHCP Operations", func() {
|
|||||||
clientCmd.Wait()
|
clientCmd.Wait()
|
||||||
|
|
||||||
Expect(originalNS.Close()).To(Succeed())
|
Expect(originalNS.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
||||||
Expect(targetNS.Close()).To(Succeed())
|
Expect(targetNS.Close()).To(Succeed())
|
||||||
defer os.RemoveAll(tmpDir)
|
Expect(testutils.UnmountNS(targetNS)).To(Succeed())
|
||||||
|
|
||||||
|
Expect(os.RemoveAll(tmpDir)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("configures and deconfigures a link with ADD/DEL", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
conf := fmt.Sprintf(`{
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
"cniVersion": "0.3.1",
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
"name": "mynet",
|
ver := ver
|
||||||
"type": "ipvlan",
|
|
||||||
"ipam": {
|
|
||||||
"type": "dhcp",
|
|
||||||
"daemonSocketPath": "%s"
|
|
||||||
}
|
|
||||||
}`, socketPath)
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
It(fmt.Sprintf("[%s] configures and deconfigures a link with ADD/DEL", ver), func() {
|
||||||
ContainerID: "dummy",
|
conf := fmt.Sprintf(`{
|
||||||
Netns: targetNS.Path(),
|
"cniVersion": "%s",
|
||||||
IfName: contVethName,
|
"name": "mynet",
|
||||||
StdinData: []byte(conf),
|
"type": "ipvlan",
|
||||||
}
|
"ipam": {
|
||||||
|
"type": "dhcp",
|
||||||
|
"daemonSocketPath": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, socketPath)
|
||||||
|
|
||||||
var addResult *current.Result
|
args := &skel.CmdArgs{
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
ContainerID: "dummy",
|
||||||
defer GinkgoRecover()
|
Netns: targetNS.Path(),
|
||||||
|
IfName: contVethName,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
var addResult *types100.Result
|
||||||
return cmdAdd(args)
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
addResult, err = current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(addResult.IPs)).To(Equal(1))
|
|
||||||
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
return testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("correctly handles multiple DELs for the same container", func() {
|
|
||||||
conf := fmt.Sprintf(`{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"ipam": {
|
|
||||||
"type": "dhcp",
|
|
||||||
"daemonSocketPath": "%s"
|
|
||||||
}
|
|
||||||
}`, socketPath)
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNS.Path(),
|
|
||||||
IfName: contVethName,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
var addResult *current.Result
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
addResult, err = current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(addResult.IPs)).To(Equal(1))
|
|
||||||
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(3)
|
|
||||||
started := sync.WaitGroup{}
|
|
||||||
started.Add(3)
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
go func() {
|
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
// Wait until all goroutines are running
|
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
started.Done()
|
return cmdAdd(args)
|
||||||
started.Wait()
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
return testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
wg.Done()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
addResult, err = types100.GetResult(r)
|
||||||
return testutils.CmdDelWithArgs(args, func() error {
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return cmdDel(args)
|
Expect(len(addResult.IPs)).To(Equal(1))
|
||||||
|
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
return testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
It(fmt.Sprintf("[%s] correctly handles multiple DELs for the same container", ver), func() {
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"ipam": {
|
||||||
|
"type": "dhcp",
|
||||||
|
"daemonSocketPath": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, socketPath)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: contVethName,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
var addResult *types100.Result
|
||||||
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
addResult, err = types100.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(len(addResult.IPs)).To(Equal(1))
|
||||||
|
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(3)
|
||||||
|
started := sync.WaitGroup{}
|
||||||
|
started.Add(3)
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
// Wait until all goroutines are running
|
||||||
|
started.Done()
|
||||||
|
started.Wait()
|
||||||
|
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
return testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
return testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -508,7 +524,19 @@ var _ = Describe("DHCP Lease Unavailable Operations", func() {
|
|||||||
// Start the DHCP client daemon
|
// Start the DHCP client daemon
|
||||||
dhcpPluginPath, err := exec.LookPath("dhcp")
|
dhcpPluginPath, err := exec.LookPath("dhcp")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
clientCmd = exec.Command(dhcpPluginPath, "daemon", "-socketpath", socketPath)
|
// Use very short timeouts for lease-unavailable operations because
|
||||||
|
// the same test is run many times, and the delays will exceed the
|
||||||
|
// `go test` timeout with default delays. Since our DHCP server
|
||||||
|
// and client daemon are local processes anyway, we can depend on
|
||||||
|
// them to respond very quickly.
|
||||||
|
clientCmd = exec.Command(dhcpPluginPath, "daemon", "-socketpath", socketPath, "-timeout", "2s", "-resendmax", "8s")
|
||||||
|
|
||||||
|
// copy dhcp client's stdout/stderr to test stdout
|
||||||
|
var b bytes.Buffer
|
||||||
|
mw := io.MultiWriter(os.Stdout, &b)
|
||||||
|
clientCmd.Stdout = mw
|
||||||
|
clientCmd.Stderr = mw
|
||||||
|
|
||||||
err = clientCmd.Start()
|
err = clientCmd.Start()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(clientCmd.Process).NotTo(BeNil())
|
Expect(clientCmd.Process).NotTo(BeNil())
|
||||||
@ -527,92 +555,101 @@ var _ = Describe("DHCP Lease Unavailable Operations", func() {
|
|||||||
clientCmd.Wait()
|
clientCmd.Wait()
|
||||||
|
|
||||||
Expect(originalNS.Close()).To(Succeed())
|
Expect(originalNS.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
||||||
Expect(targetNS.Close()).To(Succeed())
|
Expect(targetNS.Close()).To(Succeed())
|
||||||
defer os.RemoveAll(tmpDir)
|
Expect(testutils.UnmountNS(targetNS)).To(Succeed())
|
||||||
|
|
||||||
|
Expect(os.RemoveAll(tmpDir)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Configures multiple links with multiple ADD with second lease unavailable", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
conf := fmt.Sprintf(`{
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
"cniVersion": "0.3.1",
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
"name": "mynet",
|
ver := ver
|
||||||
"type": "bridge",
|
|
||||||
"bridge": "%s",
|
|
||||||
"ipam": {
|
|
||||||
"type": "dhcp",
|
|
||||||
"daemonSocketPath": "%s"
|
|
||||||
}
|
|
||||||
}`, hostBridgeName, socketPath)
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
It(fmt.Sprintf("[%s] configures multiple links with multiple ADD with second lease unavailable", ver), func() {
|
||||||
ContainerID: "dummy",
|
conf := fmt.Sprintf(`{
|
||||||
Netns: targetNS.Path(),
|
"cniVersion": "%s",
|
||||||
IfName: contVethName0,
|
"name": "mynet",
|
||||||
StdinData: []byte(conf),
|
"type": "bridge",
|
||||||
}
|
"bridge": "%s",
|
||||||
|
"ipam": {
|
||||||
|
"type": "dhcp",
|
||||||
|
"daemonSocketPath": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, hostBridgeName, socketPath)
|
||||||
|
|
||||||
var addResult *current.Result
|
args := &skel.CmdArgs{
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
ContainerID: "dummy",
|
||||||
defer GinkgoRecover()
|
Netns: targetNS.Path(),
|
||||||
|
IfName: contVethName0,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
var addResult *types100.Result
|
||||||
return cmdAdd(args)
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
addResult, err = types100.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(len(addResult.IPs)).To(Equal(1))
|
||||||
|
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
addResult, err = current.GetResult(r)
|
args = &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: contVethName1,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
_, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
println(err.Error())
|
||||||
|
Expect(err.Error()).To(Equal("error calling DHCP.Allocate: no more tries"))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(len(addResult.IPs)).To(Equal(1))
|
|
||||||
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
args = &skel.CmdArgs{
|
args = &skel.CmdArgs{
|
||||||
ContainerID: "dummy",
|
ContainerID: "dummy",
|
||||||
Netns: targetNS.Path(),
|
Netns: targetNS.Path(),
|
||||||
IfName: contVethName1,
|
IfName: contVethName1,
|
||||||
StdinData: []byte(conf),
|
StdinData: []byte(conf),
|
||||||
}
|
}
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
return testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
_, _, err := testutils.CmdAddWithArgs(args, func() error {
|
})
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
println(err.Error())
|
|
||||||
Expect(err.Error()).To(Equal("error calling DHCP.Allocate: no more tries"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
args = &skel.CmdArgs{
|
args = &skel.CmdArgs{
|
||||||
ContainerID: "dummy",
|
ContainerID: "dummy",
|
||||||
Netns: targetNS.Path(),
|
Netns: targetNS.Path(),
|
||||||
IfName: contVethName1,
|
IfName: contVethName0,
|
||||||
StdinData: []byte(conf),
|
StdinData: []byte(conf),
|
||||||
}
|
}
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
return testutils.CmdDelWithArgs(args, func() error {
|
return testutils.CmdDelWithArgs(args, func() error {
|
||||||
return cmdDel(args)
|
return cmdDel(args)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
}
|
||||||
|
|
||||||
args = &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNS.Path(),
|
|
||||||
IfName: contVethName0,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
return testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -57,6 +57,7 @@ type DHCPLease struct {
|
|||||||
rebindingTime time.Time
|
rebindingTime time.Time
|
||||||
expireTime time.Time
|
expireTime time.Time
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
resendMax time.Duration
|
||||||
broadcast bool
|
broadcast bool
|
||||||
stopping uint32
|
stopping uint32
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
@ -68,13 +69,14 @@ type DHCPLease struct {
|
|||||||
// calling DHCPLease.Stop()
|
// calling DHCPLease.Stop()
|
||||||
func AcquireLease(
|
func AcquireLease(
|
||||||
clientID, netns, ifName string,
|
clientID, netns, ifName string,
|
||||||
timeout time.Duration, broadcast bool,
|
timeout, resendMax time.Duration, broadcast bool,
|
||||||
) (*DHCPLease, error) {
|
) (*DHCPLease, error) {
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
l := &DHCPLease{
|
l := &DHCPLease{
|
||||||
clientID: clientID,
|
clientID: clientID,
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
|
resendMax: resendMax,
|
||||||
broadcast: broadcast,
|
broadcast: broadcast,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +141,7 @@ func (l *DHCPLease) acquire() error {
|
|||||||
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
|
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
|
||||||
opts[dhcp4.OptionParameterRequestList] = []byte{byte(dhcp4.OptionRouter), byte(dhcp4.OptionSubnetMask)}
|
opts[dhcp4.OptionParameterRequestList] = []byte{byte(dhcp4.OptionRouter), byte(dhcp4.OptionSubnetMask)}
|
||||||
|
|
||||||
pkt, err := backoffRetry(func() (*dhcp4.Packet, error) {
|
pkt, err := backoffRetry(l.resendMax, func() (*dhcp4.Packet, error) {
|
||||||
ok, ack, err := DhcpRequest(c, opts)
|
ok, ack, err := DhcpRequest(c, opts)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
@ -258,7 +260,7 @@ func (l *DHCPLease) renew() error {
|
|||||||
opts := make(dhcp4.Options)
|
opts := make(dhcp4.Options)
|
||||||
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
|
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
|
||||||
|
|
||||||
pkt, err := backoffRetry(func() (*dhcp4.Packet, error) {
|
pkt, err := backoffRetry(l.resendMax, func() (*dhcp4.Packet, error) {
|
||||||
ok, ack, err := DhcpRenew(c, *l.ack, opts)
|
ok, ack, err := DhcpRenew(c, *l.ack, opts)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
@ -340,7 +342,7 @@ func jitter(span time.Duration) time.Duration {
|
|||||||
return time.Duration(float64(span) * (2.0*rand.Float64() - 1.0))
|
return time.Duration(float64(span) * (2.0*rand.Float64() - 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func backoffRetry(f func() (*dhcp4.Packet, error)) (*dhcp4.Packet, error) {
|
func backoffRetry(resendMax time.Duration, f func() (*dhcp4.Packet, error)) (*dhcp4.Packet, error) {
|
||||||
var baseDelay time.Duration = resendDelay0
|
var baseDelay time.Duration = resendDelay0
|
||||||
var sleepTime time.Duration
|
var sleepTime time.Duration
|
||||||
|
|
||||||
@ -358,7 +360,7 @@ func backoffRetry(f func() (*dhcp4.Packet, error)) (*dhcp4.Packet, error) {
|
|||||||
|
|
||||||
time.Sleep(sleepTime)
|
time.Sleep(sleepTime)
|
||||||
|
|
||||||
if baseDelay < resendDelayMax {
|
if baseDelay < resendMax {
|
||||||
baseDelay *= 2
|
baseDelay *= 2
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||||
)
|
)
|
||||||
@ -40,19 +40,21 @@ func main() {
|
|||||||
var socketPath string
|
var socketPath string
|
||||||
var broadcast bool
|
var broadcast bool
|
||||||
var timeout time.Duration
|
var timeout time.Duration
|
||||||
|
var resendMax time.Duration
|
||||||
daemonFlags := flag.NewFlagSet("daemon", flag.ExitOnError)
|
daemonFlags := flag.NewFlagSet("daemon", flag.ExitOnError)
|
||||||
daemonFlags.StringVar(&pidfilePath, "pidfile", "", "optional path to write daemon PID to")
|
daemonFlags.StringVar(&pidfilePath, "pidfile", "", "optional path to write daemon PID to")
|
||||||
daemonFlags.StringVar(&hostPrefix, "hostprefix", "", "optional prefix to host root")
|
daemonFlags.StringVar(&hostPrefix, "hostprefix", "", "optional prefix to host root")
|
||||||
daemonFlags.StringVar(&socketPath, "socketpath", "", "optional dhcp server socketpath")
|
daemonFlags.StringVar(&socketPath, "socketpath", "", "optional dhcp server socketpath")
|
||||||
daemonFlags.BoolVar(&broadcast, "broadcast", false, "broadcast DHCP leases")
|
daemonFlags.BoolVar(&broadcast, "broadcast", false, "broadcast DHCP leases")
|
||||||
daemonFlags.DurationVar(&timeout, "timeout", 10*time.Second, "optional dhcp client timeout duration")
|
daemonFlags.DurationVar(&timeout, "timeout", 10*time.Second, "optional dhcp client timeout duration")
|
||||||
|
daemonFlags.DurationVar(&resendMax, "resendmax", resendDelayMax, "optional dhcp client resend max duration")
|
||||||
daemonFlags.Parse(os.Args[2:])
|
daemonFlags.Parse(os.Args[2:])
|
||||||
|
|
||||||
if socketPath == "" {
|
if socketPath == "" {
|
||||||
socketPath = defaultSocketPath
|
socketPath = defaultSocketPath
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := runDaemon(pidfilePath, hostPrefix, socketPath, timeout, broadcast); err != nil {
|
if err := runDaemon(pidfilePath, hostPrefix, socketPath, timeout, resendMax, broadcast); err != nil {
|
||||||
log.Printf(err.Error())
|
log.Printf(err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -69,7 +71,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := ¤t.Result{}
|
result := ¤t.Result{CNIVersion: current.ImplementedSpecVersion}
|
||||||
if err := rpcCall("DHCP.Allocate", args, result); err != nil {
|
if err := rpcCall("DHCP.Allocate", args, result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -96,7 +98,7 @@ func cmdCheck(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := ¤t.Result{}
|
result := ¤t.Result{CNIVersion: current.ImplementedSpecVersion}
|
||||||
if err := rpcCall("DHCP.Allocate", args, result); err != nil {
|
if err := rpcCall("DHCP.Allocate", args, result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend"
|
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend"
|
||||||
)
|
)
|
||||||
@ -108,13 +108,8 @@ func (a *IPAllocator) Get(id string, ifname string, requestedIP net.IP) (*curren
|
|||||||
if reservedIP == nil {
|
if reservedIP == nil {
|
||||||
return nil, fmt.Errorf("no IP addresses available in range set: %s", a.rangeset.String())
|
return nil, fmt.Errorf("no IP addresses available in range set: %s", a.rangeset.String())
|
||||||
}
|
}
|
||||||
version := "4"
|
|
||||||
if reservedIP.IP.To4() == nil {
|
|
||||||
version = "6"
|
|
||||||
}
|
|
||||||
|
|
||||||
return ¤t.IPConfig{
|
return ¤t.IPConfig{
|
||||||
Version: version,
|
|
||||||
Address: *reservedIP,
|
Address: *reservedIP,
|
||||||
Gateway: gw,
|
Gateway: gw,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
fakestore "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/testing"
|
fakestore "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/testing"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/020"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The top-level network config - IPAM plugins are passed the full configuration
|
// The top-level network config - IPAM plugins are passed the full configuration
|
||||||
@ -136,10 +136,8 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
|
|||||||
|
|
||||||
// CNI spec 0.2.0 and below supported only one v4 and v6 address
|
// CNI spec 0.2.0 and below supported only one v4 and v6 address
|
||||||
if numV4 > 1 || numV6 > 1 {
|
if numV4 > 1 || numV6 > 1 {
|
||||||
for _, v := range types020.SupportedVersions {
|
if ok, _ := version.GreaterThanOrEqualTo(n.CNIVersion, "0.3.0"); !ok {
|
||||||
if n.CNIVersion == v {
|
return nil, "", fmt.Errorf("CNI version %v does not support more than 1 address per family", n.CNIVersion)
|
||||||
return nil, "", fmt.Errorf("CNI version %v does not support more than 1 address per family", n.CNIVersion)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := ¤t.Result{}
|
result := ¤t.Result{CNIVersion: current.ImplementedSpecVersion}
|
||||||
|
|
||||||
if ipamConf.ResolvConf != "" {
|
if ipamConf.ResolvConf != "" {
|
||||||
dns, err := parseResolvConf(ipamConf.ResolvConf)
|
dns, err := parseResolvConf(ipamConf.ResolvConf)
|
||||||
|
@ -22,8 +22,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
types020 "github.com/containernetworking/cni/pkg/types/020"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||||
)
|
)
|
||||||
@ -225,20 +224,16 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n.IPAM.Addresses[i].Address.IP.To4() != nil {
|
if n.IPAM.Addresses[i].Address.IP.To4() != nil {
|
||||||
n.IPAM.Addresses[i].Version = "4"
|
|
||||||
numV4++
|
numV4++
|
||||||
} else {
|
} else {
|
||||||
n.IPAM.Addresses[i].Version = "6"
|
|
||||||
numV6++
|
numV6++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CNI spec 0.2.0 and below supported only one v4 and v6 address
|
// CNI spec 0.2.0 and below supported only one v4 and v6 address
|
||||||
if numV4 > 1 || numV6 > 1 {
|
if numV4 > 1 || numV6 > 1 {
|
||||||
for _, v := range types020.SupportedVersions {
|
if ok, _ := version.GreaterThanOrEqualTo(n.CNIVersion, "0.3.0"); !ok {
|
||||||
if n.CNIVersion == v {
|
return nil, "", fmt.Errorf("CNI version %v does not support more than 1 address per family", n.CNIVersion)
|
||||||
return nil, "", fmt.Errorf("CNI version %v does not support more than 1 address per family", n.CNIVersion)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,14 +249,16 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := ¤t.Result{}
|
result := ¤t.Result{
|
||||||
result.DNS = ipamConf.DNS
|
CNIVersion: current.ImplementedSpecVersion,
|
||||||
result.Routes = ipamConf.Routes
|
DNS: ipamConf.DNS,
|
||||||
|
Routes: ipamConf.Routes,
|
||||||
|
}
|
||||||
for _, v := range ipamConf.Addresses {
|
for _, v := range ipamConf.Addresses {
|
||||||
result.IPs = append(result.IPs, ¤t.IPConfig{
|
result.IPs = append(result.IPs, ¤t.IPConfig{
|
||||||
Version: v.Version,
|
|
||||||
Address: v.Address,
|
Address: v.Address,
|
||||||
Gateway: v.Gateway})
|
Gateway: v.Gateway,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.PrintResult(result, confVersion)
|
return types.PrintResult(result, confVersion)
|
||||||
|
@ -15,12 +15,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@ -28,18 +29,101 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("static Operations", func() {
|
var _ = Describe("static Operations", func() {
|
||||||
It("allocates and releases addresses with ADD/DEL", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
const ifname string = "eth0"
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
const nspath string = "/some/where"
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
|
ver := ver
|
||||||
|
|
||||||
conf := `{
|
It(fmt.Sprintf("[%s] allocates and releases addresses with ADD/DEL", ver), func() {
|
||||||
"cniVersion": "0.3.1",
|
const ifname string = "eth0"
|
||||||
"name": "mynet",
|
const nspath string = "/some/where"
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "foo0",
|
conf := fmt.Sprintf(`{
|
||||||
"ipam": {
|
"cniVersion": "%s",
|
||||||
"type": "static",
|
"name": "mynet",
|
||||||
"addresses": [ {
|
"type": "ipvlan",
|
||||||
|
"master": "foo0",
|
||||||
|
"ipam": {
|
||||||
|
"type": "static",
|
||||||
|
"addresses": [ {
|
||||||
|
"address": "10.10.0.1/24",
|
||||||
|
"gateway": "10.10.0.254"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "3ffe:ffff:0:01ff::1/64",
|
||||||
|
"gateway": "3ffe:ffff:0::1"
|
||||||
|
}],
|
||||||
|
"routes": [
|
||||||
|
{ "dst": "0.0.0.0/0" },
|
||||||
|
{ "dst": "192.168.0.0/16", "gw": "10.10.5.1" },
|
||||||
|
{ "dst": "3ffe:ffff:0:01ff::1/64" }],
|
||||||
|
"dns": {
|
||||||
|
"nameservers" : ["8.8.8.8"],
|
||||||
|
"domain": "example.com",
|
||||||
|
"search": [ "example.com" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`, ver)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the IP
|
||||||
|
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
if testutils.SpecVersionHasIPVersion(ver) {
|
||||||
|
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := types100.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Gomega is cranky about slices with different caps
|
||||||
|
Expect(*result.IPs[0]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("10.10.0.1/24"),
|
||||||
|
Gateway: net.ParseIP("10.10.0.254"),
|
||||||
|
}))
|
||||||
|
|
||||||
|
Expect(*result.IPs[1]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
||||||
|
Gateway: net.ParseIP("3ffe:ffff:0::1"),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
Expect(len(result.IPs)).To(Equal(2))
|
||||||
|
|
||||||
|
Expect(result.Routes).To(Equal([]*types.Route{
|
||||||
|
{Dst: mustCIDR("0.0.0.0/0")},
|
||||||
|
{Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")},
|
||||||
|
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64")},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Release the IP
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] doesn't error when passed an unknown ID on DEL", ver), func() {
|
||||||
|
const ifname string = "eth0"
|
||||||
|
const nspath string = "/some/where"
|
||||||
|
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"master": "foo0",
|
||||||
|
"ipam": {
|
||||||
|
"type": "static",
|
||||||
|
"addresses": [ {
|
||||||
"address": "10.10.0.1/24",
|
"address": "10.10.0.1/24",
|
||||||
"gateway": "10.10.0.254"
|
"gateway": "10.10.0.254"
|
||||||
},
|
},
|
||||||
@ -47,439 +131,370 @@ var _ = Describe("static Operations", func() {
|
|||||||
"address": "3ffe:ffff:0:01ff::1/64",
|
"address": "3ffe:ffff:0:01ff::1/64",
|
||||||
"gateway": "3ffe:ffff:0::1"
|
"gateway": "3ffe:ffff:0::1"
|
||||||
}],
|
}],
|
||||||
"routes": [
|
"routes": [
|
||||||
{ "dst": "0.0.0.0/0" },
|
{ "dst": "0.0.0.0/0" },
|
||||||
{ "dst": "192.168.0.0/16", "gw": "10.10.5.1" },
|
{ "dst": "192.168.0.0/16", "gw": "10.10.5.1" },
|
||||||
{ "dst": "3ffe:ffff:0:01ff::1/64" }],
|
{ "dst": "3ffe:ffff:0:01ff::1/64" }],
|
||||||
"dns": {
|
"dns": {
|
||||||
"nameservers" : ["8.8.8.8"],
|
"nameservers" : ["8.8.8.8"],
|
||||||
"domain": "example.com",
|
"domain": "example.com",
|
||||||
"search": [ "example.com" ]
|
"search": [ "example.com" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}`, ver)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
}
|
}
|
||||||
}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
// Release the IP
|
||||||
ContainerID: "dummy",
|
err := testutils.CmdDelWithArgs(args, func() error {
|
||||||
Netns: nspath,
|
return cmdDel(args)
|
||||||
IfName: ifname,
|
})
|
||||||
StdinData: []byte(conf),
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the IP
|
|
||||||
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
|
||||||
|
|
||||||
result, err := current.GetResult(r)
|
It(fmt.Sprintf("[%s] allocates and releases addresses with ADD/DEL, with ENV variables", ver), func() {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
const ifname string = "eth0"
|
||||||
|
const nspath string = "/some/where"
|
||||||
|
|
||||||
// Gomega is cranky about slices with different caps
|
conf := fmt.Sprintf(`{
|
||||||
Expect(*result.IPs[0]).To(Equal(
|
"cniVersion": "%s",
|
||||||
current.IPConfig{
|
"name": "mynet",
|
||||||
Version: "4",
|
"type": "ipvlan",
|
||||||
Address: mustCIDR("10.10.0.1/24"),
|
"master": "foo0",
|
||||||
Gateway: net.ParseIP("10.10.0.254"),
|
"ipam": {
|
||||||
|
"type": "static",
|
||||||
|
"routes": [
|
||||||
|
{ "dst": "0.0.0.0/0" },
|
||||||
|
{ "dst": "192.168.0.0/16", "gw": "10.10.5.1" }],
|
||||||
|
"dns": {
|
||||||
|
"nameservers" : ["8.8.8.8"],
|
||||||
|
"domain": "example.com",
|
||||||
|
"search": [ "example.com" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`, ver)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
Args: "IP=10.10.0.1/24;GATEWAY=10.10.0.254",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the IP
|
||||||
|
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
if testutils.SpecVersionHasIPVersion(ver) {
|
||||||
|
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := types100.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Gomega is cranky about slices with different caps
|
||||||
|
Expect(*result.IPs[0]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("10.10.0.1/24"),
|
||||||
|
Gateway: net.ParseIP("10.10.0.254"),
|
||||||
|
}))
|
||||||
|
|
||||||
|
Expect(len(result.IPs)).To(Equal(1))
|
||||||
|
|
||||||
|
Expect(result.Routes).To(Equal([]*types.Route{
|
||||||
|
{Dst: mustCIDR("0.0.0.0/0")},
|
||||||
|
{Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Expect(*result.IPs[1]).To(Equal(
|
// Release the IP
|
||||||
current.IPConfig{
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
Version: "6",
|
return cmdDel(args)
|
||||||
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
})
|
||||||
Gateway: net.ParseIP("3ffe:ffff:0::1"),
|
Expect(err).NotTo(HaveOccurred())
|
||||||
},
|
|
||||||
))
|
|
||||||
Expect(len(result.IPs)).To(Equal(2))
|
|
||||||
|
|
||||||
Expect(result.Routes).To(Equal([]*types.Route{
|
|
||||||
{Dst: mustCIDR("0.0.0.0/0")},
|
|
||||||
{Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")},
|
|
||||||
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64")},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Release the IP
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("doesn't error when passed an unknown ID on DEL", func() {
|
It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, with ENV variables", ver), func() {
|
||||||
const ifname string = "eth0"
|
const ifname string = "eth0"
|
||||||
const nspath string = "/some/where"
|
const nspath string = "/some/where"
|
||||||
|
|
||||||
conf := `{
|
conf := fmt.Sprintf(`{
|
||||||
"cniVersion": "0.3.0",
|
"cniVersion": "%s",
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"type": "ipvlan",
|
"type": "ipvlan",
|
||||||
"master": "foo0",
|
"master": "foo0",
|
||||||
"ipam": {
|
"ipam": {
|
||||||
"type": "static",
|
"type": "static"
|
||||||
"addresses": [ {
|
}
|
||||||
"address": "10.10.0.1/24",
|
}`, ver)
|
||||||
"gateway": "10.10.0.254"
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
Args: "IP=10.10.0.1/24,11.11.0.1/24;GATEWAY=10.10.0.254",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the IP
|
||||||
|
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
if !testutils.SpecVersionHasMultipleIPs(ver) {
|
||||||
|
errStr := fmt.Sprintf("CNI version %s does not support more than 1 address per family", ver)
|
||||||
|
Expect(err).To(MatchError(errStr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
if testutils.SpecVersionHasIPVersion(ver) {
|
||||||
|
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := types100.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Gomega is cranky about slices with different caps
|
||||||
|
Expect(*result.IPs[0]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("10.10.0.1/24"),
|
||||||
|
Gateway: net.ParseIP("10.10.0.254"),
|
||||||
|
}))
|
||||||
|
Expect(*result.IPs[1]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("11.11.0.1/24"),
|
||||||
|
Gateway: nil,
|
||||||
|
}))
|
||||||
|
|
||||||
|
Expect(len(result.IPs)).To(Equal(2))
|
||||||
|
|
||||||
|
// Release the IP
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig", ver), func() {
|
||||||
|
const ifname string = "eth0"
|
||||||
|
const nspath string = "/some/where"
|
||||||
|
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"master": "foo0",
|
||||||
|
"capabilities": {"ips": true},
|
||||||
|
"ipam": {
|
||||||
|
"type": "static",
|
||||||
|
"routes": [
|
||||||
|
{ "dst": "0.0.0.0/0", "gw": "10.10.0.254" },
|
||||||
|
{ "dst": "3ffe:ffff:0:01ff::1/64",
|
||||||
|
"gw": "3ffe:ffff:0::1" } ],
|
||||||
|
"dns": {
|
||||||
|
"nameservers" : ["8.8.8.8"],
|
||||||
|
"domain": "example.com",
|
||||||
|
"search": [ "example.com" ]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
"RuntimeConfig": {
|
||||||
"address": "3ffe:ffff:0:01ff::1/64",
|
|
||||||
"gateway": "3ffe:ffff:0::1"
|
|
||||||
}],
|
|
||||||
"routes": [
|
|
||||||
{ "dst": "0.0.0.0/0" },
|
|
||||||
{ "dst": "192.168.0.0/16", "gw": "10.10.5.1" },
|
|
||||||
{ "dst": "3ffe:ffff:0:01ff::1/64" }],
|
|
||||||
"dns": {
|
|
||||||
"nameservers" : ["8.8.8.8"],
|
|
||||||
"domain": "example.com",
|
|
||||||
"search": [ "example.com" ]
|
|
||||||
}}}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: nspath,
|
|
||||||
IfName: ifname,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the IP
|
|
||||||
err := testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("allocates and releases addresses with ADD/DEL, with ENV variables", func() {
|
|
||||||
const ifname string = "eth0"
|
|
||||||
const nspath string = "/some/where"
|
|
||||||
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "foo0",
|
|
||||||
"ipam": {
|
|
||||||
"type": "static",
|
|
||||||
"routes": [
|
|
||||||
{ "dst": "0.0.0.0/0" },
|
|
||||||
{ "dst": "192.168.0.0/16", "gw": "10.10.5.1" }],
|
|
||||||
"dns": {
|
|
||||||
"nameservers" : ["8.8.8.8"],
|
|
||||||
"domain": "example.com",
|
|
||||||
"search": [ "example.com" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: nspath,
|
|
||||||
IfName: ifname,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
Args: "IP=10.10.0.1/24;GATEWAY=10.10.0.254",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the IP
|
|
||||||
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
|
||||||
|
|
||||||
result, err := current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Gomega is cranky about slices with different caps
|
|
||||||
Expect(*result.IPs[0]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "4",
|
|
||||||
Address: mustCIDR("10.10.0.1/24"),
|
|
||||||
Gateway: net.ParseIP("10.10.0.254"),
|
|
||||||
}))
|
|
||||||
|
|
||||||
Expect(len(result.IPs)).To(Equal(1))
|
|
||||||
|
|
||||||
Expect(result.Routes).To(Equal([]*types.Route{
|
|
||||||
{Dst: mustCIDR("0.0.0.0/0")},
|
|
||||||
{Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Release the IP
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("allocates and releases multiple addresses with ADD/DEL, with ENV variables", func() {
|
|
||||||
const ifname string = "eth0"
|
|
||||||
const nspath string = "/some/where"
|
|
||||||
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "foo0",
|
|
||||||
"ipam": {
|
|
||||||
"type": "static"
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: nspath,
|
|
||||||
IfName: ifname,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
Args: "IP=10.10.0.1/24,11.11.0.1/24;GATEWAY=10.10.0.254",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the IP
|
|
||||||
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
|
||||||
|
|
||||||
result, err := current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Gomega is cranky about slices with different caps
|
|
||||||
Expect(*result.IPs[0]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "4",
|
|
||||||
Address: mustCIDR("10.10.0.1/24"),
|
|
||||||
Gateway: net.ParseIP("10.10.0.254"),
|
|
||||||
}))
|
|
||||||
Expect(*result.IPs[1]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "4",
|
|
||||||
Address: mustCIDR("11.11.0.1/24"),
|
|
||||||
Gateway: nil,
|
|
||||||
}))
|
|
||||||
|
|
||||||
Expect(len(result.IPs)).To(Equal(2))
|
|
||||||
|
|
||||||
// Release the IP
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig", func() {
|
|
||||||
const ifname string = "eth0"
|
|
||||||
const nspath string = "/some/where"
|
|
||||||
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "foo0",
|
|
||||||
"capabilities": {"ips": true},
|
|
||||||
"ipam": {
|
|
||||||
"type": "static",
|
|
||||||
"routes": [
|
|
||||||
{ "dst": "0.0.0.0/0", "gw": "10.10.0.254" },
|
|
||||||
{ "dst": "3ffe:ffff:0:01ff::1/64",
|
|
||||||
"gw": "3ffe:ffff:0::1" } ],
|
|
||||||
"dns": {
|
|
||||||
"nameservers" : ["8.8.8.8"],
|
|
||||||
"domain": "example.com",
|
|
||||||
"search": [ "example.com" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RuntimeConfig": {
|
|
||||||
"ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"]
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: nspath,
|
|
||||||
IfName: ifname,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the IP
|
|
||||||
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
|
||||||
|
|
||||||
result, err := current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Gomega is cranky about slices with different caps
|
|
||||||
Expect(*result.IPs[0]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "4",
|
|
||||||
Address: mustCIDR("10.10.0.1/24"),
|
|
||||||
}))
|
|
||||||
Expect(*result.IPs[1]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "6",
|
|
||||||
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
Expect(len(result.IPs)).To(Equal(2))
|
|
||||||
Expect(result.Routes).To(Equal([]*types.Route{
|
|
||||||
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")},
|
|
||||||
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Release the IP
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("allocates and releases multiple addresses with ADD/DEL, from args", func() {
|
|
||||||
const ifname string = "eth0"
|
|
||||||
const nspath string = "/some/where"
|
|
||||||
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "foo0",
|
|
||||||
"ipam": {
|
|
||||||
"type": "static",
|
|
||||||
"routes": [
|
|
||||||
{ "dst": "0.0.0.0/0", "gw": "10.10.0.254" },
|
|
||||||
{ "dst": "3ffe:ffff:0:01ff::1/64",
|
|
||||||
"gw": "3ffe:ffff:0::1" } ],
|
|
||||||
"dns": {
|
|
||||||
"nameservers" : ["8.8.8.8"],
|
|
||||||
"domain": "example.com",
|
|
||||||
"search": [ "example.com" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"args": {
|
|
||||||
"cni": {
|
|
||||||
"ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"]
|
"ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"]
|
||||||
}
|
}
|
||||||
|
}`, ver)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
}
|
}
|
||||||
}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
// Allocate the IP
|
||||||
ContainerID: "dummy",
|
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
Netns: nspath,
|
return cmdAdd(args)
|
||||||
IfName: ifname,
|
})
|
||||||
StdinData: []byte(conf),
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
if testutils.SpecVersionHasIPVersion(ver) {
|
||||||
|
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
||||||
// Allocate the IP
|
|
||||||
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
|
||||||
|
|
||||||
result, err := current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Gomega is cranky about slices with different caps
|
|
||||||
Expect(*result.IPs[0]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "4",
|
|
||||||
Address: mustCIDR("10.10.0.1/24"),
|
|
||||||
}))
|
|
||||||
Expect(*result.IPs[1]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "6",
|
|
||||||
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
Expect(len(result.IPs)).To(Equal(2))
|
|
||||||
Expect(result.Routes).To(Equal([]*types.Route{
|
|
||||||
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")},
|
|
||||||
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Release the IP
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig/ARGS/CNI_ARGS", func() {
|
|
||||||
const ifname string = "eth0"
|
|
||||||
const nspath string = "/some/where"
|
|
||||||
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "foo0",
|
|
||||||
"capabilities": {"ips": true},
|
|
||||||
"ipam": {
|
|
||||||
"type": "static",
|
|
||||||
"routes": [
|
|
||||||
{ "dst": "0.0.0.0/0", "gw": "10.10.0.254" },
|
|
||||||
{ "dst": "3ffe:ffff:0:01ff::1/64",
|
|
||||||
"gw": "3ffe:ffff:0::1" } ],
|
|
||||||
"dns": {
|
|
||||||
"nameservers" : ["8.8.8.8"],
|
|
||||||
"domain": "example.com",
|
|
||||||
"search": [ "example.com" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RuntimeConfig": {
|
|
||||||
"ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"]
|
|
||||||
},
|
|
||||||
"args": {
|
|
||||||
"cni": {
|
|
||||||
"ips" : ["10.10.0.2/24", "3ffe:ffff:0:01ff::2/64"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
result, err := types100.GetResult(r)
|
||||||
ContainerID: "dummy",
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Netns: nspath,
|
|
||||||
IfName: ifname,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
Args: "IP=10.10.0.3/24,11.11.0.3/24;GATEWAY=10.10.0.254",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the IP
|
// Gomega is cranky about slices with different caps
|
||||||
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
Expect(*result.IPs[0]).To(Equal(
|
||||||
return cmdAdd(args)
|
types100.IPConfig{
|
||||||
})
|
Address: mustCIDR("10.10.0.1/24"),
|
||||||
Expect(err).NotTo(HaveOccurred())
|
}))
|
||||||
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
Expect(*result.IPs[1]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
result, err := current.GetResult(r)
|
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
||||||
Expect(err).NotTo(HaveOccurred())
|
},
|
||||||
|
))
|
||||||
// only addresses in runtimeConfig configured because of its priorities
|
Expect(len(result.IPs)).To(Equal(2))
|
||||||
Expect(*result.IPs[0]).To(Equal(
|
Expect(result.Routes).To(Equal([]*types.Route{
|
||||||
current.IPConfig{
|
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")},
|
||||||
Version: "4",
|
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
|
||||||
Address: mustCIDR("10.10.0.1/24"),
|
|
||||||
}))
|
}))
|
||||||
Expect(*result.IPs[1]).To(Equal(
|
|
||||||
current.IPConfig{
|
|
||||||
Version: "6",
|
|
||||||
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
Expect(len(result.IPs)).To(Equal(2))
|
|
||||||
Expect(result.Routes).To(Equal([]*types.Route{
|
|
||||||
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")},
|
|
||||||
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Release the IP
|
// Release the IP
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
return cmdDel(args)
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, from args", ver), func() {
|
||||||
|
const ifname string = "eth0"
|
||||||
|
const nspath string = "/some/where"
|
||||||
|
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"master": "foo0",
|
||||||
|
"ipam": {
|
||||||
|
"type": "static",
|
||||||
|
"routes": [
|
||||||
|
{ "dst": "0.0.0.0/0", "gw": "10.10.0.254" },
|
||||||
|
{ "dst": "3ffe:ffff:0:01ff::1/64",
|
||||||
|
"gw": "3ffe:ffff:0::1" } ],
|
||||||
|
"dns": {
|
||||||
|
"nameservers" : ["8.8.8.8"],
|
||||||
|
"domain": "example.com",
|
||||||
|
"search": [ "example.com" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": {
|
||||||
|
"cni": {
|
||||||
|
"ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`, ver)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the IP
|
||||||
|
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
if testutils.SpecVersionHasIPVersion(ver) {
|
||||||
|
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := types100.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Gomega is cranky about slices with different caps
|
||||||
|
Expect(*result.IPs[0]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("10.10.0.1/24"),
|
||||||
|
}))
|
||||||
|
Expect(*result.IPs[1]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
Expect(len(result.IPs)).To(Equal(2))
|
||||||
|
Expect(result.Routes).To(Equal([]*types.Route{
|
||||||
|
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")},
|
||||||
|
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Release the IP
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig/ARGS/CNI_ARGS", ver), func() {
|
||||||
|
const ifname string = "eth0"
|
||||||
|
const nspath string = "/some/where"
|
||||||
|
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"master": "foo0",
|
||||||
|
"capabilities": {"ips": true},
|
||||||
|
"ipam": {
|
||||||
|
"type": "static",
|
||||||
|
"routes": [
|
||||||
|
{ "dst": "0.0.0.0/0", "gw": "10.10.0.254" },
|
||||||
|
{ "dst": "3ffe:ffff:0:01ff::1/64",
|
||||||
|
"gw": "3ffe:ffff:0::1" } ],
|
||||||
|
"dns": {
|
||||||
|
"nameservers" : ["8.8.8.8"],
|
||||||
|
"domain": "example.com",
|
||||||
|
"search": [ "example.com" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RuntimeConfig": {
|
||||||
|
"ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"]
|
||||||
|
},
|
||||||
|
"args": {
|
||||||
|
"cni": {
|
||||||
|
"ips" : ["10.10.0.2/24", "3ffe:ffff:0:01ff::2/64"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`, ver)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: nspath,
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
Args: "IP=10.10.0.3/24,11.11.0.3/24;GATEWAY=10.10.0.254",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the IP
|
||||||
|
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
if testutils.SpecVersionHasIPVersion(ver) {
|
||||||
|
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := types100.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// only addresses in runtimeConfig configured because of its priorities
|
||||||
|
Expect(*result.IPs[0]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("10.10.0.1/24"),
|
||||||
|
}))
|
||||||
|
Expect(*result.IPs[1]).To(Equal(
|
||||||
|
types100.IPConfig{
|
||||||
|
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
Expect(len(result.IPs)).To(Equal(2))
|
||||||
|
Expect(result.Routes).To(Equal([]*types.Route{
|
||||||
|
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")},
|
||||||
|
{Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Release the IP
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
func mustCIDR(s string) net.IPNet {
|
func mustCIDR(s string) net.IPNet {
|
||||||
|
@ -29,7 +29,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
"github.com/containernetworking/plugins/pkg/ipam"
|
"github.com/containernetworking/plugins/pkg/ipam"
|
||||||
@ -412,7 +412,14 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assume L2 interface only
|
// Assume L2 interface only
|
||||||
result := ¤t.Result{CNIVersion: cniVersion, Interfaces: []*current.Interface{brInterface, hostInterface, containerInterface}}
|
result := ¤t.Result{
|
||||||
|
CNIVersion: current.ImplementedSpecVersion,
|
||||||
|
Interfaces: []*current.Interface{
|
||||||
|
brInterface,
|
||||||
|
hostInterface,
|
||||||
|
containerInterface,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
if isLayer3 {
|
if isLayer3 {
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
@ -453,7 +460,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
// bridge. Hairpin mode causes echos of neighbor solicitation
|
// bridge. Hairpin mode causes echos of neighbor solicitation
|
||||||
// packets, which causes DAD failures.
|
// packets, which causes DAD failures.
|
||||||
for _, ipc := range result.IPs {
|
for _, ipc := range result.IPs {
|
||||||
if ipc.Version == "6" && (n.HairpinMode || n.PromiscMode) {
|
if ipc.Address.IP.To4() == nil && (n.HairpinMode || n.PromiscMode) {
|
||||||
if err := disableIPV6DAD(args.IfName); err != nil {
|
if err := disableIPV6DAD(args.IfName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -496,7 +503,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ipc := range result.IPs {
|
for _, ipc := range result.IPs {
|
||||||
if ipc.Version == "4" {
|
if ipc.Address.IP.To4() != nil {
|
||||||
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
|
@ -17,12 +17,17 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/020"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/040"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
@ -44,37 +49,33 @@ type Net struct {
|
|||||||
IPAM *allocator.IPAMConfig `json:"ipam"`
|
IPAM *allocator.IPAMConfig `json:"ipam"`
|
||||||
DNS types.DNS `json:"dns"`
|
DNS types.DNS `json:"dns"`
|
||||||
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
|
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
|
||||||
PrevResult current.Result `json:"-"`
|
PrevResult types100.Result `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOneConfig(netName string, cniVersion string, master string, orig *Net, prevResult types.Result) (*Net, error) {
|
func buildOneConfig(cniVersion string, master string, orig *Net, prevResult types.Result) (*Net, error) {
|
||||||
var err error
|
|
||||||
|
|
||||||
inject := map[string]interface{}{
|
|
||||||
"name": netName,
|
|
||||||
"cniVersion": cniVersion,
|
|
||||||
}
|
|
||||||
// Add previous plugin result
|
|
||||||
if prevResult != nil {
|
|
||||||
inject["prevResult"] = prevResult
|
|
||||||
}
|
|
||||||
if orig.IPAM == nil {
|
|
||||||
inject["master"] = master
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure every config uses the same name and version
|
|
||||||
config := make(map[string]interface{})
|
|
||||||
|
|
||||||
confBytes, err := json.Marshal(orig)
|
confBytes, err := json.Marshal(orig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config := make(map[string]interface{})
|
||||||
err = json.Unmarshal(confBytes, &config)
|
err = json.Unmarshal(confBytes, &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unmarshal existing network bytes: %s", err)
|
return nil, fmt.Errorf("unmarshal existing network bytes: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inject := map[string]interface{}{
|
||||||
|
"name": orig.Name,
|
||||||
|
"cniVersion": orig.CNIVersion,
|
||||||
|
}
|
||||||
|
// Add previous plugin result
|
||||||
|
if prevResult != nil && testutils.SpecVersionHasChaining(cniVersion) {
|
||||||
|
inject["prevResult"] = prevResult
|
||||||
|
}
|
||||||
|
if master != "" {
|
||||||
|
inject["master"] = master
|
||||||
|
}
|
||||||
|
|
||||||
for key, value := range inject {
|
for key, value := range inject {
|
||||||
config[key] = value
|
config[key] = value
|
||||||
}
|
}
|
||||||
@ -93,121 +94,49 @@ func buildOneConfig(netName string, cniVersion string, master string, orig *Net,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipvlanAddDelTest(conf, IFNAME string, originalNS ns.NetNS) {
|
func ipvlanAddCheckDelTest(conf, masterName string, originalNS, targetNS ns.NetNS) {
|
||||||
targetNs, err := testutils.NewNS()
|
// Unmarshal to pull out CNI spec version
|
||||||
|
rawConfig := make(map[string]interface{})
|
||||||
|
err := json.Unmarshal([]byte(conf), &rawConfig)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
defer targetNs.Close()
|
cniVersion := rawConfig["cniVersion"].(string)
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
args := &skel.CmdArgs{
|
||||||
ContainerID: "dummy",
|
ContainerID: "dummy",
|
||||||
Netns: targetNs.Path(),
|
Netns: targetNS.Path(),
|
||||||
IfName: IFNAME,
|
IfName: "ipvl0",
|
||||||
StdinData: []byte(conf),
|
StdinData: []byte(conf),
|
||||||
}
|
}
|
||||||
|
|
||||||
var result *current.Result
|
var result types.Result
|
||||||
|
var macAddress string
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
result, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||||
return cmdAdd(args)
|
return cmdAdd(args)
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
result, err = current.GetResult(r)
|
t := newTesterByVersion(cniVersion)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
macAddress = t.verifyResult(result, args.IfName)
|
||||||
|
|
||||||
Expect(len(result.Interfaces)).To(Equal(1))
|
|
||||||
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
|
||||||
Expect(len(result.IPs)).To(Equal(1))
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// Make sure ipvlan link exists in the target namespace
|
// Make sure ipvlan link exists in the target namespace
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
link, err := netlink.LinkByName(args.IfName)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
Expect(link.Attrs().Name).To(Equal(args.IfName))
|
||||||
|
|
||||||
hwaddr, err := net.ParseMAC(result.Interfaces[0].Mac)
|
if macAddress != "" {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
hwaddr, err := net.ParseMAC(macAddress)
|
||||||
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
||||||
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
}
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(addrs)).To(Equal(1))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure ipvlan link has been deleted
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(link).To(BeNil())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
|
|
||||||
func ipvlanAddCheckDelTest(conf string, netName string, IFNAME string, originalNS ns.NetNS) {
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result *current.Result
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
result, err = current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
Expect(len(result.Interfaces)).To(Equal(1))
|
|
||||||
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
|
||||||
Expect(len(result.IPs)).To(Equal(1))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure ipvlan link exists in the target namespace
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
|
||||||
|
|
||||||
hwaddr, err := net.ParseMAC(result.Interfaces[0].Mac)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
|
||||||
|
|
||||||
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
@ -225,26 +154,26 @@ func ipvlanAddCheckDelTest(conf string, netName string, IFNAME string, originalN
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
cniVersion := "0.4.0"
|
// build chained/cached config for DEL
|
||||||
newConf, err := buildOneConfig(netName, cniVersion, MASTER_NAME, n, result)
|
newConf, err := buildOneConfig(cniVersion, masterName, n, result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
confBytes, err := json.Marshal(newConf)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
confString, err := json.Marshal(newConf)
|
args.StdinData = confBytes
|
||||||
Expect(err).NotTo(HaveOccurred())
|
GinkgoT().Logf(string(confBytes))
|
||||||
|
|
||||||
args.StdinData = confString
|
if testutils.SpecVersionHasCHECK(cniVersion) {
|
||||||
|
// CNI Check on ipvlan in the target namespace
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
// CNI Check on ipvlan in the target namespace
|
return testutils.CmdCheckWithArgs(args, func() error {
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
return cmdCheck(args)
|
||||||
defer GinkgoRecover()
|
})
|
||||||
|
|
||||||
err := testutils.CmdCheckWithArgs(args, func() error {
|
|
||||||
return cmdCheck(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
}
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
@ -258,10 +187,10 @@ func ipvlanAddCheckDelTest(conf string, netName string, IFNAME string, originalN
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// Make sure ipvlan link has been deleted
|
// Make sure ipvlan link has been deleted
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
link, err := netlink.LinkByName(args.IfName)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(link).To(BeNil())
|
Expect(link).To(BeNil())
|
||||||
return nil
|
return nil
|
||||||
@ -269,8 +198,70 @@ func ipvlanAddCheckDelTest(conf string, netName string, IFNAME string, originalN
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tester interface {
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
verifyResult(result types.Result, name string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type testerBase struct{}
|
||||||
|
|
||||||
|
type testerV10x testerBase
|
||||||
|
type testerV04x testerBase
|
||||||
|
type testerV02x testerBase
|
||||||
|
|
||||||
|
func newTesterByVersion(version string) tester {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(version, "1.0."):
|
||||||
|
return &testerV10x{}
|
||||||
|
case strings.HasPrefix(version, "0.4.") || strings.HasPrefix(version, "0.3."):
|
||||||
|
return &testerV04x{}
|
||||||
|
case strings.HasPrefix(version, "0.1.") || strings.HasPrefix(version, "0.2."):
|
||||||
|
return &testerV02x{}
|
||||||
|
}
|
||||||
|
Fail(fmt.Sprintf("unsupported config version %s", version))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
func (t *testerV10x) verifyResult(result types.Result, name string) string {
|
||||||
|
r, err := types100.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(r.Interfaces)).To(Equal(1))
|
||||||
|
Expect(r.Interfaces[0].Name).To(Equal(name))
|
||||||
|
Expect(len(r.IPs)).To(Equal(1))
|
||||||
|
|
||||||
|
return r.Interfaces[0].Mac
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
func (t *testerV04x) verifyResult(result types.Result, name string) string {
|
||||||
|
r, err := types040.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(r.Interfaces)).To(Equal(1))
|
||||||
|
Expect(r.Interfaces[0].Name).To(Equal(name))
|
||||||
|
Expect(len(r.IPs)).To(Equal(1))
|
||||||
|
|
||||||
|
return r.Interfaces[0].Mac
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
func (t *testerV02x) verifyResult(result types.Result, name string) string {
|
||||||
|
r, err := types020.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(r.IP4.IP).NotTo(BeNil())
|
||||||
|
Expect(r.IP4.IP.IP).NotTo(BeNil())
|
||||||
|
Expect(r.IP6).To(BeNil())
|
||||||
|
|
||||||
|
// 0.2 and earlier don't return MAC address
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("ipvlan Operations", func() {
|
var _ = Describe("ipvlan Operations", func() {
|
||||||
var originalNS ns.NetNS
|
var originalNS, targetNS ns.NetNS
|
||||||
|
var dataDir string
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
// Create a new NetNS so we don't modify the host
|
// Create a new NetNS so we don't modify the host
|
||||||
@ -278,6 +269,12 @@ var _ = Describe("ipvlan Operations", func() {
|
|||||||
originalNS, err = testutils.NewNS()
|
originalNS, err = testutils.NewNS()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
targetNS, err = testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
dataDir, err = ioutil.TempDir("", "ipvlan_test")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
@ -296,219 +293,170 @@ var _ = Describe("ipvlan Operations", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||||
|
|
||||||
Expect(originalNS.Close()).To(Succeed())
|
Expect(originalNS.Close()).To(Succeed())
|
||||||
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
||||||
|
|
||||||
|
Expect(targetNS.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(targetNS)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("creates an ipvlan link in a non-default namespace", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
conf := &NetConf{
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
NetConf: types.NetConf{
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
CNIVersion: "0.3.1",
|
ver := ver
|
||||||
Name: "testConfig",
|
|
||||||
Type: "ipvlan",
|
|
||||||
},
|
|
||||||
Master: MASTER_NAME,
|
|
||||||
Mode: "l2",
|
|
||||||
MTU: 1500,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ipvlan in other namespace
|
It(fmt.Sprintf("[%s] creates an ipvlan link in a non-default namespace", ver), func() {
|
||||||
targetNs, err := testutils.NewNS()
|
conf := &NetConf{
|
||||||
Expect(err).NotTo(HaveOccurred())
|
NetConf: types.NetConf{
|
||||||
defer targetNs.Close()
|
CNIVersion: ver,
|
||||||
|
Name: "testConfig",
|
||||||
|
Type: "ipvlan",
|
||||||
|
},
|
||||||
|
Master: MASTER_NAME,
|
||||||
|
Mode: "l2",
|
||||||
|
MTU: 1500,
|
||||||
|
}
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
_, err := createIpvlan(conf, "foobar0", targetNS)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
_, err := createIpvlan(conf, "foobar0", targetNs)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
// Make sure ipvlan link exists in the target namespace
|
||||||
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
// Make sure ipvlan link exists in the target namespace
|
link, err := netlink.LinkByName("foobar0")
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
Expect(err).NotTo(HaveOccurred())
|
||||||
defer GinkgoRecover()
|
Expect(link.Attrs().Name).To(Equal("foobar0"))
|
||||||
|
return nil
|
||||||
link, err := netlink.LinkByName("foobar0")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().Name).To(Equal("foobar0"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures an iplvan link with ADD/DEL", func() {
|
|
||||||
const IFNAME = "ipvl0"
|
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "%s",
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`, MASTER_NAME)
|
|
||||||
|
|
||||||
ipvlanAddDelTest(conf, IFNAME, originalNS)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures an iplvan link with ADD/DEL when chained", func() {
|
|
||||||
const IFNAME = "ipvl0"
|
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{
|
|
||||||
"name": "%s"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.1.2.2/24",
|
|
||||||
"gateway": "10.1.2.1",
|
|
||||||
"interface": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"routes": []
|
|
||||||
}
|
|
||||||
}`, MASTER_NAME)
|
|
||||||
|
|
||||||
ipvlanAddDelTest(conf, IFNAME, originalNS)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("deconfigures an unconfigured ipvlan link with DEL", func() {
|
|
||||||
const IFNAME = "ipvl0"
|
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
|
||||||
"cniVersion": "0.3.0",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "%s",
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`, MASTER_NAME)
|
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures a cniVersion 0.4.0 iplvan link with ADD/CHECK/DEL", func() {
|
It(fmt.Sprintf("[%s] configures and deconfigures an iplvan link with ADD/DEL", ver), func() {
|
||||||
const IFNAME = "ipvl0"
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"master": "%s",
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24",
|
||||||
|
"dataDir": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, MASTER_NAME, dataDir)
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
ipvlanAddCheckDelTest(conf, "", originalNS, targetNS)
|
||||||
"cniVersion": "0.4.0",
|
})
|
||||||
"name": "ipvlanTest1",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"master": "%s",
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`, MASTER_NAME)
|
|
||||||
|
|
||||||
ipvlanAddCheckDelTest(conf, "ipvlanTest1", IFNAME, originalNS)
|
if testutils.SpecVersionHasChaining(ver) {
|
||||||
})
|
It(fmt.Sprintf("[%s] configures and deconfigures an iplvan link with ADD/DEL when chained", ver), func() {
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"prevResult": {
|
||||||
|
"interfaces": [
|
||||||
|
{
|
||||||
|
"name": "%s"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ips": [
|
||||||
|
{
|
||||||
|
"version": "4",
|
||||||
|
"address": "10.1.2.2/24",
|
||||||
|
"gateway": "10.1.2.1",
|
||||||
|
"interface": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": []
|
||||||
|
}
|
||||||
|
}`, ver, MASTER_NAME)
|
||||||
|
|
||||||
It("configures and deconfigures a cniVersion 0.4.0 iplvan link with ADD/CHECK/DEL when chained", func() {
|
ipvlanAddCheckDelTest(conf, MASTER_NAME, originalNS, targetNS)
|
||||||
const IFNAME = "ipvl0"
|
})
|
||||||
|
}
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
It(fmt.Sprintf("[%s] deconfigures an unconfigured ipvlan link with DEL", ver), func() {
|
||||||
"cniVersion": "0.4.0",
|
conf := fmt.Sprintf(`{
|
||||||
"name": "ipvlanTest2",
|
"cniVersion": "%s",
|
||||||
"type": "ipvlan",
|
"name": "mynet",
|
||||||
"prevResult": {
|
"type": "ipvlan",
|
||||||
"interfaces": [
|
"master": "%s",
|
||||||
{
|
"ipam": {
|
||||||
"name": "%s"
|
"type": "host-local",
|
||||||
}
|
"subnet": "10.1.2.0/24",
|
||||||
],
|
"dataDir": "%s"
|
||||||
"ips": [
|
}
|
||||||
{
|
}`, ver, MASTER_NAME, dataDir)
|
||||||
"version": "4",
|
|
||||||
"address": "10.1.2.2/24",
|
|
||||||
"gateway": "10.1.2.1",
|
|
||||||
"interface": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"routes": []
|
|
||||||
}
|
|
||||||
}`, MASTER_NAME)
|
|
||||||
|
|
||||||
ipvlanAddCheckDelTest(conf, "ipvlanTest2", IFNAME, originalNS)
|
args := &skel.CmdArgs{
|
||||||
})
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
It("configures and deconfigures a ipvlan link with ADD/DEL, without master config", func() {
|
IfName: "ipvl0",
|
||||||
const IFNAME = "ipvl0"
|
StdinData: []byte(conf),
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ipvlan",
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
// Make MASTER_NAME as default route interface
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(MASTER_NAME)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
err = netlink.LinkSetUp(link)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
var address = &net.IPNet{IP: net.IPv4(192, 0, 0, 1), Mask: net.CIDRMask(24, 32)}
|
|
||||||
var addr = &netlink.Addr{IPNet: address}
|
|
||||||
err = netlink.AddrAdd(link, addr)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// add default gateway into MASTER
|
|
||||||
dst := &net.IPNet{
|
|
||||||
IP: net.IPv4(0, 0, 0, 0),
|
|
||||||
Mask: net.CIDRMask(0, 0),
|
|
||||||
}
|
}
|
||||||
ip := net.IPv4(192, 0, 0, 254)
|
|
||||||
route := netlink.Route{LinkIndex: link.Attrs().Index, Dst: dst, Gw: ip}
|
|
||||||
err = netlink.RouteAdd(&route)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
ipvlanAddDelTest(conf, IFNAME, originalNS)
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
})
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
err := testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] configures and deconfigures a ipvlan link with ADD/DEL, without master config", ver), func() {
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ipvlan",
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24",
|
||||||
|
"dataDir": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, dataDir)
|
||||||
|
|
||||||
|
// Make MASTER_NAME as default route interface
|
||||||
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
link, err := netlink.LinkByName(MASTER_NAME)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
err = netlink.LinkSetUp(link)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var address = &net.IPNet{IP: net.IPv4(192, 0, 0, 1), Mask: net.CIDRMask(24, 32)}
|
||||||
|
var addr = &netlink.Addr{IPNet: address}
|
||||||
|
err = netlink.AddrAdd(link, addr)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// add default gateway into MASTER
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(0, 0, 0, 0),
|
||||||
|
Mask: net.CIDRMask(0, 0),
|
||||||
|
}
|
||||||
|
ip := net.IPv4(192, 0, 0, 254)
|
||||||
|
route := netlink.Route{LinkIndex: link.Attrs().Index, Dst: dst, Gw: ip}
|
||||||
|
err = netlink.RouteAdd(&route)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
ipvlanAddCheckDelTest(conf, MASTER_NAME, originalNS, targetNS)
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
@ -109,12 +109,19 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
// loopback should pass it transparently
|
// loopback should pass it transparently
|
||||||
result = conf.PrevResult
|
result = conf.PrevResult
|
||||||
} else {
|
} else {
|
||||||
loopbackInterface := ¤t.Interface{Name: args.IfName, Mac: "00:00:00:00:00:00", Sandbox: args.Netns}
|
r := ¤t.Result{
|
||||||
r := ¤t.Result{CNIVersion: conf.CNIVersion, Interfaces: []*current.Interface{loopbackInterface}}
|
CNIVersion: conf.CNIVersion,
|
||||||
|
Interfaces: []*current.Interface{
|
||||||
|
¤t.Interface{
|
||||||
|
Name: args.IfName,
|
||||||
|
Mac: "00:00:00:00:00:00",
|
||||||
|
Sandbox: args.Netns,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
if v4Addr != nil {
|
if v4Addr != nil {
|
||||||
r.IPs = append(r.IPs, ¤t.IPConfig{
|
r.IPs = append(r.IPs, ¤t.IPConfig{
|
||||||
Version: "4",
|
|
||||||
Interface: current.Int(0),
|
Interface: current.Int(0),
|
||||||
Address: *v4Addr,
|
Address: *v4Addr,
|
||||||
})
|
})
|
||||||
@ -122,7 +129,6 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
|
|
||||||
if v6Addr != nil {
|
if v6Addr != nil {
|
||||||
r.IPs = append(r.IPs, ¤t.IPConfig{
|
r.IPs = append(r.IPs, ¤t.IPConfig{
|
||||||
Version: "6",
|
|
||||||
Interface: current.Int(0),
|
Interface: current.Int(0),
|
||||||
Address: *v6Addr,
|
Address: *v6Addr,
|
||||||
})
|
})
|
||||||
|
@ -28,6 +28,10 @@ import (
|
|||||||
"github.com/onsi/gomega/gexec"
|
"github.com/onsi/gomega/gexec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func generateConfig(cniVersion string) *strings.Reader {
|
||||||
|
return strings.NewReader(fmt.Sprintf(`{ "name": "loopback-test", "cniVersion": "%s" }`, cniVersion))
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("Loopback", func() {
|
var _ = Describe("Loopback", func() {
|
||||||
var (
|
var (
|
||||||
networkNS ns.NetNS
|
networkNS ns.NetNS
|
||||||
@ -49,7 +53,6 @@ var _ = Describe("Loopback", func() {
|
|||||||
fmt.Sprintf("CNI_ARGS=%s", "none"),
|
fmt.Sprintf("CNI_ARGS=%s", "none"),
|
||||||
fmt.Sprintf("CNI_PATH=%s", "/some/test/path"),
|
fmt.Sprintf("CNI_PATH=%s", "/some/test/path"),
|
||||||
}
|
}
|
||||||
command.Stdin = strings.NewReader(`{ "name": "loopback-test", "cniVersion": "0.1.0" }`)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
@ -57,45 +60,53 @@ var _ = Describe("Loopback", func() {
|
|||||||
Expect(testutils.UnmountNS(networkNS)).To(Succeed())
|
Expect(testutils.UnmountNS(networkNS)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("when given a network namespace", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
It("sets the lo device to UP", func() {
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "ADD"))
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
|
ver := ver
|
||||||
|
|
||||||
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
Context("when given a network namespace", func() {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
It(fmt.Sprintf("[%s] sets the lo device to UP", ver), func() {
|
||||||
|
command.Stdin = generateConfig(ver)
|
||||||
|
command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "ADD"))
|
||||||
|
|
||||||
Eventually(session).Should(gbytes.Say(`{.*}`))
|
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
||||||
Eventually(session).Should(gexec.Exit(0))
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
var lo *net.Interface
|
Eventually(session).Should(gbytes.Say(`{.*}`))
|
||||||
err = networkNS.Do(func(ns.NetNS) error {
|
Eventually(session).Should(gexec.Exit(0))
|
||||||
var err error
|
|
||||||
lo, err = net.InterfaceByName("lo")
|
var lo *net.Interface
|
||||||
return err
|
err = networkNS.Do(func(ns.NetNS) error {
|
||||||
|
var err error
|
||||||
|
lo, err = net.InterfaceByName("lo")
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(lo.Flags & net.FlagUp).To(Equal(net.FlagUp))
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
Expect(lo.Flags & net.FlagUp).To(Equal(net.FlagUp))
|
It(fmt.Sprintf("[%s] sets the lo device to DOWN", ver), func() {
|
||||||
})
|
command.Stdin = generateConfig(ver)
|
||||||
|
command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "DEL"))
|
||||||
|
|
||||||
It("sets the lo device to DOWN", func() {
|
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
||||||
command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "DEL"))
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
Eventually(session).Should(gbytes.Say(``))
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Eventually(session).Should(gexec.Exit(0))
|
||||||
|
|
||||||
Eventually(session).Should(gbytes.Say(``))
|
var lo *net.Interface
|
||||||
Eventually(session).Should(gexec.Exit(0))
|
err = networkNS.Do(func(ns.NetNS) error {
|
||||||
|
var err error
|
||||||
|
lo, err = net.InterfaceByName("lo")
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
var lo *net.Interface
|
Expect(lo.Flags & net.FlagUp).NotTo(Equal(net.FlagUp))
|
||||||
err = networkNS.Do(func(ns.NetNS) error {
|
|
||||||
var err error
|
|
||||||
lo, err = net.InterfaceByName("lo")
|
|
||||||
return err
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
Expect(lo.Flags & net.FlagUp).NotTo(Equal(net.FlagUp))
|
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
@ -256,7 +256,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Assume L2 interface only
|
// Assume L2 interface only
|
||||||
result := ¤t.Result{CNIVersion: cniVersion, Interfaces: []*current.Interface{macvlanInterface}}
|
result := ¤t.Result{
|
||||||
|
CNIVersion: current.ImplementedSpecVersion,
|
||||||
|
Interfaces: []*current.Interface{macvlanInterface},
|
||||||
|
}
|
||||||
|
|
||||||
if isLayer3 {
|
if isLayer3 {
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
@ -301,7 +304,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ipc := range result.IPs {
|
for _, ipc := range result.IPs {
|
||||||
if ipc.Version == "4" {
|
if ipc.Address.IP.To4() != nil {
|
||||||
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
@ -108,7 +108,7 @@ func setupContainerVeth(netns ns.NetNS, ifName string, mtu int, pr *current.Resu
|
|||||||
}
|
}
|
||||||
|
|
||||||
addrBits := 32
|
addrBits := 32
|
||||||
if ipc.Version == "6" {
|
if ipc.Address.IP.To4() == nil {
|
||||||
addrBits = 128
|
addrBits = 128
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ func setupContainerVeth(netns ns.NetNS, ifName string, mtu int, pr *current.Resu
|
|||||||
|
|
||||||
// Send a gratuitous arp for all v4 addresses
|
// Send a gratuitous arp for all v4 addresses
|
||||||
for _, ipc := range pr.IPs {
|
for _, ipc := range pr.IPs {
|
||||||
if ipc.Version == "4" {
|
if ipc.Address.IP.To4() != nil {
|
||||||
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,15 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/020"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/040"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
@ -41,7 +45,7 @@ type Net struct {
|
|||||||
IPAM *allocator.IPAMConfig `json:"ipam"`
|
IPAM *allocator.IPAMConfig `json:"ipam"`
|
||||||
DNS types.DNS `json:"dns"`
|
DNS types.DNS `json:"dns"`
|
||||||
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
|
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
|
||||||
PrevResult current.Result `json:"-"`
|
PrevResult types100.Result `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) {
|
func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) {
|
||||||
@ -87,43 +91,166 @@ func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult typ
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tester interface {
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's IP addresses and MAC address
|
||||||
|
verifyResult(result types.Result, expectedIfName, expectedSandbox string, expectedDNS types.DNS) ([]resultIP, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testerBase struct{}
|
||||||
|
|
||||||
|
type testerV10x testerBase
|
||||||
|
type testerV04x testerBase
|
||||||
|
type testerV03x testerBase
|
||||||
|
type testerV01xOr02x testerBase
|
||||||
|
|
||||||
|
func newTesterByVersion(version string) tester {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(version, "1.0."):
|
||||||
|
return &testerV10x{}
|
||||||
|
case strings.HasPrefix(version, "0.4."):
|
||||||
|
return &testerV04x{}
|
||||||
|
case strings.HasPrefix(version, "0.3."):
|
||||||
|
return &testerV03x{}
|
||||||
|
default:
|
||||||
|
return &testerV01xOr02x{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type resultIP struct {
|
||||||
|
ip string
|
||||||
|
gw string
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's IP addresses and MAC address
|
||||||
|
func (t *testerV10x) verifyResult(result types.Result, expectedIfName, expectedSandbox string, expectedDNS types.DNS) ([]resultIP, string) {
|
||||||
|
r, err := types100.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(r.Interfaces).To(HaveLen(2))
|
||||||
|
Expect(r.Interfaces[0].Name).To(HavePrefix("veth"))
|
||||||
|
Expect(r.Interfaces[0].Mac).To(HaveLen(17))
|
||||||
|
Expect(r.Interfaces[0].Sandbox).To(BeEmpty())
|
||||||
|
Expect(r.Interfaces[1].Name).To(Equal(expectedIfName))
|
||||||
|
Expect(r.Interfaces[1].Sandbox).To(Equal(expectedSandbox))
|
||||||
|
|
||||||
|
Expect(r.DNS).To(Equal(expectedDNS))
|
||||||
|
|
||||||
|
// Grab IPs from container interface
|
||||||
|
ips := []resultIP{}
|
||||||
|
for _, ipc := range r.IPs {
|
||||||
|
if *ipc.Interface == 1 {
|
||||||
|
ips = append(ips, resultIP{
|
||||||
|
ip: ipc.Address.IP.String(),
|
||||||
|
gw: ipc.Gateway.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ips, r.Interfaces[1].Mac
|
||||||
|
}
|
||||||
|
|
||||||
|
func verify0403(result types.Result, expectedIfName, expectedSandbox string, expectedDNS types.DNS) ([]resultIP, string) {
|
||||||
|
r, err := types040.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(r.Interfaces).To(HaveLen(2))
|
||||||
|
Expect(r.Interfaces[0].Name).To(HavePrefix("veth"))
|
||||||
|
Expect(r.Interfaces[0].Mac).To(HaveLen(17))
|
||||||
|
Expect(r.Interfaces[0].Sandbox).To(BeEmpty())
|
||||||
|
Expect(r.Interfaces[1].Name).To(Equal(expectedIfName))
|
||||||
|
Expect(r.Interfaces[1].Sandbox).To(Equal(expectedSandbox))
|
||||||
|
|
||||||
|
Expect(r.DNS).To(Equal(expectedDNS))
|
||||||
|
|
||||||
|
// Grab IPs from container interface
|
||||||
|
ips := []resultIP{}
|
||||||
|
for _, ipc := range r.IPs {
|
||||||
|
if *ipc.Interface == 1 {
|
||||||
|
ips = append(ips, resultIP{
|
||||||
|
ip: ipc.Address.IP.String(),
|
||||||
|
gw: ipc.Gateway.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ips, r.Interfaces[1].Mac
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's IP addresses and MAC address
|
||||||
|
func (t *testerV04x) verifyResult(result types.Result, expectedIfName, expectedSandbox string, expectedDNS types.DNS) ([]resultIP, string) {
|
||||||
|
return verify0403(result, expectedIfName, expectedSandbox, expectedDNS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's IP addresses and MAC address
|
||||||
|
func (t *testerV03x) verifyResult(result types.Result, expectedIfName, expectedSandbox string, expectedDNS types.DNS) ([]resultIP, string) {
|
||||||
|
return verify0403(result, expectedIfName, expectedSandbox, expectedDNS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's IP addresses and MAC address
|
||||||
|
func (t *testerV01xOr02x) verifyResult(result types.Result, expectedIfName, expectedSandbox string, expectedDNS types.DNS) ([]resultIP, string) {
|
||||||
|
r, err := types020.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
ips := []resultIP{}
|
||||||
|
if r.IP4 != nil && r.IP4.IP.IP != nil {
|
||||||
|
ips = append(ips, resultIP{
|
||||||
|
ip: r.IP4.IP.IP.String(),
|
||||||
|
gw: r.IP4.Gateway.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if r.IP6 != nil && r.IP6.IP.IP != nil {
|
||||||
|
ips = append(ips, resultIP{
|
||||||
|
ip: r.IP6.IP.IP.String(),
|
||||||
|
gw: r.IP6.Gateway.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0.2 and earlier don't return MAC address
|
||||||
|
return ips, ""
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("ptp Operations", func() {
|
var _ = Describe("ptp Operations", func() {
|
||||||
var originalNS ns.NetNS
|
var originalNS, targetNS ns.NetNS
|
||||||
|
var dataDir string
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
// Create a new NetNS so we don't modify the host
|
// Create a new NetNS so we don't modify the host
|
||||||
var err error
|
var err error
|
||||||
originalNS, err = testutils.NewNS()
|
originalNS, err = testutils.NewNS()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
targetNS, err = testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
dataDir, err = ioutil.TempDir("", "ptp_test")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||||
Expect(originalNS.Close()).To(Succeed())
|
Expect(originalNS.Close()).To(Succeed())
|
||||||
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
||||||
|
Expect(targetNS.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(targetNS)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
doTest := func(conf string, numIPs int, expectedDNSConf types.DNS) {
|
doTest := func(conf, cniVersion string, numIPs int, expectedDNSConf types.DNS, targetNS ns.NetNS) {
|
||||||
const IFNAME = "ptp0"
|
const IFNAME = "ptp0"
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
args := &skel.CmdArgs{
|
||||||
ContainerID: "dummy",
|
ContainerID: "dummy",
|
||||||
Netns: targetNs.Path(),
|
Netns: targetNS.Path(),
|
||||||
IfName: IFNAME,
|
IfName: IFNAME,
|
||||||
StdinData: []byte(conf),
|
StdinData: []byte(conf),
|
||||||
}
|
}
|
||||||
|
|
||||||
var resI types.Result
|
var result types.Result
|
||||||
var res *current.Result
|
|
||||||
|
|
||||||
// Execute the plugin with the ADD command, creating the veth endpoints
|
// Execute the plugin with the ADD command, creating the veth endpoints
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
resI, _, err = testutils.CmdAddWithArgs(args, func() error {
|
var err error
|
||||||
|
result, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||||
return cmdAdd(args)
|
return cmdAdd(args)
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
@ -131,32 +258,25 @@ var _ = Describe("ptp Operations", func() {
|
|||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
res, err = current.NewResultFromResult(resI)
|
t := newTesterByVersion(cniVersion)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
ips, mac := t.verifyResult(result, IFNAME, targetNS.Path(), expectedDNSConf)
|
||||||
|
Expect(len(ips)).To(Equal(numIPs))
|
||||||
|
|
||||||
// Make sure ptp link exists in the target namespace
|
// Make sure ptp link exists in the target namespace
|
||||||
// Then, ping the gateway
|
// Then, ping the gateway
|
||||||
seenIPs := 0
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
|
|
||||||
wantMac := ""
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
link, err := netlink.LinkByName(IFNAME)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
wantMac = link.Attrs().HardwareAddr.String()
|
if mac != "" {
|
||||||
|
Expect(mac).To(Equal(link.Attrs().HardwareAddr.String()))
|
||||||
|
}
|
||||||
|
|
||||||
for _, ipc := range res.IPs {
|
for _, ipc := range ips {
|
||||||
if *ipc.Interface != 1 {
|
fmt.Fprintln(GinkgoWriter, "ping", ipc.ip, "->", ipc.gw)
|
||||||
continue
|
if err := testutils.Ping(ipc.ip, ipc.gw, 30); err != nil {
|
||||||
}
|
return fmt.Errorf("ping %s -> %s failed: %s", ipc.ip, ipc.gw, err)
|
||||||
seenIPs += 1
|
|
||||||
saddr := ipc.Address.IP.String()
|
|
||||||
daddr := ipc.Gateway.String()
|
|
||||||
fmt.Fprintln(GinkgoWriter, "ping", saddr, "->", daddr)
|
|
||||||
|
|
||||||
if err := testutils.Ping(saddr, daddr, (ipc.Version == "6"), 30); err != nil {
|
|
||||||
return fmt.Errorf("ping %s -> %s failed: %s", saddr, daddr, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,121 +284,6 @@ var _ = Describe("ptp Operations", func() {
|
|||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
Expect(seenIPs).To(Equal(numIPs))
|
|
||||||
|
|
||||||
// make sure the interfaces are correct
|
|
||||||
Expect(res.Interfaces).To(HaveLen(2))
|
|
||||||
|
|
||||||
Expect(res.Interfaces[0].Name).To(HavePrefix("veth"))
|
|
||||||
Expect(res.Interfaces[0].Mac).To(HaveLen(17))
|
|
||||||
Expect(res.Interfaces[0].Sandbox).To(BeEmpty())
|
|
||||||
|
|
||||||
Expect(res.Interfaces[1].Name).To(Equal(IFNAME))
|
|
||||||
Expect(res.Interfaces[1].Mac).To(Equal(wantMac))
|
|
||||||
Expect(res.Interfaces[1].Sandbox).To(Equal(targetNs.Path()))
|
|
||||||
|
|
||||||
// make sure DNS is correct
|
|
||||||
Expect(res.DNS).To(Equal(expectedDNSConf))
|
|
||||||
|
|
||||||
// Call the plugins with the DEL command, deleting the veth endpoints
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
err := testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure ptp link has been deleted
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(link).To(BeNil())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
|
|
||||||
doTestv4 := func(conf string, netName string, numIPs int) {
|
|
||||||
const IFNAME = "ptp0"
|
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
var resI types.Result
|
|
||||||
var res *current.Result
|
|
||||||
|
|
||||||
// Execute the plugin with the ADD command, creating the veth endpoints
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
resI, _, err = testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
res, err = current.NewResultFromResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure ptp link exists in the target namespace
|
|
||||||
// Then, ping the gateway
|
|
||||||
seenIPs := 0
|
|
||||||
|
|
||||||
wantMac := ""
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
wantMac = link.Attrs().HardwareAddr.String()
|
|
||||||
|
|
||||||
for _, ipc := range res.IPs {
|
|
||||||
if *ipc.Interface != 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seenIPs += 1
|
|
||||||
saddr := ipc.Address.IP.String()
|
|
||||||
daddr := ipc.Gateway.String()
|
|
||||||
fmt.Fprintln(GinkgoWriter, "ping", saddr, "->", daddr)
|
|
||||||
|
|
||||||
if err := testutils.Ping(saddr, daddr, (ipc.Version == "6"), 30); err != nil {
|
|
||||||
return fmt.Errorf("ping %s -> %s failed: %s", saddr, daddr, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
Expect(seenIPs).To(Equal(numIPs))
|
|
||||||
|
|
||||||
// make sure the interfaces are correct
|
|
||||||
Expect(res.Interfaces).To(HaveLen(2))
|
|
||||||
|
|
||||||
Expect(res.Interfaces[0].Name).To(HavePrefix("veth"))
|
|
||||||
Expect(res.Interfaces[0].Mac).To(HaveLen(17))
|
|
||||||
Expect(res.Interfaces[0].Sandbox).To(BeEmpty())
|
|
||||||
|
|
||||||
Expect(res.Interfaces[1].Name).To(Equal(IFNAME))
|
|
||||||
Expect(res.Interfaces[1].Mac).To(Equal(wantMac))
|
|
||||||
Expect(res.Interfaces[1].Sandbox).To(Equal(targetNs.Path()))
|
|
||||||
|
|
||||||
// call CmdCheck
|
// call CmdCheck
|
||||||
n := &Net{}
|
n := &Net{}
|
||||||
err = json.Unmarshal([]byte(conf), &n)
|
err = json.Unmarshal([]byte(conf), &n)
|
||||||
@ -287,8 +292,7 @@ var _ = Describe("ptp Operations", func() {
|
|||||||
n.IPAM, _, err = allocator.LoadIPAMConfig([]byte(conf), "")
|
n.IPAM, _, err = allocator.LoadIPAMConfig([]byte(conf), "")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
cniVersion := "0.4.0"
|
newConf, err := buildOneConfig(n.Name, cniVersion, n, result)
|
||||||
newConf, err := buildOneConfig(netName, cniVersion, n, res)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
confString, err := json.Marshal(newConf)
|
confString, err := json.Marshal(newConf)
|
||||||
@ -299,11 +303,13 @@ var _ = Describe("ptp Operations", func() {
|
|||||||
// CNI Check host-device in the target namespace
|
// CNI Check host-device in the target namespace
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
var err error
|
return testutils.CmdCheckWithArgs(args, func() error { return cmdCheck(args) })
|
||||||
err = testutils.CmdCheckWithArgs(args, func() error { return cmdCheck(args) })
|
|
||||||
return err
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
if testutils.SpecVersionHasCHECK(cniVersion) {
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
} else {
|
||||||
|
Expect(err).To(MatchError("config version does not allow CHECK"))
|
||||||
|
}
|
||||||
|
|
||||||
args.StdinData = []byte(conf)
|
args.StdinData = []byte(conf)
|
||||||
|
|
||||||
@ -320,7 +326,7 @@ var _ = Describe("ptp Operations", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// Make sure ptp link has been deleted
|
// Make sure ptp link has been deleted
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
link, err := netlink.LinkByName(IFNAME)
|
||||||
@ -331,227 +337,200 @@ var _ = Describe("ptp Operations", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
It("configures and deconfigures a ptp link with ADD/DEL", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
dnsConf := types.DNS{
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
Nameservers: []string{"10.1.2.123"},
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
Domain: "some.domain.test",
|
ver := ver
|
||||||
Search: []string{"search.test"},
|
|
||||||
Options: []string{"option1:foo"},
|
|
||||||
}
|
|
||||||
dnsConfBytes, err := json.Marshal(dnsConf)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
It(fmt.Sprintf("[%s] configures and deconfigures a ptp link with ADD/DEL", ver), func() {
|
||||||
"cniVersion": "0.3.1",
|
dnsConf := types.DNS{
|
||||||
"name": "mynet",
|
Nameservers: []string{"10.1.2.123"},
|
||||||
"type": "ptp",
|
Domain: "some.domain.test",
|
||||||
"ipMasq": true,
|
Search: []string{"search.test"},
|
||||||
"mtu": 5000,
|
Options: []string{"option1:foo"},
|
||||||
"ipam": {
|
}
|
||||||
"type": "host-local",
|
dnsConfBytes, err := json.Marshal(dnsConf)
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
},
|
|
||||||
"dns": %s
|
|
||||||
}`, string(dnsConfBytes))
|
|
||||||
|
|
||||||
doTest(conf, 1, dnsConf)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures a dual-stack ptp link with ADD/DEL", func() {
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"mtu": 5000,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"ranges": [
|
|
||||||
[{ "subnet": "10.1.2.0/24"}],
|
|
||||||
[{ "subnet": "2001:db8:1::0/66"}]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
doTest(conf, 2, types.DNS{})
|
|
||||||
})
|
|
||||||
|
|
||||||
It("does not override IPAM DNS settings if no DNS settings provided", func() {
|
|
||||||
ipamDNSConf := types.DNS{
|
|
||||||
Nameservers: []string{"10.1.2.123"},
|
|
||||||
Domain: "some.domain.test",
|
|
||||||
Search: []string{"search.test"},
|
|
||||||
Options: []string{"option1:foo"},
|
|
||||||
}
|
|
||||||
resolvConfPath, err := testutils.TmpResolvConf(ipamDNSConf)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer os.RemoveAll(resolvConfPath)
|
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"mtu": 5000,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24",
|
|
||||||
"resolvConf": "%s"
|
|
||||||
}
|
|
||||||
}`, resolvConfPath)
|
|
||||||
|
|
||||||
doTest(conf, 1, ipamDNSConf)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("overrides IPAM DNS settings if any DNS settings provided", func() {
|
|
||||||
ipamDNSConf := types.DNS{
|
|
||||||
Nameservers: []string{"10.1.2.123"},
|
|
||||||
Domain: "some.domain.test",
|
|
||||||
Search: []string{"search.test"},
|
|
||||||
Options: []string{"option1:foo"},
|
|
||||||
}
|
|
||||||
resolvConfPath, err := testutils.TmpResolvConf(ipamDNSConf)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer os.RemoveAll(resolvConfPath)
|
|
||||||
|
|
||||||
for _, ptpDNSConf := range []types.DNS{
|
|
||||||
{
|
|
||||||
Nameservers: []string{"10.1.2.234"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Domain: "someother.domain.test",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Search: []string{"search.elsewhere.test"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Options: []string{"option2:bar"},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
dnsConfBytes, err := json.Marshal(ptpDNSConf)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
conf := fmt.Sprintf(`{
|
||||||
"cniVersion": "0.3.1",
|
"cniVersion": "%s",
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"type": "ptp",
|
"type": "ptp",
|
||||||
"ipMasq": true,
|
"ipMasq": true,
|
||||||
"mtu": 5000,
|
"mtu": 5000,
|
||||||
"ipam": {
|
"ipam": {
|
||||||
"type": "host-local",
|
"type": "host-local",
|
||||||
"subnet": "10.1.2.0/24",
|
"subnet": "10.1.2.0/24",
|
||||||
"resolvConf": "%s"
|
"dataDir": "%s"
|
||||||
},
|
},
|
||||||
"dns": %s
|
"dns": %s
|
||||||
}`, resolvConfPath, string(dnsConfBytes))
|
}`, ver, dataDir, string(dnsConfBytes))
|
||||||
|
|
||||||
doTest(conf, 1, ptpDNSConf)
|
doTest(conf, ver, 1, dnsConf, targetNS)
|
||||||
}
|
})
|
||||||
})
|
|
||||||
|
|
||||||
It("overrides IPAM DNS settings if any empty list DNS settings provided", func() {
|
It(fmt.Sprintf("[%s] configures and deconfigures a dual-stack ptp link with ADD/DEL", ver), func() {
|
||||||
ipamDNSConf := types.DNS{
|
conf := fmt.Sprintf(`{
|
||||||
Nameservers: []string{"10.1.2.123"},
|
"cniVersion": "%s",
|
||||||
Domain: "some.domain.test",
|
"name": "mynet",
|
||||||
Search: []string{"search.test"},
|
"type": "ptp",
|
||||||
Options: []string{"option1:foo"},
|
"ipMasq": true,
|
||||||
}
|
"mtu": 5000,
|
||||||
resolvConfPath, err := testutils.TmpResolvConf(ipamDNSConf)
|
"ipam": {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
"type": "host-local",
|
||||||
defer os.RemoveAll(resolvConfPath)
|
"ranges": [
|
||||||
|
[{ "subnet": "10.1.2.0/24"}],
|
||||||
|
[{ "subnet": "2001:db8:1::0/66"}]
|
||||||
|
],
|
||||||
|
"dataDir": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, dataDir)
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
doTest(conf, ver, 2, types.DNS{}, targetNS)
|
||||||
"cniVersion": "0.3.1",
|
})
|
||||||
"name": "mynet",
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"mtu": 5000,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24",
|
|
||||||
"resolvConf": "%s"
|
|
||||||
},
|
|
||||||
"dns": {
|
|
||||||
"nameservers": [],
|
|
||||||
"search": [],
|
|
||||||
"options": []
|
|
||||||
}
|
|
||||||
}`, resolvConfPath)
|
|
||||||
|
|
||||||
doTest(conf, 1, types.DNS{})
|
It(fmt.Sprintf("[%s] does not override IPAM DNS settings if no DNS settings provided", ver), func() {
|
||||||
})
|
ipamDNSConf := types.DNS{
|
||||||
|
Nameservers: []string{"10.1.2.123"},
|
||||||
|
Domain: "some.domain.test",
|
||||||
|
Search: []string{"search.test"},
|
||||||
|
Options: []string{"option1:foo"},
|
||||||
|
}
|
||||||
|
resolvConfPath, err := testutils.TmpResolvConf(ipamDNSConf)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer os.RemoveAll(resolvConfPath)
|
||||||
|
|
||||||
It("deconfigures an unconfigured ptp link with DEL", func() {
|
conf := fmt.Sprintf(`{
|
||||||
const IFNAME = "ptp0"
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ptp",
|
||||||
|
"ipMasq": true,
|
||||||
|
"mtu": 5000,
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24",
|
||||||
|
"resolvConf": "%s",
|
||||||
|
"dataDir": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, resolvConfPath, dataDir)
|
||||||
|
|
||||||
conf := `{
|
doTest(conf, ver, 1, ipamDNSConf, targetNS)
|
||||||
"cniVersion": "0.3.0",
|
})
|
||||||
"name": "mynet",
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"mtu": 5000,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
It(fmt.Sprintf("[%s] overrides IPAM DNS settings if any DNS settings provided", ver), func() {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
ipamDNSConf := types.DNS{
|
||||||
defer targetNs.Close()
|
Nameservers: []string{"10.1.2.123"},
|
||||||
|
Domain: "some.domain.test",
|
||||||
|
Search: []string{"search.test"},
|
||||||
|
Options: []string{"option1:foo"},
|
||||||
|
}
|
||||||
|
resolvConfPath, err := testutils.TmpResolvConf(ipamDNSConf)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer os.RemoveAll(resolvConfPath)
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
for _, ptpDNSConf := range []types.DNS{
|
||||||
ContainerID: "dummy",
|
{
|
||||||
Netns: targetNs.Path(),
|
Nameservers: []string{"10.1.2.234"},
|
||||||
IfName: IFNAME,
|
},
|
||||||
StdinData: []byte(conf),
|
{
|
||||||
}
|
Domain: "someother.domain.test",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Search: []string{"search.elsewhere.test"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Options: []string{"option2:bar"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
dnsConfBytes, err := json.Marshal(ptpDNSConf)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// Call the plugins with the DEL command. It should not error even though the veth doesn't exist.
|
conf := fmt.Sprintf(`{
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
"cniVersion": "%s",
|
||||||
defer GinkgoRecover()
|
"name": "mynet",
|
||||||
|
"type": "ptp",
|
||||||
|
"ipMasq": true,
|
||||||
|
"mtu": 5000,
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24",
|
||||||
|
"resolvConf": "%s",
|
||||||
|
"dataDir": "%s"
|
||||||
|
},
|
||||||
|
"dns": %s
|
||||||
|
}`, ver, resolvConfPath, dataDir, string(dnsConfBytes))
|
||||||
|
|
||||||
err := testutils.CmdDelWithArgs(args, func() error {
|
doTest(conf, ver, 1, ptpDNSConf, targetNS)
|
||||||
return cmdDel(args)
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] overrides IPAM DNS settings if any empty list DNS settings provided", ver), func() {
|
||||||
|
ipamDNSConf := types.DNS{
|
||||||
|
Nameservers: []string{"10.1.2.123"},
|
||||||
|
Domain: "some.domain.test",
|
||||||
|
Search: []string{"search.test"},
|
||||||
|
Options: []string{"option1:foo"},
|
||||||
|
}
|
||||||
|
resolvConfPath, err := testutils.TmpResolvConf(ipamDNSConf)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer os.RemoveAll(resolvConfPath)
|
||||||
|
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ptp",
|
||||||
|
"ipMasq": true,
|
||||||
|
"mtu": 5000,
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24",
|
||||||
|
"dataDir": "%s",
|
||||||
|
"resolvConf": "%s"
|
||||||
|
},
|
||||||
|
"dns": {
|
||||||
|
"nameservers": [],
|
||||||
|
"search": [],
|
||||||
|
"options": []
|
||||||
|
}
|
||||||
|
}`, ver, dataDir, resolvConfPath)
|
||||||
|
|
||||||
|
doTest(conf, ver, 1, types.DNS{}, targetNS)
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] deconfigures an unconfigured ptp link with DEL", ver), func() {
|
||||||
|
const IFNAME = "ptp0"
|
||||||
|
|
||||||
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "ptp",
|
||||||
|
"ipMasq": true,
|
||||||
|
"mtu": 5000,
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"dataDir": "%s",
|
||||||
|
"subnet": "10.1.2.0/24"
|
||||||
|
}
|
||||||
|
}`, ver, dataDir)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the plugins with the DEL command. It should not error even though the veth doesn't exist.
|
||||||
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
err := testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
}
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures a CNI V4 ptp link with ADD/DEL", func() {
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.4.0",
|
|
||||||
"name": "ptpNetv4",
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"mtu": 5000,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
doTestv4(conf, "ptpNetv4", 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures a CNI V4 dual-stack ptp link with ADD/DEL", func() {
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.4.0",
|
|
||||||
"name": "ptpNetv4ds",
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"mtu": 5000,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"ranges": [
|
|
||||||
[{ "subnet": "10.1.2.0/24"}],
|
|
||||||
[{ "subnet": "2001:db8:1::0/66"}]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
doTestv4(conf, "ptpNetv4ds", 2)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
|
@ -17,12 +17,17 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/020"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/040"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
@ -45,7 +50,7 @@ type Net struct {
|
|||||||
IPAM *allocator.IPAMConfig `json:"ipam"`
|
IPAM *allocator.IPAMConfig `json:"ipam"`
|
||||||
DNS types.DNS `json:"dns"`
|
DNS types.DNS `json:"dns"`
|
||||||
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
|
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
|
||||||
PrevResult current.Result `json:"-"`
|
PrevResult types100.Result `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) {
|
func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) {
|
||||||
@ -91,14 +96,90 @@ func buildOneConfig(netName string, cniVersion string, orig *Net, prevResult typ
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tester interface {
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
verifyResult(result types.Result, name string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type testerBase struct{}
|
||||||
|
|
||||||
|
type testerV10x testerBase
|
||||||
|
type testerV04x testerBase
|
||||||
|
type testerV03x testerBase
|
||||||
|
type testerV01xOr02x testerBase
|
||||||
|
|
||||||
|
func newTesterByVersion(version string) tester {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(version, "1.0."):
|
||||||
|
return &testerV10x{}
|
||||||
|
case strings.HasPrefix(version, "0.4."):
|
||||||
|
return &testerV04x{}
|
||||||
|
case strings.HasPrefix(version, "0.3."):
|
||||||
|
return &testerV03x{}
|
||||||
|
default:
|
||||||
|
return &testerV01xOr02x{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
func (t *testerV10x) verifyResult(result types.Result, name string) string {
|
||||||
|
r, err := types100.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(r.Interfaces)).To(Equal(1))
|
||||||
|
Expect(r.Interfaces[0].Name).To(Equal(name))
|
||||||
|
Expect(len(r.IPs)).To(Equal(1))
|
||||||
|
|
||||||
|
return r.Interfaces[0].Mac
|
||||||
|
}
|
||||||
|
|
||||||
|
func verify0403(result types.Result, name string) string {
|
||||||
|
r, err := types040.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(r.Interfaces)).To(Equal(1))
|
||||||
|
Expect(r.Interfaces[0].Name).To(Equal(name))
|
||||||
|
Expect(len(r.IPs)).To(Equal(1))
|
||||||
|
|
||||||
|
return r.Interfaces[0].Mac
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
func (t *testerV04x) verifyResult(result types.Result, name string) string {
|
||||||
|
return verify0403(result, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
func (t *testerV03x) verifyResult(result types.Result, name string) string {
|
||||||
|
return verify0403(result, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyResult minimally verifies the Result and returns the interface's MAC address
|
||||||
|
func (t *testerV01xOr02x) verifyResult(result types.Result, name string) string {
|
||||||
|
r, err := types020.GetResult(result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(r.IP4.IP.IP).NotTo(BeNil())
|
||||||
|
Expect(r.IP6).To(BeNil())
|
||||||
|
|
||||||
|
// 0.2 and earlier don't return MAC address
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("vlan Operations", func() {
|
var _ = Describe("vlan Operations", func() {
|
||||||
var originalNS ns.NetNS
|
var originalNS, targetNS ns.NetNS
|
||||||
|
var dataDir string
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
// Create a new NetNS so we don't modify the host
|
// Create a new NetNS so we don't modify the host
|
||||||
var err error
|
var err error
|
||||||
originalNS, err = testutils.NewNS()
|
originalNS, err = testutils.NewNS()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
targetNS, err = testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
dataDir, err = ioutil.TempDir("", "vlan_test")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
@ -120,376 +201,290 @@ var _ = Describe("vlan Operations", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||||
Expect(originalNS.Close()).To(Succeed())
|
Expect(originalNS.Close()).To(Succeed())
|
||||||
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
||||||
|
Expect(targetNS.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(targetNS)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("creates an vlan link in a non-default namespace with given MTU", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
conf := &NetConf{
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
NetConf: types.NetConf{
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
CNIVersion: "0.3.0",
|
ver := ver
|
||||||
Name: "testConfig",
|
|
||||||
Type: "vlan",
|
|
||||||
},
|
|
||||||
Master: MASTER_NAME,
|
|
||||||
VlanId: 33,
|
|
||||||
MTU: 1500,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create vlan in other namespace
|
It(fmt.Sprintf("[%s] creates an vlan link in a non-default namespace with given MTU", ver), func() {
|
||||||
targetNs, err := testutils.NewNS()
|
conf := &NetConf{
|
||||||
Expect(err).NotTo(HaveOccurred())
|
NetConf: types.NetConf{
|
||||||
defer targetNs.Close()
|
CNIVersion: ver,
|
||||||
|
Name: "testConfig",
|
||||||
|
Type: "vlan",
|
||||||
|
},
|
||||||
|
Master: MASTER_NAME,
|
||||||
|
VlanId: 33,
|
||||||
|
MTU: 1500,
|
||||||
|
}
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
// Create vlan in other namespace
|
||||||
defer GinkgoRecover()
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
_, err := createVlan(conf, "foobar0", targetNs)
|
_, err := createVlan(conf, "foobar0", targetNS)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
return nil
|
||||||
})
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure vlan link exists in the target namespace
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName("foobar0")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().Name).To(Equal("foobar0"))
|
|
||||||
Expect(link.Attrs().MTU).To(Equal(1500))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("creates an vlan link in a non-default namespace with master's MTU", func() {
|
|
||||||
conf := &NetConf{
|
|
||||||
NetConf: types.NetConf{
|
|
||||||
CNIVersion: "0.3.0",
|
|
||||||
Name: "testConfig",
|
|
||||||
Type: "vlan",
|
|
||||||
},
|
|
||||||
Master: MASTER_NAME,
|
|
||||||
VlanId: 33,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create vlan in other namespace
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
m, err := netlink.LinkByName(MASTER_NAME)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
err = netlink.LinkSetMTU(m, 1200)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
_, err = createVlan(conf, "foobar0", targetNs)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure vlan link exists in the target namespace
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName("foobar0")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().Name).To(Equal("foobar0"))
|
|
||||||
Expect(link.Attrs().MTU).To(Equal(1200))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures an vlan link with ADD/DEL", func() {
|
|
||||||
const IFNAME = "eth0"
|
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
|
||||||
"cniVersion": "0.3.0",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "vlan",
|
|
||||||
"master": "%s",
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`, MASTER_NAME)
|
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result *current.Result
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
result, err = current.GetResult(r)
|
// Make sure vlan link exists in the target namespace
|
||||||
Expect(err).NotTo(HaveOccurred())
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
Expect(len(result.Interfaces)).To(Equal(1))
|
link, err := netlink.LinkByName("foobar0")
|
||||||
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(len(result.IPs)).To(Equal(1))
|
Expect(link.Attrs().Name).To(Equal("foobar0"))
|
||||||
return nil
|
Expect(link.Attrs().MTU).To(Equal(1500))
|
||||||
})
|
return nil
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure vlan link exists in the target namespace
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
|
||||||
|
|
||||||
hwaddr, err := net.ParseMAC(result.Interfaces[0].Mac)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
|
||||||
|
|
||||||
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(addrs)).To(Equal(1))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure vlan link has been deleted
|
It(fmt.Sprintf("[%s] creates an vlan link in a non-default namespace with master's MTU", ver), func() {
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
conf := &NetConf{
|
||||||
defer GinkgoRecover()
|
NetConf: types.NetConf{
|
||||||
|
CNIVersion: ver,
|
||||||
|
Name: "testConfig",
|
||||||
|
Type: "vlan",
|
||||||
|
},
|
||||||
|
Master: MASTER_NAME,
|
||||||
|
VlanId: 33,
|
||||||
|
}
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
// Create vlan in other namespace
|
||||||
Expect(err).To(HaveOccurred())
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
Expect(link).To(BeNil())
|
defer GinkgoRecover()
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// DEL can be called multiple times, make sure no error is returned
|
m, err := netlink.LinkByName(MASTER_NAME)
|
||||||
// if the device is already removed.
|
Expect(err).NotTo(HaveOccurred())
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = netlink.LinkSetMTU(m, 1200)
|
||||||
defer GinkgoRecover()
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
_, err = createVlan(conf, "foobar0", targetNS)
|
||||||
return cmdDel(args)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
return nil
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("configures and deconfigures an CNI V4 vlan link with ADD/CHECK/DEL", func() {
|
|
||||||
const IFNAME = "eth0"
|
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
|
||||||
"cniVersion": "0.4.0",
|
|
||||||
"name": "vlanTestv4",
|
|
||||||
"type": "vlan",
|
|
||||||
"master": "%s",
|
|
||||||
"vlanId": 1234,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`, MASTER_NAME)
|
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result *current.Result
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
result, err = current.GetResult(r)
|
// Make sure vlan link exists in the target namespace
|
||||||
Expect(err).NotTo(HaveOccurred())
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
Expect(len(result.Interfaces)).To(Equal(1))
|
link, err := netlink.LinkByName("foobar0")
|
||||||
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(len(result.IPs)).To(Equal(1))
|
Expect(link.Attrs().Name).To(Equal("foobar0"))
|
||||||
return nil
|
Expect(link.Attrs().MTU).To(Equal(1200))
|
||||||
})
|
return nil
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure vlan link exists in the target namespace
|
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
|
||||||
|
|
||||||
hwaddr, err := net.ParseMAC(result.Interfaces[0].Mac)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
|
||||||
|
|
||||||
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(addrs)).To(Equal(1))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// call CmdCheck
|
|
||||||
n := &Net{}
|
|
||||||
err = json.Unmarshal([]byte(conf), &n)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
n.IPAM, _, err = allocator.LoadIPAMConfig([]byte(conf), "")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
cniVersion := "0.4.0"
|
|
||||||
newConf, err := buildOneConfig("vlanTestv4", cniVersion, n, result)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
confString, err := json.Marshal(newConf)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
args.StdinData = confString
|
|
||||||
|
|
||||||
// CNI Check host-device in the target namespace
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
var err error
|
|
||||||
err = testutils.CmdCheckWithArgs(args, func() error { return cmdCheck(args) })
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
args.StdinData = []byte(conf)
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Make sure vlan link has been deleted
|
It(fmt.Sprintf("[%s] configures and deconfigures a vlan link with ADD/CHECK/DEL", ver), func() {
|
||||||
err = targetNs.Do(func(ns.NetNS) error {
|
const IFNAME = "eth0"
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
link, err := netlink.LinkByName(IFNAME)
|
conf := fmt.Sprintf(`{
|
||||||
Expect(err).To(HaveOccurred())
|
"cniVersion": "%s",
|
||||||
Expect(link).To(BeNil())
|
"name": "vlanTestv4",
|
||||||
return nil
|
"type": "vlan",
|
||||||
})
|
"master": "%s",
|
||||||
Expect(err).NotTo(HaveOccurred())
|
"vlanId": 1234,
|
||||||
})
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24",
|
||||||
|
"dataDir": "%s"
|
||||||
|
}
|
||||||
|
}`, ver, MASTER_NAME, dataDir)
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
|
||||||
|
t := newTesterByVersion(ver)
|
||||||
|
|
||||||
|
var result types.Result
|
||||||
|
var macAddress string
|
||||||
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
result, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
macAddress = t.verifyResult(result, IFNAME)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Make sure vlan link exists in the target namespace
|
||||||
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
link, err := netlink.LinkByName(IFNAME)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
||||||
|
|
||||||
|
if macAddress != "" {
|
||||||
|
hwaddr, err := net.ParseMAC(macAddress)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(len(addrs)).To(Equal(1))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// call CmdCheck
|
||||||
|
n := &Net{}
|
||||||
|
err = json.Unmarshal([]byte(conf), &n)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
n.IPAM, _, err = allocator.LoadIPAMConfig([]byte(conf), "")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
newConf, err := buildOneConfig("vlanTestv4", ver, n, result)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
confString, err := json.Marshal(newConf)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
args.StdinData = confString
|
||||||
|
|
||||||
|
// CNI Check host-device in the target namespace
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
return testutils.CmdCheckWithArgs(args, func() error { return cmdCheck(args) })
|
||||||
|
})
|
||||||
|
if testutils.SpecVersionHasCHECK(ver) {
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
} else {
|
||||||
|
Expect(err).To(MatchError("config version does not allow CHECK"))
|
||||||
|
}
|
||||||
|
|
||||||
|
args.StdinData = []byte(conf)
|
||||||
|
|
||||||
Describe("fails to create vlan link with invalid MTU", func() {
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "mynet",
|
|
||||||
"type": "vlan",
|
|
||||||
"master": "%s",
|
|
||||||
"mtu": %d,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "10.1.2.0/24"
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
BeforeEach(func() {
|
|
||||||
var err error
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
|
|
||||||
// set master link's MTU to 1500
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
link, err := netlink.LinkByName(MASTER_NAME)
|
return cmdDel(args)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
})
|
||||||
err = netlink.LinkSetMTU(link, 1500)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Make sure vlan link has been deleted
|
||||||
|
err = targetNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
link, err := netlink.LinkByName(IFNAME)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(link).To(BeNil())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// DEL can be called multiple times, make sure no error is returned
|
||||||
|
// if the device is already removed.
|
||||||
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("fails to create vlan link with greater MTU than master interface", func() {
|
Describe("fails to create vlan link with invalid MTU", func() {
|
||||||
var err error
|
const confFmt = `{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "mynet",
|
||||||
|
"type": "vlan",
|
||||||
|
"master": "%s",
|
||||||
|
"mtu": %d,
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "10.1.2.0/24",
|
||||||
|
"dataDir": "%s"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
BeforeEach(func() {
|
||||||
ContainerID: "dummy",
|
var err error
|
||||||
Netns: "/var/run/netns/test",
|
err = originalNS.Do(func(ns.NetNS) error {
|
||||||
IfName: "eth0",
|
defer GinkgoRecover()
|
||||||
StdinData: []byte(fmt.Sprintf(conf, MASTER_NAME, 1600)),
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = originalNS.Do(func(netNS ns.NetNS) error {
|
// set master link's MTU to 1500
|
||||||
defer GinkgoRecover()
|
link, err := netlink.LinkByName(MASTER_NAME)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
err = netlink.LinkSetMTU(link, 1500)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
_, _, err = testutils.CmdAddWithArgs(args, func() error {
|
return nil
|
||||||
return cmdAdd(args)
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] fails to create vlan link with greater MTU than master interface", ver), func() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: "/var/run/netns/test",
|
||||||
|
IfName: "eth0",
|
||||||
|
StdinData: []byte(fmt.Sprintf(confFmt, ver, MASTER_NAME, 1600, dataDir)),
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = originalNS.Do(func(netNS ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
_, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).To(Equal(fmt.Errorf("invalid MTU 1600, must be [0, master MTU(1500)]")))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] fails to create vlan link with negative MTU", ver), func() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: "/var/run/netns/test",
|
||||||
|
IfName: "eth0",
|
||||||
|
StdinData: []byte(fmt.Sprintf(confFmt, ver, MASTER_NAME, -100, dataDir)),
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = originalNS.Do(func(netNS ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
_, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).To(Equal(fmt.Errorf("invalid MTU -100, must be [0, master MTU(1500)]")))
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).To(Equal(fmt.Errorf("invalid MTU 1600, must be [0, master MTU(1500)]")))
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
It("fails to create vlan link with negative MTU", func() {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: "/var/run/netns/test",
|
|
||||||
IfName: "eth0",
|
|
||||||
StdinData: []byte(fmt.Sprintf(conf, MASTER_NAME, -100)),
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = originalNS.Do(func(netNS ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
_, _, err = testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).To(Equal(fmt.Errorf("invalid MTU -100, must be [0, master MTU(1500)]")))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/errors"
|
"github.com/containernetworking/plugins/pkg/errors"
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/errors"
|
"github.com/containernetworking/plugins/pkg/errors"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -106,7 +106,7 @@ func makeTcpClientInNS(netns string, address string, port int, numBytes int) {
|
|||||||
Expect(string(out)).To(Equal(message))
|
Expect(string(out)).To(Equal(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVeth(hostNamespace string, hostVethIfName string, containerNamespace string, containerVethIfName string, hostIP []byte, containerIP []byte, hostIfaceMTU int) {
|
func createVeth(hostNs ns.NetNS, hostVethIfName string, containerNs ns.NetNS, containerVethIfName string, hostIP []byte, containerIP []byte, hostIfaceMTU int) {
|
||||||
vethDeviceRequest := &netlink.Veth{
|
vethDeviceRequest := &netlink.Veth{
|
||||||
LinkAttrs: netlink.LinkAttrs{
|
LinkAttrs: netlink.LinkAttrs{
|
||||||
Name: hostVethIfName,
|
Name: hostVethIfName,
|
||||||
@ -116,10 +116,7 @@ func createVeth(hostNamespace string, hostVethIfName string, containerNamespace
|
|||||||
PeerName: containerVethIfName,
|
PeerName: containerVethIfName,
|
||||||
}
|
}
|
||||||
|
|
||||||
hostNs, err := ns.GetNS(hostNamespace)
|
err := hostNs.Do(func(_ ns.NetNS) error {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = hostNs.Do(func(_ ns.NetNS) error {
|
|
||||||
if err := netlink.LinkAdd(vethDeviceRequest); err != nil {
|
if err := netlink.LinkAdd(vethDeviceRequest); err != nil {
|
||||||
return fmt.Errorf("creating veth pair: %s", err)
|
return fmt.Errorf("creating veth pair: %s", err)
|
||||||
}
|
}
|
||||||
@ -129,11 +126,6 @@ func createVeth(hostNamespace string, hostVethIfName string, containerNamespace
|
|||||||
return fmt.Errorf("failed to find newly-created veth device %q: %v", containerVethIfName, err)
|
return fmt.Errorf("failed to find newly-created veth device %q: %v", containerVethIfName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
containerNs, err := ns.GetNS(containerNamespace)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = netlink.LinkSetNsFd(containerVeth, int(containerNs.Fd()))
|
err = netlink.LinkSetNsFd(containerVeth, int(containerNs.Fd()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to move veth to container namespace: %s", err)
|
return fmt.Errorf("failed to move veth to container namespace: %s", err)
|
||||||
@ -169,8 +161,6 @@ func createVeth(hostNamespace string, hostVethIfName string, containerNamespace
|
|||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
containerNs, err := ns.GetNS(containerNamespace)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
err = containerNs.Do(func(_ ns.NetNS) error {
|
err = containerNs.Do(func(_ ns.NetNS) error {
|
||||||
peerAddr := &net.IPNet{
|
peerAddr := &net.IPNet{
|
||||||
IP: hostIP,
|
IP: hostIP,
|
||||||
@ -203,7 +193,7 @@ func createVeth(hostNamespace string, hostVethIfName string, containerNamespace
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVethInOneNs(namespace, vethName, peerName string) {
|
func createVethInOneNs(netNS ns.NetNS, vethName, peerName string) {
|
||||||
vethDeviceRequest := &netlink.Veth{
|
vethDeviceRequest := &netlink.Veth{
|
||||||
LinkAttrs: netlink.LinkAttrs{
|
LinkAttrs: netlink.LinkAttrs{
|
||||||
Name: vethName,
|
Name: vethName,
|
||||||
@ -212,10 +202,7 @@ func createVethInOneNs(namespace, vethName, peerName string) {
|
|||||||
PeerName: peerName,
|
PeerName: peerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
netNS, err := ns.GetNS(namespace)
|
err := netNS.Do(func(_ ns.NetNS) error {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = netNS.Do(func(_ ns.NetNS) error {
|
|
||||||
if err := netlink.LinkAdd(vethDeviceRequest); err != nil {
|
if err := netlink.LinkAdd(vethDeviceRequest); err != nil {
|
||||||
return fmt.Errorf("failed to create veth pair: %v", err)
|
return fmt.Errorf("failed to create veth pair: %v", err)
|
||||||
}
|
}
|
||||||
@ -229,11 +216,8 @@ func createVethInOneNs(namespace, vethName, peerName string) {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMacvlan(namespace, master, macvlanName string) {
|
func createMacvlan(netNS ns.NetNS, master, macvlanName string) {
|
||||||
netNS, err := ns.GetNS(namespace)
|
err := netNS.Do(func(_ ns.NetNS) error {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = netNS.Do(func(_ ns.NetNS) error {
|
|
||||||
m, err := netlink.LinkByName(master)
|
m, err := netlink.LinkByName(master)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to lookup master %q: %v", master, err)
|
return fmt.Errorf("failed to lookup master %q: %v", master, err)
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ip"
|
"github.com/containernetworking/plugins/pkg/ip"
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||||
@ -130,7 +130,9 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if result == nil {
|
if result == nil {
|
||||||
result = ¤t.Result{}
|
result = ¤t.Result{
|
||||||
|
CNIVersion: current.ImplementedSpecVersion,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return types.PrintResult(result, conf.CNIVersion)
|
return types.PrintResult(result, conf.CNIVersion)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/invoke"
|
"github.com/containernetworking/cni/pkg/invoke"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
@ -34,30 +34,7 @@ import (
|
|||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const ifname = "eth0"
|
||||||
confTmpl = `{
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "firewalld-test",
|
|
||||||
"type": "firewall",
|
|
||||||
"backend": "firewalld",
|
|
||||||
"zone": "trusted",
|
|
||||||
"prevResult": {
|
|
||||||
"cniVersion": "0.3.0",
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "%s", "sandbox": "%s"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
ifname = "eth0"
|
|
||||||
)
|
|
||||||
|
|
||||||
type fakeFirewalld struct {
|
type fakeFirewalld struct {
|
||||||
zone string
|
zone string
|
||||||
@ -125,6 +102,30 @@ func spawnSessionDbus(wg *sync.WaitGroup) (string, *exec.Cmd) {
|
|||||||
return busAddr, cmd
|
return busAddr, cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeFirewalldConf(ver, ifname string, ns ns.NetNS) []byte {
|
||||||
|
return []byte(fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "firewalld-test",
|
||||||
|
"type": "firewall",
|
||||||
|
"backend": "firewalld",
|
||||||
|
"zone": "trusted",
|
||||||
|
"prevResult": {
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"interfaces": [
|
||||||
|
{"name": "%s", "sandbox": "%s"}
|
||||||
|
],
|
||||||
|
"ips": [
|
||||||
|
{
|
||||||
|
"version": "4",
|
||||||
|
"address": "10.0.0.2/24",
|
||||||
|
"gateway": "10.0.0.1",
|
||||||
|
"interface": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`, ver, ver, ifname, ns.Path()))
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("firewalld test", func() {
|
var _ = Describe("firewalld test", func() {
|
||||||
var (
|
var (
|
||||||
targetNs ns.NetNS
|
targetNs ns.NetNS
|
||||||
@ -177,167 +178,119 @@ var _ = Describe("firewalld test", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
Expect(targetNs.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(targetNs)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("works with a 0.3.1 config", func() {
|
// firewall plugin requires a prevResult and thus only supports 0.3.0
|
||||||
Expect(isFirewalldRunning()).To(BeTrue())
|
// and later CNI versions
|
||||||
|
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||||
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
|
ver := ver
|
||||||
|
|
||||||
conf := fmt.Sprintf(confTmpl, ifname, targetNs.Path())
|
It(fmt.Sprintf("[%s] works with a config", ver), func() {
|
||||||
args := &skel.CmdArgs{
|
Expect(isFirewalldRunning()).To(BeTrue())
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNs.Path(),
|
conf := makeFirewalldConf(ver, ifname, targetNs)
|
||||||
IfName: ifname,
|
args := &skel.CmdArgs{
|
||||||
StdinData: []byte(conf),
|
ContainerID: "dummy",
|
||||||
}
|
Netns: targetNs.Path(),
|
||||||
_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
|
IfName: ifname,
|
||||||
return cmdAdd(args)
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(fwd.zone).To(Equal("trusted"))
|
||||||
|
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
||||||
|
fwd.clear()
|
||||||
|
|
||||||
|
err = testutils.CmdDel(targetNs.Path(), args.ContainerID, ifname, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(fwd.zone).To(Equal("trusted"))
|
||||||
|
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(fwd.zone).To(Equal("trusted"))
|
|
||||||
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
|
||||||
fwd.clear()
|
|
||||||
|
|
||||||
err = testutils.CmdDel(targetNs.Path(), args.ContainerID, ifname, func() error {
|
It(fmt.Sprintf("[%s] defaults to the firewalld backend", ver), func() {
|
||||||
return cmdDel(args)
|
Expect(isFirewalldRunning()).To(BeTrue())
|
||||||
|
|
||||||
|
conf := makeFirewalldConf(ver, ifname, targetNs)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNs.Path(),
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(fwd.zone).To(Equal("trusted"))
|
||||||
|
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(fwd.zone).To(Equal("trusted"))
|
|
||||||
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("defaults to the firewalld backend", func() {
|
It(fmt.Sprintf("[%s] passes through the prevResult", ver), func() {
|
||||||
conf := `{
|
Expect(isFirewalldRunning()).To(BeTrue())
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "firewalld-test",
|
|
||||||
"type": "firewall",
|
|
||||||
"zone": "trusted",
|
|
||||||
"prevResult": {
|
|
||||||
"cniVersion": "0.3.0",
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "eth0", "sandbox": "/foobar"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
Expect(isFirewalldRunning()).To(BeTrue())
|
conf := makeFirewalldConf(ver, ifname, targetNs)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNs.Path(),
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
r, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
result, err := current.GetResult(r)
|
||||||
ContainerID: "dummy",
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: ifname,
|
Expect(len(result.Interfaces)).To(Equal(1))
|
||||||
StdinData: []byte(conf),
|
Expect(result.Interfaces[0].Name).To(Equal("eth0"))
|
||||||
}
|
Expect(len(result.IPs)).To(Equal(1))
|
||||||
_, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
|
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(fwd.zone).To(Equal("trusted"))
|
|
||||||
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("passes through the prevResult", func() {
|
It(fmt.Sprintf("[%s] works with Check", ver), func() {
|
||||||
conf := `{
|
Expect(isFirewalldRunning()).To(BeTrue())
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"name": "firewalld-test",
|
|
||||||
"type": "firewall",
|
|
||||||
"zone": "trusted",
|
|
||||||
"prevResult": {
|
|
||||||
"cniVersion": "0.3.0",
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "eth0", "sandbox": "/foobar"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
Expect(isFirewalldRunning()).To(BeTrue())
|
conf := makeFirewalldConf(ver, ifname, targetNs)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNs.Path(),
|
||||||
|
IfName: ifname,
|
||||||
|
StdinData: []byte(conf),
|
||||||
|
}
|
||||||
|
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(fwd.zone).To(Equal("trusted"))
|
||||||
|
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
if testutils.SpecVersionHasCHECK(ver) {
|
||||||
ContainerID: "dummy",
|
_, err = current.GetResult(r)
|
||||||
Netns: targetNs.Path(),
|
Expect(err).NotTo(HaveOccurred())
|
||||||
IfName: ifname,
|
|
||||||
StdinData: []byte(conf),
|
err = testutils.CmdCheckWithArgs(args, func() error {
|
||||||
}
|
return cmdCheck(args)
|
||||||
r, _, err := testutils.CmdAdd(targetNs.Path(), args.ContainerID, ifname, []byte(conf), func() error {
|
})
|
||||||
return cmdAdd(args)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(fwd.zone).To(Equal("trusted"))
|
||||||
|
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
}
|
||||||
|
|
||||||
result, err := current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
Expect(len(result.Interfaces)).To(Equal(1))
|
|
||||||
Expect(result.Interfaces[0].Name).To(Equal("eth0"))
|
|
||||||
Expect(len(result.IPs)).To(Equal(1))
|
|
||||||
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("works with a 0.4.0 config, including Check", func() {
|
|
||||||
Expect(isFirewalldRunning()).To(BeTrue())
|
|
||||||
|
|
||||||
conf := `{
|
|
||||||
"cniVersion": "0.4.0",
|
|
||||||
"name": "firewalld-test",
|
|
||||||
"type": "firewall",
|
|
||||||
"backend": "firewalld",
|
|
||||||
"zone": "trusted",
|
|
||||||
"prevResult": {
|
|
||||||
"cniVersion": "0.4.0",
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "eth0", "sandbox": "/foobar"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: ifname,
|
|
||||||
StdinData: []byte(conf),
|
|
||||||
}
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(fwd.zone).To(Equal("trusted"))
|
|
||||||
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
|
||||||
|
|
||||||
_, err = current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = testutils.CmdCheckWithArgs(args, func() error {
|
|
||||||
return cmdCheck(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(fwd.zone).To(Equal("trusted"))
|
|
||||||
Expect(fwd.source).To(Equal("10.0.0.2/32"))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -21,7 +21,8 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/040"
|
||||||
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
@ -165,35 +166,38 @@ func validateCleanedUp(bytes []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeIptablesConf(ver string) []byte {
|
||||||
|
return []byte(fmt.Sprintf(`{
|
||||||
|
"name": "test",
|
||||||
|
"type": "firewall",
|
||||||
|
"backend": "iptables",
|
||||||
|
"ifName": "dummy0",
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"prevResult": {
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"interfaces": [
|
||||||
|
{"name": "dummy0"}
|
||||||
|
],
|
||||||
|
"ips": [
|
||||||
|
{
|
||||||
|
"version": "4",
|
||||||
|
"address": "10.0.0.2/24",
|
||||||
|
"interface": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"address": "2001:db8:1:2::1/64",
|
||||||
|
"interface": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`, ver, ver))
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("firewall plugin iptables backend", func() {
|
var _ = Describe("firewall plugin iptables backend", func() {
|
||||||
var originalNS, targetNS ns.NetNS
|
var originalNS, targetNS ns.NetNS
|
||||||
const IFNAME string = "dummy0"
|
const IFNAME string = "dummy0"
|
||||||
|
|
||||||
fullConf := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "firewall",
|
|
||||||
"backend": "iptables",
|
|
||||||
"ifName": "dummy0",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "dummy0"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"interface": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "6",
|
|
||||||
"address": "2001:db8:1:2::1/64",
|
|
||||||
"interface": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
// Create a new NetNS so we don't modify the host
|
// Create a new NetNS so we don't modify the host
|
||||||
var err error
|
var err error
|
||||||
@ -224,296 +228,174 @@ var _ = Describe("firewall plugin iptables backend", func() {
|
|||||||
Expect(targetNS.Close()).To(Succeed())
|
Expect(targetNS.Close()).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("passes prevResult through unchanged", func() {
|
// firewall plugin requires a prevResult and thus only supports 0.3.0
|
||||||
args := &skel.CmdArgs{
|
// and later CNI versions
|
||||||
ContainerID: "dummy",
|
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||||
Netns: targetNS.Path(),
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
IfName: IFNAME,
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
StdinData: fullConf,
|
ver := ver
|
||||||
}
|
|
||||||
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
It(fmt.Sprintf("[%s] passes prevResult through unchanged", ver), func() {
|
||||||
defer GinkgoRecover()
|
fullConf := makeIptablesConf(ver)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
r, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
ContainerID: "dummy",
|
||||||
return cmdAdd(args)
|
Netns: targetNS.Path(),
|
||||||
})
|
IfName: IFNAME,
|
||||||
Expect(err).NotTo(HaveOccurred())
|
StdinData: fullConf,
|
||||||
|
|
||||||
result, err := current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
Expect(len(result.Interfaces)).To(Equal(1))
|
|
||||||
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
|
||||||
Expect(len(result.IPs)).To(Equal(2))
|
|
||||||
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
|
|
||||||
Expect(result.IPs[1].Address.String()).To(Equal("2001:db8:1:2::1/64"))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("installs the right iptables rules on the host", func() {
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNS.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: fullConf,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
validateFullRuleset(fullConf)
|
|
||||||
|
|
||||||
// ensure creation is idempotent
|
|
||||||
_, _, err = testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("correctly handles a custom IptablesAdminChainName", func() {
|
|
||||||
conf := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "firewall",
|
|
||||||
"backend": "iptables",
|
|
||||||
"ifName": "dummy0",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"iptablesAdminChainName": "CNI-foobar",
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "dummy0"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"interface": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "6",
|
|
||||||
"address": "2001:db8:1:2::1/64",
|
|
||||||
"interface": 0
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
ContainerID: "dummy",
|
defer GinkgoRecover()
|
||||||
Netns: targetNS.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: conf,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
r, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
||||||
defer GinkgoRecover()
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, conf, func() error {
|
result, err := current.GetResult(r)
|
||||||
return cmdAdd(args)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(result.Interfaces)).To(Equal(1))
|
||||||
|
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
||||||
|
Expect(len(result.IPs)).To(Equal(2))
|
||||||
|
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
|
||||||
|
Expect(result.IPs[1].Address.String()).To(Equal("2001:db8:1:2::1/64"))
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
var ipt *iptables.IPTables
|
It(fmt.Sprintf("[%s] installs the right iptables rules on the host", ver), func() {
|
||||||
for _, proto := range []iptables.Protocol{iptables.ProtocolIPv4, iptables.ProtocolIPv6} {
|
fullConf := makeIptablesConf(ver)
|
||||||
ipt, err = iptables.NewWithProtocol(proto)
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: fullConf,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// Ensure custom admin chain name
|
validateFullRuleset(fullConf)
|
||||||
chains, err := ipt.ListChains("filter")
|
|
||||||
|
// ensure creation is idempotent
|
||||||
|
_, _, err = testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
var foundAdmin bool
|
|
||||||
for _, ch := range chains {
|
return nil
|
||||||
if ch == "CNI-foobar" {
|
})
|
||||||
foundAdmin = true
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] correctly handles a custom IptablesAdminChainName", ver), func() {
|
||||||
|
conf := []byte(fmt.Sprintf(`{
|
||||||
|
"name": "test",
|
||||||
|
"type": "firewall",
|
||||||
|
"backend": "iptables",
|
||||||
|
"ifName": "dummy0",
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"iptablesAdminChainName": "CNI-foobar",
|
||||||
|
"prevResult": {
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"interfaces": [
|
||||||
|
{"name": "dummy0"}
|
||||||
|
],
|
||||||
|
"ips": [
|
||||||
|
{
|
||||||
|
"version": "4",
|
||||||
|
"address": "10.0.0.2/24",
|
||||||
|
"interface": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"address": "2001:db8:1:2::1/64",
|
||||||
|
"interface": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`, ver, ver))
|
||||||
|
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: conf,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
|
||||||
|
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, conf, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var ipt *iptables.IPTables
|
||||||
|
for _, proto := range []iptables.Protocol{iptables.ProtocolIPv4, iptables.ProtocolIPv6} {
|
||||||
|
ipt, err = iptables.NewWithProtocol(proto)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Ensure custom admin chain name
|
||||||
|
chains, err := ipt.ListChains("filter")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
var foundAdmin bool
|
||||||
|
for _, ch := range chains {
|
||||||
|
if ch == "CNI-foobar" {
|
||||||
|
foundAdmin = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Expect(foundAdmin).To(Equal(true))
|
||||||
}
|
}
|
||||||
Expect(foundAdmin).To(Equal(true))
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] installs iptables rules, checks rules, then cleans up on delete", ver), func() {
|
||||||
|
fullConf := makeIptablesConf(ver)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "dummy",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: fullConf,
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
})
|
defer GinkgoRecover()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("cleans up on delete", func() {
|
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
args := &skel.CmdArgs{
|
return cmdAdd(args)
|
||||||
ContainerID: "dummy",
|
})
|
||||||
Netns: targetNS.Path(),
|
Expect(err).NotTo(HaveOccurred())
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: fullConf,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
_, err = types040.GetResult(r)
|
||||||
defer GinkgoRecover()
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
if testutils.SpecVersionHasCHECK(ver) {
|
||||||
return cmdAdd(args)
|
err = testutils.CmdCheckWithArgs(args, func() error {
|
||||||
})
|
return cmdCheck(args)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
})
|
||||||
validateFullRuleset(fullConf)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
validateFullRuleset(fullConf)
|
||||||
err = testutils.CmdDel(targetNS.Path(), args.ContainerID, IFNAME, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
validateCleanedUp(fullConf)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("installs the right iptables rules on the host v4.0.x and check is successful", func() {
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNS.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: fullConf,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
validateFullRuleset(fullConf)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("cleans up on delete v4.0.x", func() {
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNS.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: fullConf,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
_, _, err := testutils.CmdAdd(targetNS.Path(), args.ContainerID, IFNAME, fullConf, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
validateFullRuleset(fullConf)
|
|
||||||
|
|
||||||
err = testutils.CmdDel(targetNS.Path(), args.ContainerID, IFNAME, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
validateCleanedUp(fullConf)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
var _ = Describe("firewall plugin iptables backend v0.4.x", func() {
|
|
||||||
var originalNS, targetNS ns.NetNS
|
|
||||||
const IFNAME string = "dummy0"
|
|
||||||
|
|
||||||
fullConf := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "firewall",
|
|
||||||
"backend": "iptables",
|
|
||||||
"ifName": "dummy0",
|
|
||||||
"cniVersion": "0.4.0",
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "dummy0"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"interface": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "6",
|
|
||||||
"address": "2001:db8:1:2::1/64",
|
|
||||||
"interface": 0
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
// Create a new NetNS so we don't modify the host
|
return cmdDel(args)
|
||||||
var err error
|
})
|
||||||
originalNS, err = testutils.NewNS()
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(err).NotTo(HaveOccurred())
|
validateCleanedUp(fullConf)
|
||||||
|
return nil
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
err = netlink.LinkAdd(&netlink.Dummy{
|
|
||||||
LinkAttrs: netlink.LinkAttrs{
|
|
||||||
Name: IFNAME,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
_, err = netlink.LinkByName(IFNAME)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
}
|
||||||
|
|
||||||
targetNS, err = testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
AfterEach(func() {
|
|
||||||
Expect(originalNS.Close()).To(Succeed())
|
|
||||||
Expect(targetNS.Close()).To(Succeed())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("installs iptables rules, Check rules then cleans up on delete using v4.0.x", func() {
|
|
||||||
args := &skel.CmdArgs{
|
|
||||||
ContainerID: "dummy",
|
|
||||||
Netns: targetNS.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: fullConf,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := originalNS.Do(func(ns.NetNS) error {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
|
|
||||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
|
||||||
return cmdAdd(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
_, err = current.GetResult(r)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = testutils.CmdCheckWithArgs(args, func() error {
|
|
||||||
return cmdCheck(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
validateFullRuleset(fullConf)
|
|
||||||
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
validateCleanedUp(fullConf)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/godbus/dbus"
|
"github.com/godbus/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/utils"
|
"github.com/containernetworking/plugins/pkg/utils"
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
)
|
)
|
||||||
|
@ -189,7 +189,7 @@ func consumeScratchNetConf(containerID, dataDir string) (func(error), []byte, er
|
|||||||
return cleanup, netConfBytes, err
|
return cleanup, netConfBytes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func delegateAdd(cid, dataDir string, netconf map[string]interface{}) error {
|
func delegateAdd(cid, dataDir, cniVersion string, netconf map[string]interface{}) error {
|
||||||
netconfBytes, err := json.Marshal(netconf)
|
netconfBytes, err := json.Marshal(netconf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error serializing delegate netconf: %v", err)
|
return fmt.Errorf("error serializing delegate netconf: %v", err)
|
||||||
@ -205,7 +205,7 @@ func delegateAdd(cid, dataDir string, netconf map[string]interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.Print()
|
return types.PrintResult(result, cniVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasKey(m map[string]interface{}, k string) bool {
|
func hasKey(m map[string]interface{}, k string) bool {
|
||||||
@ -247,7 +247,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
n.Delegate["runtimeConfig"] = n.RuntimeConfig
|
n.Delegate["runtimeConfig"] = n.RuntimeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
return doCmdAdd(args, n, fenv)
|
// Delegate CNI config version must match flannel plugin config version
|
||||||
|
n.Delegate["cniVersion"] = n.CNIVersion
|
||||||
|
|
||||||
|
return doCmdAdd(args, n.CNIVersion, n, fenv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdDel(args *skel.CmdArgs) error {
|
func cmdDel(args *skel.CmdArgs) error {
|
||||||
|
@ -72,7 +72,7 @@ func getDelegateIPAM(n *NetConf, fenv *subnetEnv) (map[string]interface{}, error
|
|||||||
return ipam, nil
|
return ipam, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error {
|
func doCmdAdd(args *skel.CmdArgs, cniVersion string, n *NetConf, fenv *subnetEnv) error {
|
||||||
n.Delegate["name"] = n.Name
|
n.Delegate["name"] = n.Name
|
||||||
|
|
||||||
if !hasKey(n.Delegate, "type") {
|
if !hasKey(n.Delegate, "type") {
|
||||||
@ -105,7 +105,7 @@ func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error {
|
|||||||
}
|
}
|
||||||
n.Delegate["ipam"] = ipam
|
n.Delegate["ipam"] = ipam
|
||||||
|
|
||||||
return delegateAdd(args.ContainerID, n.DataDir, n.Delegate)
|
return delegateAdd(args.ContainerID, n.DataDir, cniVersion, n.Delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCmdDel(args *skel.CmdArgs, n *NetConf) (err error) {
|
func doCmdDel(args *skel.CmdArgs, n *NetConf) (err error) {
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
@ -31,6 +31,7 @@ import (
|
|||||||
var _ = Describe("Flannel", func() {
|
var _ = Describe("Flannel", func() {
|
||||||
var (
|
var (
|
||||||
originalNS ns.NetNS
|
originalNS ns.NetNS
|
||||||
|
targetNS ns.NetNS
|
||||||
onlyIpv4Input string
|
onlyIpv4Input string
|
||||||
onlyIpv6Input string
|
onlyIpv6Input string
|
||||||
dualStackInput string
|
dualStackInput string
|
||||||
@ -40,22 +41,12 @@ var _ = Describe("Flannel", func() {
|
|||||||
dataDir string
|
dataDir string
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
const inputTemplate = `{
|
||||||
var err error
|
"name": "cni-flannel",
|
||||||
originalNS, err = testutils.NewNS()
|
"type": "flannel",
|
||||||
Expect(err).NotTo(HaveOccurred())
|
"cniVersion": "%s",
|
||||||
})
|
"subnetFile": "%s",
|
||||||
|
"dataDir": "%s"%s
|
||||||
AfterEach(func() {
|
|
||||||
Expect(originalNS.Close()).To(Succeed())
|
|
||||||
})
|
|
||||||
|
|
||||||
const inputTemplate = `
|
|
||||||
{
|
|
||||||
"name": "cni-flannel",
|
|
||||||
"type": "flannel",
|
|
||||||
"subnetFile": "%s",
|
|
||||||
"dataDir": "%s"%s
|
|
||||||
}`
|
}`
|
||||||
|
|
||||||
const inputIPAMTemplate = `
|
const inputIPAMTemplate = `
|
||||||
@ -95,6 +86,8 @@ FLANNEL_MTU=1472
|
|||||||
FLANNEL_IPMASQ=true
|
FLANNEL_IPMASQ=true
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const IFNAME = "eth0"
|
||||||
|
|
||||||
var writeSubnetEnv = func(contents string) string {
|
var writeSubnetEnv = func(contents string) string {
|
||||||
file, err := ioutil.TempFile("", "subnet.env")
|
file, err := ioutil.TempFile("", "subnet.env")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
@ -114,17 +107,29 @@ FLANNEL_IPMASQ=true
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
var makeInput = func(inputIPAM string, subnetFile string) string {
|
var makeInput = func(cniVersion, inputIPAM string, subnetFile string) string {
|
||||||
ipamPart := ""
|
ipamPart := ""
|
||||||
if len(inputIPAM) > 0 {
|
if len(inputIPAM) > 0 {
|
||||||
ipamPart = ",\n \"ipam\":\n" + inputIPAM
|
ipamPart = ",\n \"ipam\":\n" + inputIPAM
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(inputTemplate, subnetFile, dataDir, ipamPart)
|
return fmt.Sprintf(inputTemplate, cniVersion, subnetFile, dataDir, ipamPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
var makeHostLocalIPAM = func(dataDir string) string {
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
"type": "host-local",
|
||||||
|
"dataDir": "%s"
|
||||||
|
}`, dataDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
var err error
|
var err error
|
||||||
|
originalNS, err = testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
targetNS, err = testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// flannel subnet.env
|
// flannel subnet.env
|
||||||
onlyIpv4SubnetFile = writeSubnetEnv(onlyIpv4FlannelSubnetEnv)
|
onlyIpv4SubnetFile = writeSubnetEnv(onlyIpv4FlannelSubnetEnv)
|
||||||
onlyIpv6SubnetFile = writeSubnetEnv(onlyIpv6FlannelSubnetEnv)
|
onlyIpv6SubnetFile = writeSubnetEnv(onlyIpv6FlannelSubnetEnv)
|
||||||
@ -133,264 +138,274 @@ FLANNEL_IPMASQ=true
|
|||||||
// flannel state dir
|
// flannel state dir
|
||||||
dataDir, err = ioutil.TempDir("", "dataDir")
|
dataDir, err = ioutil.TempDir("", "dataDir")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
onlyIpv4Input = makeInput("", onlyIpv4SubnetFile)
|
|
||||||
onlyIpv6Input = makeInput("", onlyIpv6SubnetFile)
|
|
||||||
dualStackInput = makeInput("", dualStackSubnetFile)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
Expect(targetNS.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(targetNS)).To(Succeed())
|
||||||
|
Expect(originalNS.Close()).To(Succeed())
|
||||||
|
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
|
||||||
|
|
||||||
os.Remove(onlyIpv4SubnetFile)
|
os.Remove(onlyIpv4SubnetFile)
|
||||||
os.Remove(onlyIpv6SubnetFile)
|
os.Remove(onlyIpv6SubnetFile)
|
||||||
os.Remove(dualStackSubnetFile)
|
os.Remove(dualStackSubnetFile)
|
||||||
os.Remove(dataDir)
|
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("CNI lifecycle", func() {
|
Describe("CNI lifecycle", func() {
|
||||||
Context("when using only ipv4 stack", func() {
|
for _, ver := range testutils.AllSpecVersions {
|
||||||
It("uses dataDir for storing network configuration with ipv4 stack", func() {
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
const IFNAME = "eth0"
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
|
ver := ver
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
Context("when using only ipv4 stack", func() {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
It(fmt.Sprintf("[%s] uses dataDir for storing network configuration with ipv4 stack", ver), func() {
|
||||||
defer targetNs.Close()
|
inputIPAM := makeHostLocalIPAM(dataDir)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "some-container-id-ipv4",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: []byte(makeInput(ver, inputIPAM, onlyIpv4SubnetFile)),
|
||||||
|
}
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
ContainerID: "some-container-id-ipv4",
|
defer GinkgoRecover()
|
||||||
Netns: targetNs.Path(),
|
|
||||||
IfName: IFNAME,
|
|
||||||
StdinData: []byte(onlyIpv4Input),
|
|
||||||
}
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
By("calling ADD with ipv4 stack")
|
||||||
defer GinkgoRecover()
|
GinkgoT().Logf("dataDir is %s", dataDir)
|
||||||
|
GinkgoT().Logf("conf is %s", args.StdinData)
|
||||||
|
resI, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
|
return cmdAdd(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
By("calling ADD with ipv4 stack")
|
By("check that plugin writes the net config to dataDir with ipv4 stack")
|
||||||
resI, _, err := testutils.CmdAddWithArgs(args, func() error {
|
path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-ipv4")
|
||||||
return cmdAdd(args)
|
Expect(path).Should(BeAnExistingFile())
|
||||||
|
|
||||||
|
netConfBytes, err := ioutil.ReadFile(path)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
expected := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"ipMasq": false,
|
||||||
|
"ipam": {
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"dst": "10.1.0.0/16"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ranges": [
|
||||||
|
[{
|
||||||
|
"subnet": "10.1.17.0/24"
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
"type": "host-local",
|
||||||
|
"dataDir": "%s"
|
||||||
|
},
|
||||||
|
"isGateway": true,
|
||||||
|
"mtu": 1472,
|
||||||
|
"name": "cni-flannel",
|
||||||
|
"type": "bridge"
|
||||||
|
}`, ver, dataDir)
|
||||||
|
Expect(netConfBytes).Should(MatchJSON(expected))
|
||||||
|
|
||||||
|
result, err := current.NewResultFromResult(resI)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(result.IPs).To(HaveLen(1))
|
||||||
|
|
||||||
|
By("calling DEL with ipv4 stack")
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
By("check that plugin removes net config from state dir with ipv4 stack")
|
||||||
|
Expect(path).ShouldNot(BeAnExistingFile())
|
||||||
|
|
||||||
|
By("calling DEL again with ipv4 stack")
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
By("check that plugin does not fail due to missing net config with ipv4 stack")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
By("check that plugin writes the net config to dataDir with ipv4 stack")
|
|
||||||
path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-ipv4")
|
|
||||||
Expect(path).Should(BeAnExistingFile())
|
|
||||||
|
|
||||||
netConfBytes, err := ioutil.ReadFile(path)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
expected := `{
|
|
||||||
"ipMasq": false,
|
|
||||||
"ipam": {
|
|
||||||
"routes": [
|
|
||||||
{
|
|
||||||
"dst": "10.1.0.0/16"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ranges": [
|
|
||||||
[{
|
|
||||||
"subnet": "10.1.17.0/24"
|
|
||||||
}]
|
|
||||||
],
|
|
||||||
"type": "host-local"
|
|
||||||
},
|
|
||||||
"isGateway": true,
|
|
||||||
"mtu": 1472,
|
|
||||||
"name": "cni-flannel",
|
|
||||||
"type": "bridge"
|
|
||||||
}
|
|
||||||
`
|
|
||||||
Expect(netConfBytes).Should(MatchJSON(expected))
|
|
||||||
|
|
||||||
result, err := current.NewResultFromResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(result.IPs).To(HaveLen(1))
|
|
||||||
|
|
||||||
By("calling DEL with ipv4 stack")
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
By("check that plugin removes net config from state dir with ipv4 stack")
|
|
||||||
Expect(path).ShouldNot(BeAnExistingFile())
|
|
||||||
|
|
||||||
By("calling DEL again with ipv4 stack")
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
By("check that plugin does not fail due to missing net config with ipv4 stack")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
Context("when using only ipv6 stack", func() {
|
Context("when using only ipv6 stack", func() {
|
||||||
It("uses dataDir for storing network configuration with ipv6 stack", func() {
|
It(fmt.Sprintf("[%s] uses dataDir for storing network configuration with ipv6 stack", ver), func() {
|
||||||
const IFNAME = "eth0"
|
inputIPAM := makeHostLocalIPAM(dataDir)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "some-container-id-ipv6",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: []byte(makeInput(ver, inputIPAM, onlyIpv6SubnetFile)),
|
||||||
|
}
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
defer GinkgoRecover()
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
By("calling ADD with ipv6 stack")
|
||||||
ContainerID: "some-container-id-ipv6",
|
resI, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
Netns: targetNs.Path(),
|
return cmdAdd(args)
|
||||||
IfName: IFNAME,
|
})
|
||||||
StdinData: []byte(onlyIpv6Input),
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
By("check that plugin writes the net config to dataDir with ipv6 stack")
|
||||||
defer GinkgoRecover()
|
path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-ipv6")
|
||||||
|
Expect(path).Should(BeAnExistingFile())
|
||||||
|
|
||||||
By("calling ADD with ipv6 stack")
|
netConfBytes, err := ioutil.ReadFile(path)
|
||||||
resI, _, err := testutils.CmdAddWithArgs(args, func() error {
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return cmdAdd(args)
|
expected := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"ipMasq": false,
|
||||||
|
"ipam": {
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"dst": "fc00::/48"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ranges": [
|
||||||
|
[{
|
||||||
|
"subnet": "fc00::/64"
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
"type": "host-local",
|
||||||
|
"dataDir": "%s"
|
||||||
|
},
|
||||||
|
"isGateway": true,
|
||||||
|
"mtu": 1472,
|
||||||
|
"name": "cni-flannel",
|
||||||
|
"type": "bridge"
|
||||||
|
}`, ver, dataDir)
|
||||||
|
Expect(netConfBytes).Should(MatchJSON(expected))
|
||||||
|
|
||||||
|
result, err := current.NewResultFromResult(resI)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(result.IPs).To(HaveLen(1))
|
||||||
|
|
||||||
|
By("calling DEL with ipv6 stack")
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
By("check that plugin removes net config from state dir with ipv6 stack")
|
||||||
|
Expect(path).ShouldNot(BeAnExistingFile())
|
||||||
|
|
||||||
|
By("calling DEL again with ipv6 stack")
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
By("check that plugin does not fail due to missing net config with ipv6 stack")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
By("check that plugin writes the net config to dataDir with ipv6 stack")
|
|
||||||
path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-ipv6")
|
|
||||||
Expect(path).Should(BeAnExistingFile())
|
|
||||||
|
|
||||||
netConfBytes, err := ioutil.ReadFile(path)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
expected := `{
|
|
||||||
"ipMasq": false,
|
|
||||||
"ipam": {
|
|
||||||
"routes": [
|
|
||||||
{
|
|
||||||
"dst": "fc00::/48"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ranges": [
|
|
||||||
[{
|
|
||||||
"subnet": "fc00::/64"
|
|
||||||
}]
|
|
||||||
],
|
|
||||||
"type": "host-local"
|
|
||||||
},
|
|
||||||
"isGateway": true,
|
|
||||||
"mtu": 1472,
|
|
||||||
"name": "cni-flannel",
|
|
||||||
"type": "bridge"
|
|
||||||
}
|
|
||||||
`
|
|
||||||
Expect(netConfBytes).Should(MatchJSON(expected))
|
|
||||||
|
|
||||||
result, err := current.NewResultFromResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(result.IPs).To(HaveLen(1))
|
|
||||||
|
|
||||||
By("calling DEL with ipv6 stack")
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
By("check that plugin removes net config from state dir with ipv6 stack")
|
|
||||||
Expect(path).ShouldNot(BeAnExistingFile())
|
|
||||||
|
|
||||||
By("calling DEL again with ipv6 stack")
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
By("check that plugin does not fail due to missing net config with ipv6 stack")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
Context("when using dual stack", func() {
|
Context("when using dual stack", func() {
|
||||||
It("uses dataDir for storing network configuration with dual stack", func() {
|
It(fmt.Sprintf("[%s] uses dataDir for storing network configuration with dual stack", ver), func() {
|
||||||
const IFNAME = "eth0"
|
inputIPAM := makeHostLocalIPAM(dataDir)
|
||||||
|
args := &skel.CmdArgs{
|
||||||
|
ContainerID: "some-container-id-dual-stack",
|
||||||
|
Netns: targetNS.Path(),
|
||||||
|
IfName: IFNAME,
|
||||||
|
StdinData: []byte(makeInput(ver, inputIPAM, dualStackSubnetFile)),
|
||||||
|
}
|
||||||
|
|
||||||
targetNs, err := testutils.NewNS()
|
err := originalNS.Do(func(ns.NetNS) error {
|
||||||
Expect(err).NotTo(HaveOccurred())
|
defer GinkgoRecover()
|
||||||
defer targetNs.Close()
|
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
By("calling ADD with dual stack")
|
||||||
ContainerID: "some-container-id-dual-stack",
|
resI, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||||
Netns: targetNs.Path(),
|
return cmdAdd(args)
|
||||||
IfName: IFNAME,
|
})
|
||||||
StdinData: []byte(dualStackInput),
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
|
||||||
|
|
||||||
err = originalNS.Do(func(ns.NetNS) error {
|
By("check that plugin writes the net config to dataDir with dual stack")
|
||||||
defer GinkgoRecover()
|
path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-dual-stack")
|
||||||
|
Expect(path).Should(BeAnExistingFile())
|
||||||
|
|
||||||
By("calling ADD with dual stack")
|
netConfBytes, err := ioutil.ReadFile(path)
|
||||||
resI, _, err := testutils.CmdAddWithArgs(args, func() error {
|
Expect(err).NotTo(HaveOccurred())
|
||||||
return cmdAdd(args)
|
expected := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"ipMasq": false,
|
||||||
|
"ipam": {
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"dst": "10.1.0.0/16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dst": "fc00::/48"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ranges": [
|
||||||
|
[{
|
||||||
|
"subnet": "10.1.17.0/24"
|
||||||
|
}],
|
||||||
|
[{
|
||||||
|
"subnet": "fc00::/64"
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
"type": "host-local",
|
||||||
|
"dataDir": "%s"
|
||||||
|
},
|
||||||
|
"isGateway": true,
|
||||||
|
"mtu": 1472,
|
||||||
|
"name": "cni-flannel",
|
||||||
|
"type": "bridge"
|
||||||
|
}`, ver, dataDir)
|
||||||
|
Expect(netConfBytes).Should(MatchJSON(expected))
|
||||||
|
|
||||||
|
result, err := current.NewResultFromResult(resI)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(result.IPs).To(HaveLen(2))
|
||||||
|
|
||||||
|
By("calling DEL with dual stack")
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
By("check that plugin removes net config from state dir with dual stack")
|
||||||
|
Expect(path).ShouldNot(BeAnExistingFile())
|
||||||
|
|
||||||
|
By("calling DEL again with dual stack")
|
||||||
|
err = testutils.CmdDelWithArgs(args, func() error {
|
||||||
|
return cmdDel(args)
|
||||||
|
})
|
||||||
|
By("check that plugin does not fail due to missing net config with dual stack")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
By("check that plugin writes the net config to dataDir with dual stack")
|
|
||||||
path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-dual-stack")
|
|
||||||
Expect(path).Should(BeAnExistingFile())
|
|
||||||
|
|
||||||
netConfBytes, err := ioutil.ReadFile(path)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
expected := `{
|
|
||||||
"ipMasq": false,
|
|
||||||
"ipam": {
|
|
||||||
"routes": [
|
|
||||||
{
|
|
||||||
"dst": "10.1.0.0/16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dst": "fc00::/48"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ranges": [
|
|
||||||
[{
|
|
||||||
"subnet": "10.1.17.0/24"
|
|
||||||
}],
|
|
||||||
[{
|
|
||||||
"subnet": "fc00::/64"
|
|
||||||
}]
|
|
||||||
],
|
|
||||||
"type": "host-local"
|
|
||||||
},
|
|
||||||
"isGateway": true,
|
|
||||||
"mtu": 1472,
|
|
||||||
"name": "cni-flannel",
|
|
||||||
"type": "bridge"
|
|
||||||
}
|
|
||||||
`
|
|
||||||
Expect(netConfBytes).Should(MatchJSON(expected))
|
|
||||||
|
|
||||||
result, err := current.NewResultFromResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(result.IPs).To(HaveLen(2))
|
|
||||||
|
|
||||||
By("calling DEL with dual stack")
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
By("check that plugin removes net config from state dir with dual stack")
|
|
||||||
Expect(path).ShouldNot(BeAnExistingFile())
|
|
||||||
|
|
||||||
By("calling DEL again with dual stack")
|
|
||||||
err = testutils.CmdDelWithArgs(args, func() error {
|
|
||||||
return cmdDel(args)
|
|
||||||
})
|
|
||||||
By("check that plugin does not fail due to missing net config with dual stack")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("loadFlannelNetConf", func() {
|
Describe("loadFlannelNetConf", func() {
|
||||||
|
var (
|
||||||
|
onlyIpv4Input string
|
||||||
|
onlyIpv6Input string
|
||||||
|
dualStackInput string
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
onlyIpv4Input = makeInput(current.ImplementedSpecVersion, "", onlyIpv4SubnetFile)
|
||||||
|
onlyIpv6Input = makeInput(current.ImplementedSpecVersion, "", onlyIpv6SubnetFile)
|
||||||
|
dualStackInput = makeInput(current.ImplementedSpecVersion, "", dualStackSubnetFile)
|
||||||
|
})
|
||||||
|
|
||||||
Context("when subnetFile and dataDir are specified with ipv4 stack", func() {
|
Context("when subnetFile and dataDir are specified with ipv4 stack", func() {
|
||||||
It("loads flannel network config with ipv4 stack", func() {
|
It("loads flannel network config with ipv4 stack", func() {
|
||||||
conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
|
conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
|
||||||
@ -553,7 +568,7 @@ FLANNEL_IPMASQ=true
|
|||||||
Context("when input IPAM is provided with ipv4 stack", func() {
|
Context("when input IPAM is provided with ipv4 stack", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
|
inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
|
||||||
onlyIpv4Input = makeInput(inputIPAM, onlyIpv4SubnetFile)
|
onlyIpv4Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv4SubnetFile)
|
||||||
})
|
})
|
||||||
It("configures Delegate IPAM accordingly with ipv4 stack", func() {
|
It("configures Delegate IPAM accordingly with ipv4 stack", func() {
|
||||||
conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
|
conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
|
||||||
@ -575,7 +590,7 @@ FLANNEL_IPMASQ=true
|
|||||||
Context("when input IPAM is provided with ipv6 stack", func() {
|
Context("when input IPAM is provided with ipv6 stack", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
|
inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
|
||||||
onlyIpv6Input = makeInput(inputIPAM, onlyIpv6SubnetFile)
|
onlyIpv6Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv6SubnetFile)
|
||||||
})
|
})
|
||||||
It("configures Delegate IPAM accordingly with ipv6 stack", func() {
|
It("configures Delegate IPAM accordingly with ipv6 stack", func() {
|
||||||
conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
|
conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
|
||||||
@ -597,7 +612,7 @@ FLANNEL_IPMASQ=true
|
|||||||
Context("when input IPAM is provided with dual stack", func() {
|
Context("when input IPAM is provided with dual stack", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
|
inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
|
||||||
dualStackInput = makeInput(inputIPAM, dualStackSubnetFile)
|
dualStackInput = makeInput(current.ImplementedSpecVersion, inputIPAM, dualStackSubnetFile)
|
||||||
})
|
})
|
||||||
It("configures Delegate IPAM accordingly with dual stack", func() {
|
It("configures Delegate IPAM accordingly with dual stack", func() {
|
||||||
conf, err := loadFlannelNetConf([]byte(dualStackInput))
|
conf, err := loadFlannelNetConf([]byte(dualStackInput))
|
||||||
@ -619,7 +634,7 @@ FLANNEL_IPMASQ=true
|
|||||||
Context("when input IPAM is provided without 'type' with ipv4 stack", func() {
|
Context("when input IPAM is provided without 'type' with ipv4 stack", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
|
inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
|
||||||
onlyIpv4Input = makeInput(inputIPAM, onlyIpv4SubnetFile)
|
onlyIpv4Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv4SubnetFile)
|
||||||
})
|
})
|
||||||
It("configures Delegate IPAM with 'host-local' ipam with ipv4 stack", func() {
|
It("configures Delegate IPAM with 'host-local' ipam with ipv4 stack", func() {
|
||||||
conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
|
conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
|
||||||
@ -640,7 +655,7 @@ FLANNEL_IPMASQ=true
|
|||||||
Context("when input IPAM is provided without 'type' with ipv6 stack", func() {
|
Context("when input IPAM is provided without 'type' with ipv6 stack", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
|
inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
|
||||||
onlyIpv6Input = makeInput(inputIPAM, onlyIpv6SubnetFile)
|
onlyIpv6Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv6SubnetFile)
|
||||||
})
|
})
|
||||||
It("configures Delegate IPAM with 'host-local' ipam with ipv6 stack", func() {
|
It("configures Delegate IPAM with 'host-local' ipam with ipv6 stack", func() {
|
||||||
conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
|
conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
|
||||||
@ -661,7 +676,7 @@ FLANNEL_IPMASQ=true
|
|||||||
Context("when input IPAM is provided without 'type' with dual stack", func() {
|
Context("when input IPAM is provided without 'type' with dual stack", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
|
inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
|
||||||
dualStackInput = makeInput(inputIPAM, dualStackSubnetFile)
|
dualStackInput = makeInput(current.ImplementedSpecVersion, inputIPAM, dualStackSubnetFile)
|
||||||
})
|
})
|
||||||
It("configures Delegate IPAM with 'host-local' ipam with dual stack", func() {
|
It("configures Delegate IPAM with 'host-local' ipam with dual stack", func() {
|
||||||
conf, err := loadFlannelNetConf([]byte(dualStackInput))
|
conf, err := loadFlannelNetConf([]byte(dualStackInput))
|
||||||
|
@ -30,7 +30,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error {
|
func doCmdAdd(args *skel.CmdArgs, cniVersion string, n *NetConf, fenv *subnetEnv) error {
|
||||||
n.Delegate["name"] = n.Name
|
n.Delegate["name"] = n.Name
|
||||||
|
|
||||||
if !hasKey(n.Delegate, "type") {
|
if !hasKey(n.Delegate, "type") {
|
||||||
@ -52,7 +52,8 @@ func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error {
|
|||||||
"subnet": fenv.sn.String(),
|
"subnet": fenv.sn.String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return delegateAdd(hns.GetSandboxContainerID(args.ContainerID, args.Netns), n.DataDir, n.Delegate)
|
sandboxID := hns.GetSandboxContainerID(args.ContainerID, args.Netns)
|
||||||
|
return delegateAdd(sandboxID, n.DataDir, cniVersion, n.Delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCmdDel(args *skel.CmdArgs, n *NetConf) (err error) {
|
func doCmdDel(args *skel.CmdArgs, n *NetConf) (err error) {
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
@ -223,9 +223,10 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, *current.Result, er
|
|||||||
|
|
||||||
if conf.PrevResult != nil {
|
if conf.PrevResult != nil {
|
||||||
for _, ip := range result.IPs {
|
for _, ip := range result.IPs {
|
||||||
if ip.Version == "6" && conf.ContIPv6.IP != nil {
|
isIPv4 := ip.Address.IP.To4() != nil
|
||||||
|
if !isIPv4 && conf.ContIPv6.IP != nil {
|
||||||
continue
|
continue
|
||||||
} else if ip.Version == "4" && conf.ContIPv4.IP != nil {
|
} else if isIPv4 && conf.ContIPv4.IP != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,11 +240,10 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, *current.Result, er
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch ip.Version {
|
if ip.Address.IP.To4() != nil {
|
||||||
case "6":
|
|
||||||
conf.ContIPv6 = ip.Address
|
|
||||||
case "4":
|
|
||||||
conf.ContIPv4 = ip.Address
|
conf.ContIPv4 = ip.Address
|
||||||
|
} else {
|
||||||
|
conf.ContIPv6 = ip.Address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/libcni"
|
"github.com/containernetworking/cni/libcni"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
@ -37,9 +37,36 @@ import (
|
|||||||
|
|
||||||
const TIMEOUT = 90
|
const TIMEOUT = 90
|
||||||
|
|
||||||
|
func makeConfig(ver string) *libcni.NetworkConfigList {
|
||||||
|
configList, err := libcni.ConfListFromBytes([]byte(fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "cni-portmap-unit-test",
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"type": "ptp",
|
||||||
|
"ipMasq": true,
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "172.16.31.0/24",
|
||||||
|
"routes": [
|
||||||
|
{"dst": "0.0.0.0/0"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "portmap",
|
||||||
|
"capabilities": {
|
||||||
|
"portMappings": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, ver)))
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return configList
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("portmap integration tests", func() {
|
var _ = Describe("portmap integration tests", func() {
|
||||||
var (
|
var (
|
||||||
configList *libcni.NetworkConfigList
|
|
||||||
cniConf *libcni.CNIConfig
|
cniConf *libcni.CNIConfig
|
||||||
targetNS ns.NetNS
|
targetNS ns.NetNS
|
||||||
containerPort int
|
containerPort int
|
||||||
@ -47,38 +74,11 @@ var _ = Describe("portmap integration tests", func() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
var err error
|
|
||||||
rawConfig := `{
|
|
||||||
"cniVersion": "0.3.0",
|
|
||||||
"name": "cni-portmap-unit-test",
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "172.16.31.0/24",
|
|
||||||
"routes": [
|
|
||||||
{"dst": "0.0.0.0/0"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "portmap",
|
|
||||||
"capabilities": {
|
|
||||||
"portMappings": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`
|
|
||||||
|
|
||||||
configList, err = libcni.ConfListFromBytes([]byte(rawConfig))
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// turn PATH in to CNI_PATH
|
// turn PATH in to CNI_PATH
|
||||||
dirs := filepath.SplitList(os.Getenv("PATH"))
|
dirs := filepath.SplitList(os.Getenv("PATH"))
|
||||||
cniConf = &libcni.CNIConfig{Path: dirs}
|
cniConf = &libcni.CNIConfig{Path: dirs}
|
||||||
|
|
||||||
|
var err error
|
||||||
targetNS, err = testutils.NewNS()
|
targetNS, err = testutils.NewNS()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS.Path())
|
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS.Path())
|
||||||
@ -90,333 +90,340 @@ var _ = Describe("portmap integration tests", func() {
|
|||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
session.Terminate().Wait()
|
session.Terminate().Wait()
|
||||||
if targetNS != nil {
|
targetNS.Close()
|
||||||
targetNS.Close()
|
testutils.UnmountNS(targetNS)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("Creating an interface in a namespace with the ptp plugin", func() {
|
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||||
// This needs to be done using Ginkgo's asynchronous testing mode.
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
It("forwards a TCP port on ipv4", func(done Done) {
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
var err error
|
ver := ver
|
||||||
hostPort := rand.Intn(10000) + 1025
|
|
||||||
runtimeConfig := libcni.RuntimeConf{
|
Describe("Creating an interface in a namespace with the ptp plugin", func() {
|
||||||
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
// This needs to be done using Ginkgo's asynchronous testing mode.
|
||||||
NetNS: targetNS.Path(),
|
It(fmt.Sprintf("[%s] forwards a TCP port on ipv4", ver), func(done Done) {
|
||||||
IfName: "eth0",
|
var err error
|
||||||
CapabilityArgs: map[string]interface{}{
|
hostPort := rand.Intn(10000) + 1025
|
||||||
"portMappings": []map[string]interface{}{
|
runtimeConfig := libcni.RuntimeConf{
|
||||||
{
|
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
||||||
"hostPort": hostPort,
|
NetNS: targetNS.Path(),
|
||||||
"containerPort": containerPort,
|
IfName: "eth0",
|
||||||
"protocol": "tcp",
|
CapabilityArgs: map[string]interface{}{
|
||||||
|
"portMappings": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"hostPort": hostPort,
|
||||||
|
"containerPort": containerPort,
|
||||||
|
"protocol": "tcp",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make delete idempotent, so we can clean up on failure
|
|
||||||
netDeleted := false
|
|
||||||
deleteNetwork := func() error {
|
|
||||||
if netDeleted {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
netDeleted = true
|
configList := makeConfig(ver)
|
||||||
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// we'll also manually check the iptables chains
|
// Make delete idempotent, so we can clean up on failure
|
||||||
ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
|
netDeleted := false
|
||||||
Expect(err).NotTo(HaveOccurred())
|
deleteNetwork := func() error {
|
||||||
dnatChainName := genDnatChain("cni-portmap-unit-test", runtimeConfig.ContainerID).name
|
if netDeleted {
|
||||||
|
return nil
|
||||||
// Create the network
|
}
|
||||||
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
netDeleted = true
|
||||||
Expect(err).NotTo(HaveOccurred())
|
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
defer deleteNetwork()
|
|
||||||
|
|
||||||
// Undo Docker's forwarding policy
|
|
||||||
cmd := exec.Command("iptables", "-t", "filter",
|
|
||||||
"-P", "FORWARD", "ACCEPT")
|
|
||||||
cmd.Stderr = GinkgoWriter
|
|
||||||
err = cmd.Run()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Check the chain exists
|
|
||||||
_, err = ipt.List("nat", dnatChainName)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
result, err := current.GetResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
var contIP net.IP
|
|
||||||
|
|
||||||
for _, ip := range result.IPs {
|
|
||||||
intfIndex := *ip.Interface
|
|
||||||
if result.Interfaces[intfIndex].Sandbox == "" {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
contIP = ip.Address.IP
|
|
||||||
}
|
|
||||||
if contIP == nil {
|
|
||||||
Fail("could not determine container IP")
|
|
||||||
}
|
|
||||||
|
|
||||||
hostIP := getLocalIP()
|
// we'll also manually check the iptables chains
|
||||||
fmt.Fprintf(GinkgoWriter, "hostIP: %s:%d, contIP: %s:%d\n",
|
ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
|
||||||
hostIP, hostPort, contIP, containerPort)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
dnatChainName := genDnatChain("cni-portmap-unit-test", runtimeConfig.ContainerID).name
|
||||||
|
|
||||||
// dump iptables-save output for debugging
|
// Create the network
|
||||||
cmd = exec.Command("iptables-save")
|
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
cmd.Stderr = GinkgoWriter
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stdout = GinkgoWriter
|
defer deleteNetwork()
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// dump ip routes output for debugging
|
// Undo Docker's forwarding policy
|
||||||
cmd = exec.Command("ip", "route")
|
cmd := exec.Command("iptables", "-t", "filter",
|
||||||
cmd.Stderr = GinkgoWriter
|
"-P", "FORWARD", "ACCEPT")
|
||||||
cmd.Stdout = GinkgoWriter
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(cmd.Run()).To(Succeed())
|
err = cmd.Run()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// dump ip addresses output for debugging
|
// Check the chain exists
|
||||||
cmd = exec.Command("ip", "addr")
|
_, err = ipt.List("nat", dnatChainName)
|
||||||
cmd.Stderr = GinkgoWriter
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// Sanity check: verify that the container is reachable directly
|
result, err := types100.GetResult(resI)
|
||||||
contOK := testEchoServer(contIP.String(), "tcp", containerPort, "")
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
var contIP net.IP
|
||||||
|
|
||||||
// Verify that a connection to the forwarded port works
|
for _, ip := range result.IPs {
|
||||||
dnatOK := testEchoServer(hostIP, "tcp", hostPort, "")
|
intfIndex := *ip.Interface
|
||||||
|
if result.Interfaces[intfIndex].Sandbox == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
contIP = ip.Address.IP
|
||||||
|
}
|
||||||
|
if contIP == nil {
|
||||||
|
Fail("could not determine container IP")
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that a connection to localhost works
|
hostIP := getLocalIP()
|
||||||
snatOK := testEchoServer("127.0.0.1", "tcp", hostPort, "")
|
fmt.Fprintf(GinkgoWriter, "hostIP: %s:%d, contIP: %s:%d\n",
|
||||||
|
hostIP, hostPort, contIP, containerPort)
|
||||||
|
|
||||||
// verify that hairpin works
|
// dump iptables-save output for debugging
|
||||||
hairpinOK := testEchoServer(hostIP, "tcp", hostPort, targetNS.Path())
|
cmd = exec.Command("iptables-save")
|
||||||
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Cleanup
|
// dump ip routes output for debugging
|
||||||
session.Terminate()
|
cmd = exec.Command("ip", "route")
|
||||||
err = deleteNetwork()
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(err).NotTo(HaveOccurred())
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Verify iptables rules are gone
|
// dump ip addresses output for debugging
|
||||||
_, err = ipt.List("nat", dnatChainName)
|
cmd = exec.Command("ip", "addr")
|
||||||
Expect(err).To(MatchError(ContainSubstring("iptables: No chain/target/match by that name.")))
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Check that everything succeeded *after* we clean up the network
|
// Sanity check: verify that the container is reachable directly
|
||||||
if !contOK {
|
contOK := testEchoServer(contIP.String(), "tcp", containerPort, "")
|
||||||
Fail("connection direct to " + contIP.String() + " failed")
|
|
||||||
}
|
|
||||||
if !dnatOK {
|
|
||||||
Fail("Connection to " + hostIP + " was not forwarded")
|
|
||||||
}
|
|
||||||
if !snatOK {
|
|
||||||
Fail("connection to 127.0.0.1 was not forwarded")
|
|
||||||
}
|
|
||||||
if !hairpinOK {
|
|
||||||
Fail("Hairpin connection failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
close(done)
|
// Verify that a connection to the forwarded port works
|
||||||
}, TIMEOUT*9)
|
dnatOK := testEchoServer(hostIP, "tcp", hostPort, "")
|
||||||
|
|
||||||
It("forwards a UDP port on ipv4 and keep working after creating a second container with the same HostPort", func(done Done) {
|
// Verify that a connection to localhost works
|
||||||
var err error
|
snatOK := testEchoServer("127.0.0.1", "tcp", hostPort, "")
|
||||||
hostPort := rand.Intn(10000) + 1025
|
|
||||||
runtimeConfig := libcni.RuntimeConf{
|
// verify that hairpin works
|
||||||
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
hairpinOK := testEchoServer(hostIP, "tcp", hostPort, targetNS.Path())
|
||||||
NetNS: targetNS.Path(),
|
|
||||||
IfName: "eth0",
|
// Cleanup
|
||||||
CapabilityArgs: map[string]interface{}{
|
session.Terminate()
|
||||||
"portMappings": []map[string]interface{}{
|
err = deleteNetwork()
|
||||||
{
|
Expect(err).NotTo(HaveOccurred())
|
||||||
"hostPort": hostPort,
|
|
||||||
"containerPort": containerPort,
|
// Verify iptables rules are gone
|
||||||
"protocol": "udp",
|
_, err = ipt.List("nat", dnatChainName)
|
||||||
|
Expect(err).To(MatchError(ContainSubstring("iptables: No chain/target/match by that name.")))
|
||||||
|
|
||||||
|
// Check that everything succeeded *after* we clean up the network
|
||||||
|
if !contOK {
|
||||||
|
Fail("connection direct to " + contIP.String() + " failed")
|
||||||
|
}
|
||||||
|
if !dnatOK {
|
||||||
|
Fail("Connection to " + hostIP + " was not forwarded")
|
||||||
|
}
|
||||||
|
if !snatOK {
|
||||||
|
Fail("connection to 127.0.0.1 was not forwarded")
|
||||||
|
}
|
||||||
|
if !hairpinOK {
|
||||||
|
Fail("Hairpin connection failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
}, TIMEOUT*9)
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] forwards a UDP port on ipv4 and keep working after creating a second container with the same HostPort", ver), func(done Done) {
|
||||||
|
var err error
|
||||||
|
hostPort := rand.Intn(10000) + 1025
|
||||||
|
runtimeConfig := libcni.RuntimeConf{
|
||||||
|
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
||||||
|
NetNS: targetNS.Path(),
|
||||||
|
IfName: "eth0",
|
||||||
|
CapabilityArgs: map[string]interface{}{
|
||||||
|
"portMappings": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"hostPort": hostPort,
|
||||||
|
"containerPort": containerPort,
|
||||||
|
"protocol": "udp",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make delete idempotent, so we can clean up on failure
|
|
||||||
netDeleted := false
|
|
||||||
deleteNetwork := func() error {
|
|
||||||
if netDeleted {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
netDeleted = true
|
configList := makeConfig(ver)
|
||||||
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the network
|
// Make delete idempotent, so we can clean up on failure
|
||||||
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
netDeleted := false
|
||||||
Expect(err).NotTo(HaveOccurred())
|
deleteNetwork := func() error {
|
||||||
defer deleteNetwork()
|
if netDeleted {
|
||||||
|
return nil
|
||||||
// Undo Docker's forwarding policy
|
}
|
||||||
cmd := exec.Command("iptables", "-t", "filter",
|
netDeleted = true
|
||||||
"-P", "FORWARD", "ACCEPT")
|
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
cmd.Stderr = GinkgoWriter
|
|
||||||
err = cmd.Run()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
result, err := current.GetResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
var contIP net.IP
|
|
||||||
|
|
||||||
for _, ip := range result.IPs {
|
|
||||||
intfIndex := *ip.Interface
|
|
||||||
if result.Interfaces[intfIndex].Sandbox == "" {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
contIP = ip.Address.IP
|
|
||||||
}
|
|
||||||
if contIP == nil {
|
|
||||||
Fail("could not determine container IP")
|
|
||||||
}
|
|
||||||
|
|
||||||
hostIP := getLocalIP()
|
// Create the network
|
||||||
fmt.Fprintf(GinkgoWriter, "First container hostIP: %s:%d, contIP: %s:%d\n",
|
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
hostIP, hostPort, contIP, containerPort)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer deleteNetwork()
|
||||||
|
|
||||||
// dump iptables-save output for debugging
|
// Undo Docker's forwarding policy
|
||||||
cmd = exec.Command("iptables-save")
|
cmd := exec.Command("iptables", "-t", "filter",
|
||||||
cmd.Stderr = GinkgoWriter
|
"-P", "FORWARD", "ACCEPT")
|
||||||
cmd.Stdout = GinkgoWriter
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(cmd.Run()).To(Succeed())
|
err = cmd.Run()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// dump ip routes output for debugging
|
result, err := types100.GetResult(resI)
|
||||||
cmd = exec.Command("ip", "route")
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stderr = GinkgoWriter
|
var contIP net.IP
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// dump ip addresses output for debugging
|
for _, ip := range result.IPs {
|
||||||
cmd = exec.Command("ip", "addr")
|
intfIndex := *ip.Interface
|
||||||
cmd.Stderr = GinkgoWriter
|
if result.Interfaces[intfIndex].Sandbox == "" {
|
||||||
cmd.Stdout = GinkgoWriter
|
continue
|
||||||
Expect(cmd.Run()).To(Succeed())
|
}
|
||||||
|
contIP = ip.Address.IP
|
||||||
|
}
|
||||||
|
if contIP == nil {
|
||||||
|
Fail("could not determine container IP")
|
||||||
|
}
|
||||||
|
|
||||||
// Sanity check: verify that the container is reachable directly
|
hostIP := getLocalIP()
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP.String(), containerPort)
|
fmt.Fprintf(GinkgoWriter, "First container hostIP: %s:%d, contIP: %s:%d\n",
|
||||||
contOK := testEchoServer(contIP.String(), "udp", containerPort, "")
|
hostIP, hostPort, contIP, containerPort)
|
||||||
|
|
||||||
// Verify that a connection to the forwarded port works
|
// dump iptables-save output for debugging
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
cmd = exec.Command("iptables-save")
|
||||||
dnatOK := testEchoServer(hostIP, "udp", hostPort, "")
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Cleanup
|
// dump ip routes output for debugging
|
||||||
session.Terminate()
|
cmd = exec.Command("ip", "route")
|
||||||
err = deleteNetwork()
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(err).NotTo(HaveOccurred())
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Check that everything succeeded *after* we clean up the network
|
// dump ip addresses output for debugging
|
||||||
if !contOK {
|
cmd = exec.Command("ip", "addr")
|
||||||
Fail("connection direct to " + contIP.String() + " failed")
|
cmd.Stderr = GinkgoWriter
|
||||||
}
|
cmd.Stdout = GinkgoWriter
|
||||||
if !dnatOK {
|
Expect(cmd.Run()).To(Succeed())
|
||||||
Fail("Connection to " + hostIP + " was not forwarded")
|
|
||||||
}
|
|
||||||
// Create a second container
|
|
||||||
targetNS2, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS2.Path())
|
|
||||||
|
|
||||||
// Start an echo server and get the port
|
// Sanity check: verify that the container is reachable directly
|
||||||
containerPort, session2, err := StartEchoServerInNamespace(targetNS2)
|
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP.String(), containerPort)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
contOK := testEchoServer(contIP.String(), "udp", containerPort, "")
|
||||||
|
|
||||||
runtimeConfig2 := libcni.RuntimeConf{
|
// Verify that a connection to the forwarded port works
|
||||||
ContainerID: fmt.Sprintf("unit-test2-%d", hostPort),
|
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
||||||
NetNS: targetNS2.Path(),
|
dnatOK := testEchoServer(hostIP, "udp", hostPort, "")
|
||||||
IfName: "eth0",
|
|
||||||
CapabilityArgs: map[string]interface{}{
|
// Cleanup
|
||||||
"portMappings": []map[string]interface{}{
|
session.Terminate()
|
||||||
{
|
err = deleteNetwork()
|
||||||
"hostPort": hostPort,
|
Expect(err).NotTo(HaveOccurred())
|
||||||
"containerPort": containerPort,
|
|
||||||
"protocol": "udp",
|
// Check that everything succeeded *after* we clean up the network
|
||||||
|
if !contOK {
|
||||||
|
Fail("connection direct to " + contIP.String() + " failed")
|
||||||
|
}
|
||||||
|
if !dnatOK {
|
||||||
|
Fail("Connection to " + hostIP + " was not forwarded")
|
||||||
|
}
|
||||||
|
// Create a second container
|
||||||
|
targetNS2, err := testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS2.Path())
|
||||||
|
|
||||||
|
// Start an echo server and get the port
|
||||||
|
containerPort, session2, err := StartEchoServerInNamespace(targetNS2)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
runtimeConfig2 := libcni.RuntimeConf{
|
||||||
|
ContainerID: fmt.Sprintf("unit-test2-%d", hostPort),
|
||||||
|
NetNS: targetNS2.Path(),
|
||||||
|
IfName: "eth0",
|
||||||
|
CapabilityArgs: map[string]interface{}{
|
||||||
|
"portMappings": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"hostPort": hostPort,
|
||||||
|
"containerPort": containerPort,
|
||||||
|
"protocol": "udp",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make delete idempotent, so we can clean up on failure
|
|
||||||
net2Deleted := false
|
|
||||||
deleteNetwork2 := func() error {
|
|
||||||
if net2Deleted {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
net2Deleted = true
|
|
||||||
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the network
|
// Make delete idempotent, so we can clean up on failure
|
||||||
resI2, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig2)
|
net2Deleted := false
|
||||||
Expect(err).NotTo(HaveOccurred())
|
deleteNetwork2 := func() error {
|
||||||
defer deleteNetwork2()
|
if net2Deleted {
|
||||||
|
return nil
|
||||||
result2, err := current.GetResult(resI2)
|
}
|
||||||
Expect(err).NotTo(HaveOccurred())
|
net2Deleted = true
|
||||||
var contIP2 net.IP
|
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig2)
|
||||||
|
|
||||||
for _, ip := range result2.IPs {
|
|
||||||
intfIndex := *ip.Interface
|
|
||||||
if result2.Interfaces[intfIndex].Sandbox == "" {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
contIP2 = ip.Address.IP
|
|
||||||
}
|
|
||||||
if contIP2 == nil {
|
|
||||||
Fail("could not determine container IP")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(GinkgoWriter, "Second container: hostIP: %s:%d, contIP: %s:%d\n",
|
// Create the network
|
||||||
hostIP, hostPort, contIP2, containerPort)
|
resI2, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig2)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer deleteNetwork2()
|
||||||
|
|
||||||
// dump iptables-save output for debugging
|
result2, err := types100.GetResult(resI2)
|
||||||
cmd = exec.Command("iptables-save")
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stderr = GinkgoWriter
|
var contIP2 net.IP
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// dump ip routes output for debugging
|
for _, ip := range result2.IPs {
|
||||||
cmd = exec.Command("ip", "route")
|
intfIndex := *ip.Interface
|
||||||
cmd.Stderr = GinkgoWriter
|
if result2.Interfaces[intfIndex].Sandbox == "" {
|
||||||
cmd.Stdout = GinkgoWriter
|
continue
|
||||||
Expect(cmd.Run()).To(Succeed())
|
}
|
||||||
|
contIP2 = ip.Address.IP
|
||||||
|
}
|
||||||
|
if contIP2 == nil {
|
||||||
|
Fail("could not determine container IP")
|
||||||
|
}
|
||||||
|
|
||||||
// dump ip addresses output for debugging
|
fmt.Fprintf(GinkgoWriter, "Second container: hostIP: %s:%d, contIP: %s:%d\n",
|
||||||
cmd = exec.Command("ip", "addr")
|
hostIP, hostPort, contIP2, containerPort)
|
||||||
cmd.Stderr = GinkgoWriter
|
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// Sanity check: verify that the container is reachable directly
|
// dump iptables-save output for debugging
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP2.String(), containerPort)
|
cmd = exec.Command("iptables-save")
|
||||||
cont2OK := testEchoServer(contIP2.String(), "udp", containerPort, "")
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Verify that a connection to the forwarded port works
|
// dump ip routes output for debugging
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
cmd = exec.Command("ip", "route")
|
||||||
dnat2OK := testEchoServer(hostIP, "udp", hostPort, "")
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Cleanup
|
// dump ip addresses output for debugging
|
||||||
session2.Terminate()
|
cmd = exec.Command("ip", "addr")
|
||||||
err = deleteNetwork2()
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(err).NotTo(HaveOccurred())
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Check that everything succeeded *after* we clean up the network
|
// Sanity check: verify that the container is reachable directly
|
||||||
if !cont2OK {
|
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP2.String(), containerPort)
|
||||||
Fail("connection direct to " + contIP2.String() + " failed")
|
cont2OK := testEchoServer(contIP2.String(), "udp", containerPort, "")
|
||||||
}
|
|
||||||
if !dnat2OK {
|
|
||||||
Fail("Connection to " + hostIP + " was not forwarded")
|
|
||||||
}
|
|
||||||
|
|
||||||
close(done)
|
// Verify that a connection to the forwarded port works
|
||||||
}, TIMEOUT*9)
|
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
||||||
})
|
dnat2OK := testEchoServer(hostIP, "udp", hostPort, "")
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
session2.Terminate()
|
||||||
|
err = deleteNetwork2()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Check that everything succeeded *after* we clean up the network
|
||||||
|
if !cont2OK {
|
||||||
|
Fail("connection direct to " + contIP2.String() + " failed")
|
||||||
|
}
|
||||||
|
if !dnat2OK {
|
||||||
|
Fail("Connection to " + hostIP + " was not forwarded")
|
||||||
|
}
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
}, TIMEOUT*9)
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// testEchoServer returns true if we found an echo server on the port
|
// testEchoServer returns true if we found an echo server on the port
|
||||||
|
@ -27,336 +27,342 @@ var _ = Describe("portmapping configuration", func() {
|
|||||||
netName := "testNetName"
|
netName := "testNetName"
|
||||||
containerID := "icee6giejonei6sohng6ahngee7laquohquee9shiGo7fohferakah3Feiyoolu2pei7ciPhoh7shaoX6vai3vuf0ahfaeng8yohb9ceu0daez5hashee8ooYai5wa3y"
|
containerID := "icee6giejonei6sohng6ahngee7laquohquee9shiGo7fohferakah3Feiyoolu2pei7ciPhoh7shaoX6vai3vuf0ahfaeng8yohb9ceu0daez5hashee8ooYai5wa3y"
|
||||||
|
|
||||||
Context("config parsing", func() {
|
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||||
It("Correctly parses an ADD config", func() {
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
configBytes := []byte(`{
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
"name": "test",
|
ver := ver
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
|
||||||
{ "hostPort": 8081, "containerPort": 81, "protocol": "udp"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"snat": false,
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"conditionsV6": ["c", "d"],
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "host"},
|
|
||||||
{"name": "container", "sandbox":"netns"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.1/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "6",
|
|
||||||
"address": "2001:db8:1::2/64",
|
|
||||||
"gateway": "2001:db8:1::1",
|
|
||||||
"interface": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
c, _, err := parseConfig(configBytes, "container")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(c.CNIVersion).To(Equal("0.3.1"))
|
|
||||||
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
|
||||||
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
|
||||||
fvar := false
|
|
||||||
Expect(c.SNAT).To(Equal(&fvar))
|
|
||||||
Expect(c.Name).To(Equal("test"))
|
|
||||||
|
|
||||||
n, err := types.ParseCIDR("10.0.0.2/24")
|
Context("config parsing", func() {
|
||||||
Expect(c.ContIPv4).To(Equal(*n))
|
It(fmt.Sprintf("[%s] correctly parses an ADD config", ver), func() {
|
||||||
n, err = types.ParseCIDR("2001:db8:1::2/64")
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
Expect(c.ContIPv6).To(Equal(*n))
|
"name": "test",
|
||||||
})
|
"type": "portmap",
|
||||||
|
"cniVersion": "%s",
|
||||||
It("Correctly parses a DEL config", func() {
|
"runtimeConfig": {
|
||||||
// When called with DEL, neither runtimeConfig nor prevResult may be specified
|
"portMappings": [
|
||||||
configBytes := []byte(`{
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
||||||
"name": "test",
|
{ "hostPort": 8081, "containerPort": 81, "protocol": "udp"}
|
||||||
"type": "portmap",
|
]
|
||||||
"cniVersion": "0.3.1",
|
},
|
||||||
"snat": false,
|
"snat": false,
|
||||||
"conditionsV4": ["a", "b"],
|
"conditionsV4": ["a", "b"],
|
||||||
"conditionsV6": ["c", "d"]
|
"conditionsV6": ["c", "d"],
|
||||||
}`)
|
"prevResult": {
|
||||||
c, _, err := parseConfig(configBytes, "container")
|
"interfaces": [
|
||||||
Expect(err).NotTo(HaveOccurred())
|
{"name": "host"},
|
||||||
Expect(c.CNIVersion).To(Equal("0.3.1"))
|
{"name": "container", "sandbox":"netns"}
|
||||||
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
],
|
||||||
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
"ips": [
|
||||||
fvar := false
|
{
|
||||||
Expect(c.SNAT).To(Equal(&fvar))
|
"version": "4",
|
||||||
Expect(c.Name).To(Equal("test"))
|
"address": "10.0.0.1/24",
|
||||||
})
|
"gateway": "10.0.0.1",
|
||||||
|
"interface": 0
|
||||||
It("fails with invalid mappings", func() {
|
},
|
||||||
configBytes := []byte(`{
|
{
|
||||||
"name": "test",
|
"version": "6",
|
||||||
"type": "portmap",
|
"address": "2001:db8:1::2/64",
|
||||||
"cniVersion": "0.3.1",
|
"gateway": "2001:db8:1::1",
|
||||||
"snat": false,
|
"interface": 1
|
||||||
"conditionsV4": ["a", "b"],
|
},
|
||||||
"conditionsV6": ["c", "d"],
|
{
|
||||||
"runtimeConfig": {
|
"version": "4",
|
||||||
"portMappings": [
|
"address": "10.0.0.2/24",
|
||||||
{ "hostPort": 0, "containerPort": 80, "protocol": "tcp"}
|
"gateway": "10.0.0.1",
|
||||||
]
|
"interface": 1
|
||||||
}
|
}
|
||||||
}`)
|
]
|
||||||
_, _, err := parseConfig(configBytes, "container")
|
}
|
||||||
Expect(err).To(MatchError("Invalid host port number: 0"))
|
}`, ver))
|
||||||
})
|
c, _, err := parseConfig(configBytes, "container")
|
||||||
|
|
||||||
It("Does not fail on missing prevResult interface index", func() {
|
|
||||||
configBytes := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "host"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.1/24",
|
|
||||||
"gateway": "10.0.0.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
_, _, err := parseConfig(configBytes, "container")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("Generating chains", func() {
|
|
||||||
Context("for DNAT", func() {
|
|
||||||
It("generates a correct standard container chain", func() {
|
|
||||||
ch := genDnatChain(netName, containerID)
|
|
||||||
|
|
||||||
Expect(ch).To(Equal(chain{
|
|
||||||
table: "nat",
|
|
||||||
name: "CNI-DN-bfd599665540dd91d5d28",
|
|
||||||
entryChains: []string{TopLevelDNATChainName},
|
|
||||||
}))
|
|
||||||
configBytes := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
|
||||||
{ "hostPort": 8081, "containerPort": 80, "protocol": "tcp"},
|
|
||||||
{ "hostPort": 8080, "containerPort": 81, "protocol": "udp"},
|
|
||||||
{ "hostPort": 8082, "containerPort": 82, "protocol": "udp"},
|
|
||||||
{ "hostPort": 8083, "containerPort": 83, "protocol": "tcp", "hostIP": "192.168.0.2"},
|
|
||||||
{ "hostPort": 8084, "containerPort": 84, "protocol": "tcp", "hostIP": "0.0.0.0"},
|
|
||||||
{ "hostPort": 8085, "containerPort": 85, "protocol": "tcp", "hostIP": "2001:db8:a::1"},
|
|
||||||
{ "hostPort": 8086, "containerPort": 86, "protocol": "tcp", "hostIP": "::"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"snat": true,
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"conditionsV6": ["c", "d"]
|
|
||||||
}`)
|
|
||||||
|
|
||||||
conf, _, err := parseConfig(configBytes, "foo")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
conf.ContainerID = containerID
|
Expect(c.CNIVersion).To(Equal(ver))
|
||||||
|
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
||||||
ch = genDnatChain(conf.Name, containerID)
|
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
||||||
Expect(ch).To(Equal(chain{
|
|
||||||
table: "nat",
|
|
||||||
name: "CNI-DN-67e92b96e692a494b6b85",
|
|
||||||
entryChains: []string{"CNI-HOSTPORT-DNAT"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
n, err := types.ParseCIDR("10.0.0.2/24")
|
|
||||||
fillDnatRules(&ch, conf, *n)
|
|
||||||
|
|
||||||
Expect(ch.entryRules).To(Equal([][]string{
|
|
||||||
{"-m", "comment", "--comment",
|
|
||||||
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
|
||||||
"-m", "multiport",
|
|
||||||
"-p", "tcp",
|
|
||||||
"--destination-ports", "8080,8081,8083,8084,8085,8086",
|
|
||||||
"a", "b"},
|
|
||||||
{"-m", "comment", "--comment",
|
|
||||||
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
|
||||||
"-m", "multiport",
|
|
||||||
"-p", "udp",
|
|
||||||
"--destination-ports", "8080,8082",
|
|
||||||
"a", "b"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
|
||||||
// tcp rules and not hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
// udp rules and not hostIP
|
|
||||||
{"-p", "udp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
|
||||||
// tcp rules and hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
|
||||||
// tcp rules and hostIP = "0.0.0.0"
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
ch.rules = nil
|
|
||||||
ch.entryRules = nil
|
|
||||||
|
|
||||||
n, err = types.ParseCIDR("2001:db8::2/64")
|
|
||||||
fillDnatRules(&ch, conf, *n)
|
|
||||||
|
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
|
||||||
// tcp rules and not hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
|
||||||
// udp rules and not hostIP
|
|
||||||
{"-p", "udp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:81"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "[2001:db8::2]:82"},
|
|
||||||
// tcp rules and hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-j", "DNAT", "--to-destination", "[2001:db8::2]:85"},
|
|
||||||
// tcp rules and hostIP = "::"
|
|
||||||
{"-p", "tcp", "--dport", "8086", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8086", "-j", "DNAT", "--to-destination", "[2001:db8::2]:86"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Disable snat, generate rules
|
|
||||||
ch.rules = nil
|
|
||||||
ch.entryRules = nil
|
|
||||||
fvar := false
|
fvar := false
|
||||||
conf.SNAT = &fvar
|
Expect(c.SNAT).To(Equal(&fvar))
|
||||||
|
Expect(c.Name).To(Equal("test"))
|
||||||
|
|
||||||
n, err = types.ParseCIDR("10.0.0.2/24")
|
|
||||||
fillDnatRules(&ch, conf, *n)
|
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("generates a correct chain with external mark", func() {
|
|
||||||
ch := genDnatChain(netName, containerID)
|
|
||||||
|
|
||||||
Expect(ch).To(Equal(chain{
|
|
||||||
table: "nat",
|
|
||||||
name: "CNI-DN-bfd599665540dd91d5d28",
|
|
||||||
entryChains: []string{TopLevelDNATChainName},
|
|
||||||
}))
|
|
||||||
configBytes := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"externalSetMarkChain": "PLZ-SET-MARK",
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"conditionsV6": ["c", "d"]
|
|
||||||
}`)
|
|
||||||
|
|
||||||
conf, _, err := parseConfig(configBytes, "foo")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
conf.ContainerID = containerID
|
|
||||||
|
|
||||||
ch = genDnatChain(conf.Name, containerID)
|
|
||||||
n, err := types.ParseCIDR("10.0.0.2/24")
|
n, err := types.ParseCIDR("10.0.0.2/24")
|
||||||
fillDnatRules(&ch, conf, *n)
|
Expect(c.ContIPv4).To(Equal(*n))
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
n, err = types.ParseCIDR("2001:db8:1::2/64")
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "PLZ-SET-MARK"},
|
Expect(c.ContIPv6).To(Equal(*n))
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "PLZ-SET-MARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("generates a correct top-level chain", func() {
|
It(fmt.Sprintf("[%s] correctly parses a DEL config", ver), func() {
|
||||||
ch := genToplevelDnatChain()
|
// When called with DEL, neither runtimeConfig nor prevResult may be specified
|
||||||
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
Expect(ch).To(Equal(chain{
|
"name": "test",
|
||||||
table: "nat",
|
"type": "portmap",
|
||||||
name: "CNI-HOSTPORT-DNAT",
|
"cniVersion": "%s",
|
||||||
entryChains: []string{"PREROUTING", "OUTPUT"},
|
"snat": false,
|
||||||
entryRules: [][]string{{"-m", "addrtype", "--dst-type", "LOCAL"}},
|
"conditionsV4": ["a", "b"],
|
||||||
}))
|
"conditionsV6": ["c", "d"]
|
||||||
|
}`, ver))
|
||||||
|
c, _, err := parseConfig(configBytes, "container")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(c.CNIVersion).To(Equal(ver))
|
||||||
|
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
||||||
|
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
||||||
|
fvar := false
|
||||||
|
Expect(c.SNAT).To(Equal(&fvar))
|
||||||
|
Expect(c.Name).To(Equal("test"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("generates the correct mark chains", func() {
|
It(fmt.Sprintf("[%s] fails with invalid mappings", ver), func() {
|
||||||
masqBit := 5
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
ch := genSetMarkChain(masqBit)
|
"name": "test",
|
||||||
Expect(ch).To(Equal(chain{
|
"type": "portmap",
|
||||||
table: "nat",
|
"cniVersion": "%s",
|
||||||
name: "CNI-HOSTPORT-SETMARK",
|
"snat": false,
|
||||||
rules: [][]string{{
|
"conditionsV4": ["a", "b"],
|
||||||
"-m", "comment",
|
"conditionsV6": ["c", "d"],
|
||||||
"--comment", "CNI portfwd masquerade mark",
|
"runtimeConfig": {
|
||||||
"-j", "MARK",
|
"portMappings": [
|
||||||
"--set-xmark", "0x20/0x20",
|
{ "hostPort": 0, "containerPort": 80, "protocol": "tcp"}
|
||||||
}},
|
]
|
||||||
}))
|
}
|
||||||
|
}`, ver))
|
||||||
|
_, _, err := parseConfig(configBytes, "container")
|
||||||
|
Expect(err).To(MatchError("Invalid host port number: 0"))
|
||||||
|
})
|
||||||
|
|
||||||
ch = genMarkMasqChain(masqBit)
|
It(fmt.Sprintf("[%s] does not fail on missing prevResult interface index", ver), func() {
|
||||||
Expect(ch).To(Equal(chain{
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
table: "nat",
|
"name": "test",
|
||||||
name: "CNI-HOSTPORT-MASQ",
|
"type": "portmap",
|
||||||
entryChains: []string{"POSTROUTING"},
|
"cniVersion": "%s",
|
||||||
entryRules: [][]string{{
|
"runtimeConfig": {
|
||||||
"-m", "comment",
|
"portMappings": [
|
||||||
"--comment", "CNI portfwd requiring masquerade",
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
||||||
}},
|
]
|
||||||
rules: [][]string{{
|
},
|
||||||
"-m", "mark",
|
"conditionsV4": ["a", "b"],
|
||||||
"--mark", "0x20/0x20",
|
"prevResult": {
|
||||||
"-j", "MASQUERADE",
|
"interfaces": [
|
||||||
}},
|
{"name": "host"}
|
||||||
prependEntry: true,
|
],
|
||||||
}))
|
"ips": [
|
||||||
|
{
|
||||||
|
"version": "4",
|
||||||
|
"address": "10.0.0.1/24",
|
||||||
|
"gateway": "10.0.0.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`, ver))
|
||||||
|
_, _, err := parseConfig(configBytes, "container")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
Describe("Generating chains", func() {
|
||||||
|
Context("for DNAT", func() {
|
||||||
|
It(fmt.Sprintf("[%s] generates a correct standard container chain", ver), func() {
|
||||||
|
ch := genDnatChain(netName, containerID)
|
||||||
|
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-DN-bfd599665540dd91d5d28",
|
||||||
|
entryChains: []string{TopLevelDNATChainName},
|
||||||
|
}))
|
||||||
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
|
"name": "test",
|
||||||
|
"type": "portmap",
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"runtimeConfig": {
|
||||||
|
"portMappings": [
|
||||||
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
||||||
|
{ "hostPort": 8081, "containerPort": 80, "protocol": "tcp"},
|
||||||
|
{ "hostPort": 8080, "containerPort": 81, "protocol": "udp"},
|
||||||
|
{ "hostPort": 8082, "containerPort": 82, "protocol": "udp"},
|
||||||
|
{ "hostPort": 8083, "containerPort": 83, "protocol": "tcp", "hostIP": "192.168.0.2"},
|
||||||
|
{ "hostPort": 8084, "containerPort": 84, "protocol": "tcp", "hostIP": "0.0.0.0"},
|
||||||
|
{ "hostPort": 8085, "containerPort": 85, "protocol": "tcp", "hostIP": "2001:db8:a::1"},
|
||||||
|
{ "hostPort": 8086, "containerPort": 86, "protocol": "tcp", "hostIP": "::"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"snat": true,
|
||||||
|
"conditionsV4": ["a", "b"],
|
||||||
|
"conditionsV6": ["c", "d"]
|
||||||
|
}`, ver))
|
||||||
|
|
||||||
|
conf, _, err := parseConfig(configBytes, "foo")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
conf.ContainerID = containerID
|
||||||
|
|
||||||
|
ch = genDnatChain(conf.Name, containerID)
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-DN-67e92b96e692a494b6b85",
|
||||||
|
entryChains: []string{"CNI-HOSTPORT-DNAT"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
n, err := types.ParseCIDR("10.0.0.2/24")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
|
||||||
|
Expect(ch.entryRules).To(Equal([][]string{
|
||||||
|
{"-m", "comment", "--comment",
|
||||||
|
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
||||||
|
"-m", "multiport",
|
||||||
|
"-p", "tcp",
|
||||||
|
"--destination-ports", "8080,8081,8083,8084,8085,8086",
|
||||||
|
"a", "b"},
|
||||||
|
{"-m", "comment", "--comment",
|
||||||
|
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
||||||
|
"-m", "multiport",
|
||||||
|
"-p", "udp",
|
||||||
|
"--destination-ports", "8080,8082",
|
||||||
|
"a", "b"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
// tcp rules and not hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
// udp rules and not hostIP
|
||||||
|
{"-p", "udp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
||||||
|
// tcp rules and hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
||||||
|
// tcp rules and hostIP = "0.0.0.0"
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
ch.rules = nil
|
||||||
|
ch.entryRules = nil
|
||||||
|
|
||||||
|
n, err = types.ParseCIDR("2001:db8::2/64")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
// tcp rules and not hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
||||||
|
// udp rules and not hostIP
|
||||||
|
{"-p", "udp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:81"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "[2001:db8::2]:82"},
|
||||||
|
// tcp rules and hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-j", "DNAT", "--to-destination", "[2001:db8::2]:85"},
|
||||||
|
// tcp rules and hostIP = "::"
|
||||||
|
{"-p", "tcp", "--dport", "8086", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8086", "-j", "DNAT", "--to-destination", "[2001:db8::2]:86"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Disable snat, generate rules
|
||||||
|
ch.rules = nil
|
||||||
|
ch.entryRules = nil
|
||||||
|
fvar := false
|
||||||
|
conf.SNAT = &fvar
|
||||||
|
|
||||||
|
n, err = types.ParseCIDR("10.0.0.2/24")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] generates a correct chain with external mark", ver), func() {
|
||||||
|
ch := genDnatChain(netName, containerID)
|
||||||
|
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-DN-bfd599665540dd91d5d28",
|
||||||
|
entryChains: []string{TopLevelDNATChainName},
|
||||||
|
}))
|
||||||
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
|
"name": "test",
|
||||||
|
"type": "portmap",
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"runtimeConfig": {
|
||||||
|
"portMappings": [
|
||||||
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"externalSetMarkChain": "PLZ-SET-MARK",
|
||||||
|
"conditionsV4": ["a", "b"],
|
||||||
|
"conditionsV6": ["c", "d"]
|
||||||
|
}`, ver))
|
||||||
|
|
||||||
|
conf, _, err := parseConfig(configBytes, "foo")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
conf.ContainerID = containerID
|
||||||
|
|
||||||
|
ch = genDnatChain(conf.Name, containerID)
|
||||||
|
n, err := types.ParseCIDR("10.0.0.2/24")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "PLZ-SET-MARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "PLZ-SET-MARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] generates a correct top-level chain", ver), func() {
|
||||||
|
ch := genToplevelDnatChain()
|
||||||
|
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-HOSTPORT-DNAT",
|
||||||
|
entryChains: []string{"PREROUTING", "OUTPUT"},
|
||||||
|
entryRules: [][]string{{"-m", "addrtype", "--dst-type", "LOCAL"}},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] generates the correct mark chains", ver), func() {
|
||||||
|
masqBit := 5
|
||||||
|
ch := genSetMarkChain(masqBit)
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-HOSTPORT-SETMARK",
|
||||||
|
rules: [][]string{{
|
||||||
|
"-m", "comment",
|
||||||
|
"--comment", "CNI portfwd masquerade mark",
|
||||||
|
"-j", "MARK",
|
||||||
|
"--set-xmark", "0x20/0x20",
|
||||||
|
}},
|
||||||
|
}))
|
||||||
|
|
||||||
|
ch = genMarkMasqChain(masqBit)
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-HOSTPORT-MASQ",
|
||||||
|
entryChains: []string{"POSTROUTING"},
|
||||||
|
entryRules: [][]string{{
|
||||||
|
"-m", "comment",
|
||||||
|
"--comment", "CNI portfwd requiring masquerade",
|
||||||
|
}},
|
||||||
|
rules: [][]string{{
|
||||||
|
"-m", "mark",
|
||||||
|
"--mark", "0x20/0x20",
|
||||||
|
"-j", "MASQUERADE",
|
||||||
|
}},
|
||||||
|
prependEntry: true,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
@ -234,7 +234,7 @@ func doRoutes(ipCfgs []*current.IPConfig, origRoutes []*types.Route, iface strin
|
|||||||
// Source must be restricted to a single IP, not a full subnet
|
// Source must be restricted to a single IP, not a full subnet
|
||||||
var src net.IPNet
|
var src net.IPNet
|
||||||
src.IP = ipCfg.Address.IP
|
src.IP = ipCfg.Address.IP
|
||||||
if ipCfg.Version == "4" {
|
if src.IP.To4() != nil {
|
||||||
src.Mask = net.CIDRMask(32, 32)
|
src.Mask = net.CIDRMask(32, 32)
|
||||||
} else {
|
} else {
|
||||||
src.Mask = net.CIDRMask(128, 128)
|
src.Mask = net.CIDRMask(128, 128)
|
||||||
@ -253,7 +253,7 @@ func doRoutes(ipCfgs []*current.IPConfig, origRoutes []*types.Route, iface strin
|
|||||||
log.Printf("Adding default route to gateway %s", ipCfg.Gateway.String())
|
log.Printf("Adding default route to gateway %s", ipCfg.Gateway.String())
|
||||||
|
|
||||||
var dest net.IPNet
|
var dest net.IPNet
|
||||||
if ipCfg.Version == "4" {
|
if ipCfg.Address.IP.To4() != nil {
|
||||||
dest.IP = net.IPv4zero
|
dest.IP = net.IPv4zero
|
||||||
dest.Mask = net.CIDRMask(0, 32)
|
dest.Mask = net.CIDRMask(0, 32)
|
||||||
} else {
|
} else {
|
||||||
|
@ -241,6 +241,7 @@ var _ = Describe("sbr test", func() {
|
|||||||
"name": "cni-plugin-sbr-test",
|
"name": "cni-plugin-sbr-test",
|
||||||
"type": "sbr",
|
"type": "sbr",
|
||||||
"prevResult": {
|
"prevResult": {
|
||||||
|
"cniVersion": "0.3.0",
|
||||||
"interfaces": [
|
"interfaces": [
|
||||||
{
|
{
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
@ -332,6 +333,7 @@ var _ = Describe("sbr test", func() {
|
|||||||
"name": "cni-plugin-sbr-test",
|
"name": "cni-plugin-sbr-test",
|
||||||
"type": "sbr",
|
"type": "sbr",
|
||||||
"prevResult": {
|
"prevResult": {
|
||||||
|
"cniVersion": "0.3.0",
|
||||||
"interfaces": [
|
"interfaces": [
|
||||||
{
|
{
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
@ -399,19 +401,12 @@ var _ = Describe("sbr test", func() {
|
|||||||
Expect(equalRoutes(expNet1.Routes, devNet1.Routes)).To(BeTrue())
|
Expect(equalRoutes(expNet1.Routes, devNet1.Routes)).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("works with a 0.2.0 config", func() {
|
It("fails with CNI spec versions that don't support plugin chaining", func() {
|
||||||
conf := `{
|
conf := `{
|
||||||
"cniVersion": "0.2.0",
|
"cniVersion": "0.2.0",
|
||||||
"name": "cni-plugin-sbr-test",
|
"name": "cni-plugin-sbr-test",
|
||||||
"type": "sbr",
|
"type": "sbr",
|
||||||
"anotherAwesomeArg": "foo",
|
"anotherAwesomeArg": "foo"
|
||||||
"prevResult": {
|
|
||||||
"ip4": {
|
|
||||||
"ip": "192.168.1.209/24",
|
|
||||||
"gateway": "192.168.1.1",
|
|
||||||
"routes": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
}`
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
args := &skel.CmdArgs{
|
||||||
@ -424,7 +419,7 @@ var _ = Describe("sbr test", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
_, _, err = testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
_, _, err = testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).To(MatchError("This plugin must be called as chained plugin"))
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -32,7 +32,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
@ -322,7 +322,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ipc := range result.IPs {
|
for _, ipc := range result.IPs {
|
||||||
if ipc.Version == "4" {
|
if ipc.Address.IP.To4() != nil {
|
||||||
_ = arping.GratuitousArpOverIfaceByName(ipc.Address.IP, args.IfName)
|
_ = arping.GratuitousArpOverIfaceByName(ipc.Address.IP, args.IfName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -22,7 +22,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
|
|
||||||
|
@ -19,11 +19,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
current "github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||||
@ -33,21 +32,15 @@ import (
|
|||||||
// is passed in on stdin. Your plugin may wish to expose its functionality via
|
// is passed in on stdin. Your plugin may wish to expose its functionality via
|
||||||
// runtime args, see CONVENTIONS.md in the CNI spec.
|
// runtime args, see CONVENTIONS.md in the CNI spec.
|
||||||
type PluginConf struct {
|
type PluginConf struct {
|
||||||
types.NetConf // You may wish to not nest this type
|
// This embeds the standard NetConf structure which allows your plugin
|
||||||
|
// to more easily parse standard fields like Name, Type, CNIVersion,
|
||||||
|
// and PrevResult.
|
||||||
|
types.NetConf
|
||||||
|
|
||||||
RuntimeConfig *struct {
|
RuntimeConfig *struct {
|
||||||
SampleConfig map[string]interface{} `json:"sample"`
|
SampleConfig map[string]interface{} `json:"sample"`
|
||||||
} `json:"runtimeConfig"`
|
} `json:"runtimeConfig"`
|
||||||
|
|
||||||
// This is the previous result, when called in the context of a chained
|
|
||||||
// plugin. Because this plugin supports multiple versions, we'll have to
|
|
||||||
// parse this in two passes. If your plugin is not chained, this can be
|
|
||||||
// removed (though you may wish to error if a non-chainable plugin is
|
|
||||||
// chained.
|
|
||||||
// If you need to modify the result before returning it, you will need
|
|
||||||
// to actually convert it to a concrete versioned struct.
|
|
||||||
RawPrevResult *map[string]interface{} `json:"prevResult"`
|
|
||||||
PrevResult *current.Result `json:"-"`
|
|
||||||
|
|
||||||
// Add plugin-specifc flags here
|
// Add plugin-specifc flags here
|
||||||
MyAwesomeFlag bool `json:"myAwesomeFlag"`
|
MyAwesomeFlag bool `json:"myAwesomeFlag"`
|
||||||
AnotherAwesomeArg string `json:"anotherAwesomeArg"`
|
AnotherAwesomeArg string `json:"anotherAwesomeArg"`
|
||||||
@ -61,21 +54,12 @@ func parseConfig(stdin []byte) (*PluginConf, error) {
|
|||||||
return nil, fmt.Errorf("failed to parse network configuration: %v", err)
|
return nil, fmt.Errorf("failed to parse network configuration: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse previous result. Remove this if your plugin is not chained.
|
// Parse previous result. This will parse, validate, and place the
|
||||||
if conf.RawPrevResult != nil {
|
// previous result object into conf.PrevResult. If you need to modify
|
||||||
resultBytes, err := json.Marshal(conf.RawPrevResult)
|
// or inspect the PrevResult you will need to convert it to a concrete
|
||||||
if err != nil {
|
// versioned Result struct.
|
||||||
return nil, fmt.Errorf("could not serialize prevResult: %v", err)
|
if err := version.ParsePrevResult(&conf.NetConf); err != nil {
|
||||||
}
|
return nil, fmt.Errorf("could not parse prevResult: %v", err)
|
||||||
res, err := version.NewResult(conf.CNIVersion, resultBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not parse prevResult: %v", err)
|
|
||||||
}
|
|
||||||
conf.RawPrevResult = nil
|
|
||||||
conf.PrevResult, err = current.NewResultFromResult(res)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not convert result to current version: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// End previous result parsing
|
// End previous result parsing
|
||||||
|
|
||||||
@ -94,50 +78,62 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove this if this is an "originating" plugin
|
// A plugin can be either an "originating" plugin or a "chained" plugin.
|
||||||
|
// Originating plugins perform initial sandbox setup and do not require
|
||||||
|
// any result from a previous plugin in the chain. A chained plugin
|
||||||
|
// modifies sandbox configuration that was previously set up by an
|
||||||
|
// originating plugin and may optionally require a PrevResult from
|
||||||
|
// earlier plugins in the chain.
|
||||||
|
|
||||||
|
// START chained plugin code
|
||||||
if conf.PrevResult == nil {
|
if conf.PrevResult == nil {
|
||||||
return fmt.Errorf("must be called as chained plugin")
|
return fmt.Errorf("must be called as chained plugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uncomment if this is an "originating" plugin
|
// Convert the PrevResult to a concrete Result type that can be modified.
|
||||||
|
prevResult, err := current.GetResult(conf.PrevResult)
|
||||||
//if conf.PrevResult != nil {
|
if err != nil {
|
||||||
// return fmt.Errorf("must be called as the first plugin")
|
return fmt.Errorf("failed to convert prevResult: %v", err)
|
||||||
// }
|
|
||||||
|
|
||||||
// This is some sample code to generate the list of container-side IPs.
|
|
||||||
// We're casting the prevResult to a 0.3.0 response, which can also include
|
|
||||||
// host-side IPs (but doesn't when converted from a 0.2.0 response).
|
|
||||||
//
|
|
||||||
// You don't need this if you are writing an "originating" plugin.
|
|
||||||
containerIPs := make([]net.IP, 0, len(conf.PrevResult.IPs))
|
|
||||||
if conf.CNIVersion != "0.3.0" {
|
|
||||||
for _, ip := range conf.PrevResult.IPs {
|
|
||||||
containerIPs = append(containerIPs, ip.Address.IP)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, ip := range conf.PrevResult.IPs {
|
|
||||||
if ip.Interface == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
intIdx := *ip.Interface
|
|
||||||
// Every IP is indexed in to the interfaces array, with "-1" standing
|
|
||||||
// for an unknown interface (which we'll assume to be Container-side
|
|
||||||
// Skip all IPs we know belong to an interface with the wrong name.
|
|
||||||
if intIdx >= 0 && intIdx < len(conf.PrevResult.Interfaces) && conf.PrevResult.Interfaces[intIdx].Name != args.IfName {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
containerIPs = append(containerIPs, ip.Address.IP)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(containerIPs) == 0 {
|
|
||||||
|
if len(prevResult.IPs) == 0 {
|
||||||
return fmt.Errorf("got no container IPs")
|
return fmt.Errorf("got no container IPs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass the prevResult through this plugin to the next one
|
||||||
|
result := prevResult
|
||||||
|
|
||||||
|
// END chained plugin code
|
||||||
|
|
||||||
|
// START originating plugin code
|
||||||
|
// if conf.PrevResult != nil {
|
||||||
|
// return fmt.Errorf("must be called as the first plugin")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Generate some fake container IPs and add to the result
|
||||||
|
// result := ¤t.Result{CNIVersion: current.ImplementedSpecVersion}
|
||||||
|
// result.Interfaces = []*current.Interface{
|
||||||
|
// {
|
||||||
|
// Name: "intf0",
|
||||||
|
// Sandbox: args.Netns,
|
||||||
|
// Mac: "00:11:22:33:44:55",
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// result.IPs = []*current.IPConfig{
|
||||||
|
// {
|
||||||
|
// Address: "1.2.3.4/24",
|
||||||
|
// Gateway: "1.2.3.1",
|
||||||
|
// // Interface is an index into the Interfaces array
|
||||||
|
// // of the Interface element this IP applies to
|
||||||
|
// Interface: current.Int(0),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// END originating plugin code
|
||||||
|
|
||||||
// Implement your plugin here
|
// Implement your plugin here
|
||||||
|
|
||||||
// Pass through the result for the next plugin
|
// Pass through the result for the next plugin
|
||||||
return types.PrintResult(conf.PrevResult, conf.CNIVersion)
|
return types.PrintResult(result, conf.CNIVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmdDel is called for DELETE requests
|
// cmdDel is called for DELETE requests
|
||||||
|
@ -45,6 +45,7 @@ var _ = Describe("sample test", func() {
|
|||||||
"type": "sample",
|
"type": "sample",
|
||||||
"anotherAwesomeArg": "awesome",
|
"anotherAwesomeArg": "awesome",
|
||||||
"prevResult": {
|
"prevResult": {
|
||||||
|
"cniVersion": "0.3.0",
|
||||||
"interfaces": [
|
"interfaces": [
|
||||||
{
|
{
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
@ -71,7 +72,6 @@ var _ = Describe("sample test", func() {
|
|||||||
}
|
}
|
||||||
_, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
_, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("fails an invalid config", func() {
|
It("fails an invalid config", func() {
|
||||||
@ -106,22 +106,14 @@ var _ = Describe("sample test", func() {
|
|||||||
}
|
}
|
||||||
_, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
_, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||||
Expect(err).To(MatchError("anotherAwesomeArg must be specified"))
|
Expect(err).To(MatchError("anotherAwesomeArg must be specified"))
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("works with a 0.2.0 config", func() {
|
It("fails with CNI spec versions that don't support plugin chaining", func() {
|
||||||
conf := `{
|
conf := `{
|
||||||
"cniVersion": "0.2.0",
|
"cniVersion": "0.2.0",
|
||||||
"name": "cni-plugin-sample-test",
|
"name": "cni-plugin-sample-test",
|
||||||
"type": "sample",
|
"type": "sample",
|
||||||
"anotherAwesomeArg": "foo",
|
"anotherAwesomeArg": "foo"
|
||||||
"prevResult": {
|
|
||||||
"ip4": {
|
|
||||||
"ip": "10.0.0.2/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"routes": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
}`
|
||||||
|
|
||||||
args := &skel.CmdArgs{
|
args := &skel.CmdArgs{
|
||||||
@ -131,8 +123,7 @@ var _ = Describe("sample test", func() {
|
|||||||
StdinData: []byte(conf),
|
StdinData: []byte(conf),
|
||||||
}
|
}
|
||||||
_, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
_, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).To(MatchError("must be called as chained plugin"))
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
82
vendor/github.com/containernetworking/cni/pkg/types/020/types.go
generated
vendored
82
vendor/github.com/containernetworking/cni/pkg/types/020/types.go
generated
vendored
@ -22,25 +22,44 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
convert "github.com/containernetworking/cni/pkg/types/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ImplementedSpecVersion string = "0.2.0"
|
const ImplementedSpecVersion string = "0.2.0"
|
||||||
|
|
||||||
var SupportedVersions = []string{"", "0.1.0", ImplementedSpecVersion}
|
var supportedVersions = []string{"", "0.1.0", ImplementedSpecVersion}
|
||||||
|
|
||||||
|
// Register converters for all versions less than the implemented spec version
|
||||||
|
func init() {
|
||||||
|
convert.RegisterConverter("0.1.0", []string{ImplementedSpecVersion}, convertFrom010)
|
||||||
|
convert.RegisterConverter(ImplementedSpecVersion, []string{"0.1.0"}, convertTo010)
|
||||||
|
|
||||||
|
// Creator
|
||||||
|
convert.RegisterCreator(supportedVersions, NewResult)
|
||||||
|
}
|
||||||
|
|
||||||
// Compatibility types for CNI version 0.1.0 and 0.2.0
|
// Compatibility types for CNI version 0.1.0 and 0.2.0
|
||||||
|
|
||||||
|
// NewResult creates a new Result object from JSON data. The JSON data
|
||||||
|
// must be compatible with the CNI versions implemented by this type.
|
||||||
func NewResult(data []byte) (types.Result, error) {
|
func NewResult(data []byte) (types.Result, error) {
|
||||||
result := &Result{}
|
result := &Result{}
|
||||||
if err := json.Unmarshal(data, result); err != nil {
|
if err := json.Unmarshal(data, result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return result, nil
|
for _, v := range supportedVersions {
|
||||||
|
if result.CNIVersion == v {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q",
|
||||||
|
supportedVersions, result.CNIVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResult converts the given Result object to the ImplementedSpecVersion
|
||||||
|
// and returns the concrete type or an error
|
||||||
func GetResult(r types.Result) (*Result, error) {
|
func GetResult(r types.Result) (*Result, error) {
|
||||||
// We expect version 0.1.0/0.2.0 results
|
result020, err := convert.Convert(r, ImplementedSpecVersion)
|
||||||
result020, err := r.GetAsVersion(ImplementedSpecVersion)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -51,6 +70,32 @@ func GetResult(r types.Result) (*Result, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertFrom010(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
if toVersion != "0.2.0" {
|
||||||
|
panic("only converts to version 0.2.0")
|
||||||
|
}
|
||||||
|
fromResult := from.(*Result)
|
||||||
|
return &Result{
|
||||||
|
CNIVersion: ImplementedSpecVersion,
|
||||||
|
IP4: fromResult.IP4.Copy(),
|
||||||
|
IP6: fromResult.IP6.Copy(),
|
||||||
|
DNS: *fromResult.DNS.Copy(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTo010(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
if toVersion != "0.1.0" {
|
||||||
|
panic("only converts to version 0.1.0")
|
||||||
|
}
|
||||||
|
fromResult := from.(*Result)
|
||||||
|
return &Result{
|
||||||
|
CNIVersion: "0.1.0",
|
||||||
|
IP4: fromResult.IP4.Copy(),
|
||||||
|
IP6: fromResult.IP6.Copy(),
|
||||||
|
DNS: *fromResult.DNS.Copy(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Result is what gets returned from the plugin (via stdout) to the caller
|
// Result is what gets returned from the plugin (via stdout) to the caller
|
||||||
type Result struct {
|
type Result struct {
|
||||||
CNIVersion string `json:"cniVersion,omitempty"`
|
CNIVersion string `json:"cniVersion,omitempty"`
|
||||||
@ -60,17 +105,16 @@ type Result struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) Version() string {
|
func (r *Result) Version() string {
|
||||||
return ImplementedSpecVersion
|
return r.CNIVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
||||||
for _, supportedVersion := range SupportedVersions {
|
// If the creator of the result did not set the CNIVersion, assume it
|
||||||
if version == supportedVersion {
|
// should be the highest spec version implemented by this Result
|
||||||
r.CNIVersion = version
|
if r.CNIVersion == "" {
|
||||||
return r, nil
|
r.CNIVersion = ImplementedSpecVersion
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("cannot convert version %q to %s", SupportedVersions, version)
|
return convert.Convert(r, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) Print() error {
|
func (r *Result) Print() error {
|
||||||
@ -93,6 +137,22 @@ type IPConfig struct {
|
|||||||
Routes []types.Route
|
Routes []types.Route
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *IPConfig) Copy() *IPConfig {
|
||||||
|
if i == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var routes []types.Route
|
||||||
|
for _, fromRoute := range i.Routes {
|
||||||
|
routes = append(routes, *fromRoute.Copy())
|
||||||
|
}
|
||||||
|
return &IPConfig{
|
||||||
|
IP: i.IP,
|
||||||
|
Gateway: i.Gateway,
|
||||||
|
Routes: routes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// net.IPNet is not JSON (un)marshallable so this duality is needed
|
// net.IPNet is not JSON (un)marshallable so this duality is needed
|
||||||
// for our custom IPNet type
|
// for our custom IPNet type
|
||||||
|
|
||||||
|
305
vendor/github.com/containernetworking/cni/pkg/types/040/types.go
generated
vendored
Normal file
305
vendor/github.com/containernetworking/cni/pkg/types/040/types.go
generated
vendored
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
// Copyright 2016 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package types040
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
types020 "github.com/containernetworking/cni/pkg/types/020"
|
||||||
|
convert "github.com/containernetworking/cni/pkg/types/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ImplementedSpecVersion string = "0.4.0"
|
||||||
|
|
||||||
|
var supportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion}
|
||||||
|
|
||||||
|
// Register converters for all versions less than the implemented spec version
|
||||||
|
func init() {
|
||||||
|
// Up-converters
|
||||||
|
convert.RegisterConverter("0.1.0", supportedVersions, convertFrom02x)
|
||||||
|
convert.RegisterConverter("0.2.0", supportedVersions, convertFrom02x)
|
||||||
|
convert.RegisterConverter("0.3.0", supportedVersions, convertInternal)
|
||||||
|
convert.RegisterConverter("0.3.1", supportedVersions, convertInternal)
|
||||||
|
|
||||||
|
// Down-converters
|
||||||
|
convert.RegisterConverter("0.4.0", []string{"0.3.0", "0.3.1"}, convertInternal)
|
||||||
|
convert.RegisterConverter("0.4.0", []string{"0.1.0", "0.2.0"}, convertTo02x)
|
||||||
|
convert.RegisterConverter("0.3.1", []string{"0.1.0", "0.2.0"}, convertTo02x)
|
||||||
|
convert.RegisterConverter("0.3.0", []string{"0.1.0", "0.2.0"}, convertTo02x)
|
||||||
|
|
||||||
|
// Creator
|
||||||
|
convert.RegisterCreator(supportedVersions, NewResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResult(data []byte) (types.Result, error) {
|
||||||
|
result := &Result{}
|
||||||
|
if err := json.Unmarshal(data, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range supportedVersions {
|
||||||
|
if result.CNIVersion == v {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q",
|
||||||
|
supportedVersions, result.CNIVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetResult(r types.Result) (*Result, error) {
|
||||||
|
resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result, ok := resultCurrent.(*Result)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to convert result")
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResultFromResult(result types.Result) (*Result, error) {
|
||||||
|
newResult, err := convert.Convert(result, ImplementedSpecVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newResult.(*Result), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result is what gets returned from the plugin (via stdout) to the caller
|
||||||
|
type Result struct {
|
||||||
|
CNIVersion string `json:"cniVersion,omitempty"`
|
||||||
|
Interfaces []*Interface `json:"interfaces,omitempty"`
|
||||||
|
IPs []*IPConfig `json:"ips,omitempty"`
|
||||||
|
Routes []*types.Route `json:"routes,omitempty"`
|
||||||
|
DNS types.DNS `json:"dns,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert020IPConfig(from *types020.IPConfig, ipVersion string) *IPConfig {
|
||||||
|
return &IPConfig{
|
||||||
|
Version: ipVersion,
|
||||||
|
Address: from.IP,
|
||||||
|
Gateway: from.Gateway,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFrom02x(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
fromResult := from.(*types020.Result)
|
||||||
|
toResult := &Result{
|
||||||
|
CNIVersion: toVersion,
|
||||||
|
DNS: *fromResult.DNS.Copy(),
|
||||||
|
Routes: []*types.Route{},
|
||||||
|
}
|
||||||
|
if fromResult.IP4 != nil {
|
||||||
|
toResult.IPs = append(toResult.IPs, convert020IPConfig(fromResult.IP4, "4"))
|
||||||
|
for _, fromRoute := range fromResult.IP4.Routes {
|
||||||
|
toResult.Routes = append(toResult.Routes, fromRoute.Copy())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fromResult.IP6 != nil {
|
||||||
|
toResult.IPs = append(toResult.IPs, convert020IPConfig(fromResult.IP6, "6"))
|
||||||
|
for _, fromRoute := range fromResult.IP6.Routes {
|
||||||
|
toResult.Routes = append(toResult.Routes, fromRoute.Copy())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return toResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertInternal(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
fromResult := from.(*Result)
|
||||||
|
toResult := &Result{
|
||||||
|
CNIVersion: toVersion,
|
||||||
|
DNS: *fromResult.DNS.Copy(),
|
||||||
|
Routes: []*types.Route{},
|
||||||
|
}
|
||||||
|
for _, fromIntf := range fromResult.Interfaces {
|
||||||
|
toResult.Interfaces = append(toResult.Interfaces, fromIntf.Copy())
|
||||||
|
}
|
||||||
|
for _, fromIPC := range fromResult.IPs {
|
||||||
|
toResult.IPs = append(toResult.IPs, fromIPC.Copy())
|
||||||
|
}
|
||||||
|
for _, fromRoute := range fromResult.Routes {
|
||||||
|
toResult.Routes = append(toResult.Routes, fromRoute.Copy())
|
||||||
|
}
|
||||||
|
return toResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTo02x(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
fromResult := from.(*Result)
|
||||||
|
toResult := &types020.Result{
|
||||||
|
CNIVersion: toVersion,
|
||||||
|
DNS: *fromResult.DNS.Copy(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fromIP := range fromResult.IPs {
|
||||||
|
// Only convert the first IP address of each version as 0.2.0
|
||||||
|
// and earlier cannot handle multiple IP addresses
|
||||||
|
if fromIP.Version == "4" && toResult.IP4 == nil {
|
||||||
|
toResult.IP4 = &types020.IPConfig{
|
||||||
|
IP: fromIP.Address,
|
||||||
|
Gateway: fromIP.Gateway,
|
||||||
|
}
|
||||||
|
} else if fromIP.Version == "6" && toResult.IP6 == nil {
|
||||||
|
toResult.IP6 = &types020.IPConfig{
|
||||||
|
IP: fromIP.Address,
|
||||||
|
Gateway: fromIP.Gateway,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if toResult.IP4 != nil && toResult.IP6 != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fromRoute := range fromResult.Routes {
|
||||||
|
is4 := fromRoute.Dst.IP.To4() != nil
|
||||||
|
if is4 && toResult.IP4 != nil {
|
||||||
|
toResult.IP4.Routes = append(toResult.IP4.Routes, types.Route{
|
||||||
|
Dst: fromRoute.Dst,
|
||||||
|
GW: fromRoute.GW,
|
||||||
|
})
|
||||||
|
} else if !is4 && toResult.IP6 != nil {
|
||||||
|
toResult.IP6.Routes = append(toResult.IP6.Routes, types.Route{
|
||||||
|
Dst: fromRoute.Dst,
|
||||||
|
GW: fromRoute.GW,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if toResult.IP4 == nil && toResult.IP6 == nil {
|
||||||
|
return nil, fmt.Errorf("cannot convert: no valid IP addresses")
|
||||||
|
}
|
||||||
|
|
||||||
|
return toResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) Version() string {
|
||||||
|
return r.CNIVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
||||||
|
// If the creator of the result did not set the CNIVersion, assume it
|
||||||
|
// should be the highest spec version implemented by this Result
|
||||||
|
if r.CNIVersion == "" {
|
||||||
|
r.CNIVersion = ImplementedSpecVersion
|
||||||
|
}
|
||||||
|
return convert.Convert(r, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) Print() error {
|
||||||
|
return r.PrintTo(os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) PrintTo(writer io.Writer) error {
|
||||||
|
data, err := json.MarshalIndent(r, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = writer.Write(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface contains values about the created interfaces
|
||||||
|
type Interface struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Mac string `json:"mac,omitempty"`
|
||||||
|
Sandbox string `json:"sandbox,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interface) String() string {
|
||||||
|
return fmt.Sprintf("%+v", *i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interface) Copy() *Interface {
|
||||||
|
if i == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newIntf := *i
|
||||||
|
return &newIntf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns a pointer to the int value passed in. Used to
|
||||||
|
// set the IPConfig.Interface field.
|
||||||
|
func Int(v int) *int {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPConfig contains values necessary to configure an IP address on an interface
|
||||||
|
type IPConfig struct {
|
||||||
|
// IP version, either "4" or "6"
|
||||||
|
Version string
|
||||||
|
// Index into Result structs Interfaces list
|
||||||
|
Interface *int
|
||||||
|
Address net.IPNet
|
||||||
|
Gateway net.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPConfig) String() string {
|
||||||
|
return fmt.Sprintf("%+v", *i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPConfig) Copy() *IPConfig {
|
||||||
|
if i == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ipc := &IPConfig{
|
||||||
|
Version: i.Version,
|
||||||
|
Address: i.Address,
|
||||||
|
Gateway: i.Gateway,
|
||||||
|
}
|
||||||
|
if i.Interface != nil {
|
||||||
|
intf := *i.Interface
|
||||||
|
ipc.Interface = &intf
|
||||||
|
}
|
||||||
|
return ipc
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON (un)marshallable types
|
||||||
|
type ipConfig struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Interface *int `json:"interface,omitempty"`
|
||||||
|
Address types.IPNet `json:"address"`
|
||||||
|
Gateway net.IP `json:"gateway,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IPConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
ipc := ipConfig{
|
||||||
|
Version: c.Version,
|
||||||
|
Interface: c.Interface,
|
||||||
|
Address: types.IPNet(c.Address),
|
||||||
|
Gateway: c.Gateway,
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(ipc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IPConfig) UnmarshalJSON(data []byte) error {
|
||||||
|
ipc := ipConfig{}
|
||||||
|
if err := json.Unmarshal(data, &ipc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Version = ipc.Version
|
||||||
|
c.Interface = ipc.Interface
|
||||||
|
c.Address = net.IPNet(ipc.Address)
|
||||||
|
c.Gateway = ipc.Gateway
|
||||||
|
return nil
|
||||||
|
}
|
307
vendor/github.com/containernetworking/cni/pkg/types/100/types.go
generated
vendored
Normal file
307
vendor/github.com/containernetworking/cni/pkg/types/100/types.go
generated
vendored
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
// Copyright 2016 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package types100
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
types040 "github.com/containernetworking/cni/pkg/types/040"
|
||||||
|
convert "github.com/containernetworking/cni/pkg/types/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ImplementedSpecVersion string = "1.0.0"
|
||||||
|
|
||||||
|
var supportedVersions = []string{ImplementedSpecVersion}
|
||||||
|
|
||||||
|
// Register converters for all versions less than the implemented spec version
|
||||||
|
func init() {
|
||||||
|
// Up-converters
|
||||||
|
convert.RegisterConverter("0.1.0", supportedVersions, convertFrom02x)
|
||||||
|
convert.RegisterConverter("0.2.0", supportedVersions, convertFrom02x)
|
||||||
|
convert.RegisterConverter("0.3.0", supportedVersions, convertFrom04x)
|
||||||
|
convert.RegisterConverter("0.3.1", supportedVersions, convertFrom04x)
|
||||||
|
convert.RegisterConverter("0.4.0", supportedVersions, convertFrom04x)
|
||||||
|
|
||||||
|
// Down-converters
|
||||||
|
convert.RegisterConverter("1.0.0", []string{"0.3.0", "0.3.1", "0.4.0"}, convertTo04x)
|
||||||
|
convert.RegisterConverter("1.0.0", []string{"0.1.0", "0.2.0"}, convertTo02x)
|
||||||
|
|
||||||
|
// Creator
|
||||||
|
convert.RegisterCreator(supportedVersions, NewResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResult(data []byte) (types.Result, error) {
|
||||||
|
result := &Result{}
|
||||||
|
if err := json.Unmarshal(data, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range supportedVersions {
|
||||||
|
if result.CNIVersion == v {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q",
|
||||||
|
supportedVersions, result.CNIVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetResult(r types.Result) (*Result, error) {
|
||||||
|
resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result, ok := resultCurrent.(*Result)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to convert result")
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResultFromResult(result types.Result) (*Result, error) {
|
||||||
|
newResult, err := convert.Convert(result, ImplementedSpecVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newResult.(*Result), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result is what gets returned from the plugin (via stdout) to the caller
|
||||||
|
type Result struct {
|
||||||
|
CNIVersion string `json:"cniVersion,omitempty"`
|
||||||
|
Interfaces []*Interface `json:"interfaces,omitempty"`
|
||||||
|
IPs []*IPConfig `json:"ips,omitempty"`
|
||||||
|
Routes []*types.Route `json:"routes,omitempty"`
|
||||||
|
DNS types.DNS `json:"dns,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFrom02x(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
result040, err := convert.Convert(from, "0.4.0")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result100, err := convertFrom04x(result040, ImplementedSpecVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result100, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertIPConfigFrom040(from *types040.IPConfig) *IPConfig {
|
||||||
|
to := &IPConfig{
|
||||||
|
Address: from.Address,
|
||||||
|
Gateway: from.Gateway,
|
||||||
|
}
|
||||||
|
if from.Interface != nil {
|
||||||
|
intf := *from.Interface
|
||||||
|
to.Interface = &intf
|
||||||
|
}
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertInterfaceFrom040(from *types040.Interface) *Interface {
|
||||||
|
return &Interface{
|
||||||
|
Name: from.Name,
|
||||||
|
Mac: from.Mac,
|
||||||
|
Sandbox: from.Sandbox,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFrom04x(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
fromResult := from.(*types040.Result)
|
||||||
|
toResult := &Result{
|
||||||
|
CNIVersion: toVersion,
|
||||||
|
DNS: *fromResult.DNS.Copy(),
|
||||||
|
Routes: []*types.Route{},
|
||||||
|
}
|
||||||
|
for _, fromIntf := range fromResult.Interfaces {
|
||||||
|
toResult.Interfaces = append(toResult.Interfaces, convertInterfaceFrom040(fromIntf))
|
||||||
|
}
|
||||||
|
for _, fromIPC := range fromResult.IPs {
|
||||||
|
toResult.IPs = append(toResult.IPs, convertIPConfigFrom040(fromIPC))
|
||||||
|
}
|
||||||
|
for _, fromRoute := range fromResult.Routes {
|
||||||
|
toResult.Routes = append(toResult.Routes, fromRoute.Copy())
|
||||||
|
}
|
||||||
|
return toResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertIPConfigTo040(from *IPConfig) *types040.IPConfig {
|
||||||
|
version := "6"
|
||||||
|
if from.Address.IP.To4() != nil {
|
||||||
|
version = "4"
|
||||||
|
}
|
||||||
|
to := &types040.IPConfig{
|
||||||
|
Version: version,
|
||||||
|
Address: from.Address,
|
||||||
|
Gateway: from.Gateway,
|
||||||
|
}
|
||||||
|
if from.Interface != nil {
|
||||||
|
intf := *from.Interface
|
||||||
|
to.Interface = &intf
|
||||||
|
}
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertInterfaceTo040(from *Interface) *types040.Interface {
|
||||||
|
return &types040.Interface{
|
||||||
|
Name: from.Name,
|
||||||
|
Mac: from.Mac,
|
||||||
|
Sandbox: from.Sandbox,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTo04x(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
fromResult := from.(*Result)
|
||||||
|
toResult := &types040.Result{
|
||||||
|
CNIVersion: toVersion,
|
||||||
|
DNS: *fromResult.DNS.Copy(),
|
||||||
|
Routes: []*types.Route{},
|
||||||
|
}
|
||||||
|
for _, fromIntf := range fromResult.Interfaces {
|
||||||
|
toResult.Interfaces = append(toResult.Interfaces, convertInterfaceTo040(fromIntf))
|
||||||
|
}
|
||||||
|
for _, fromIPC := range fromResult.IPs {
|
||||||
|
toResult.IPs = append(toResult.IPs, convertIPConfigTo040(fromIPC))
|
||||||
|
}
|
||||||
|
for _, fromRoute := range fromResult.Routes {
|
||||||
|
toResult.Routes = append(toResult.Routes, fromRoute.Copy())
|
||||||
|
}
|
||||||
|
return toResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTo02x(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
// First convert to 0.4.0
|
||||||
|
result040, err := convertTo04x(from, "0.4.0")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result02x, err := convert.Convert(result040, toVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result02x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) Version() string {
|
||||||
|
return r.CNIVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
||||||
|
// If the creator of the result did not set the CNIVersion, assume it
|
||||||
|
// should be the highest spec version implemented by this Result
|
||||||
|
if r.CNIVersion == "" {
|
||||||
|
r.CNIVersion = ImplementedSpecVersion
|
||||||
|
}
|
||||||
|
return convert.Convert(r, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) Print() error {
|
||||||
|
return r.PrintTo(os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) PrintTo(writer io.Writer) error {
|
||||||
|
data, err := json.MarshalIndent(r, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = writer.Write(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface contains values about the created interfaces
|
||||||
|
type Interface struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Mac string `json:"mac,omitempty"`
|
||||||
|
Sandbox string `json:"sandbox,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interface) String() string {
|
||||||
|
return fmt.Sprintf("%+v", *i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interface) Copy() *Interface {
|
||||||
|
if i == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newIntf := *i
|
||||||
|
return &newIntf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns a pointer to the int value passed in. Used to
|
||||||
|
// set the IPConfig.Interface field.
|
||||||
|
func Int(v int) *int {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPConfig contains values necessary to configure an IP address on an interface
|
||||||
|
type IPConfig struct {
|
||||||
|
// Index into Result structs Interfaces list
|
||||||
|
Interface *int
|
||||||
|
Address net.IPNet
|
||||||
|
Gateway net.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPConfig) String() string {
|
||||||
|
return fmt.Sprintf("%+v", *i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPConfig) Copy() *IPConfig {
|
||||||
|
if i == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ipc := &IPConfig{
|
||||||
|
Address: i.Address,
|
||||||
|
Gateway: i.Gateway,
|
||||||
|
}
|
||||||
|
if i.Interface != nil {
|
||||||
|
intf := *i.Interface
|
||||||
|
ipc.Interface = &intf
|
||||||
|
}
|
||||||
|
return ipc
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON (un)marshallable types
|
||||||
|
type ipConfig struct {
|
||||||
|
Interface *int `json:"interface,omitempty"`
|
||||||
|
Address types.IPNet `json:"address"`
|
||||||
|
Gateway net.IP `json:"gateway,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IPConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
ipc := ipConfig{
|
||||||
|
Interface: c.Interface,
|
||||||
|
Address: types.IPNet(c.Address),
|
||||||
|
Gateway: c.Gateway,
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(ipc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IPConfig) UnmarshalJSON(data []byte) error {
|
||||||
|
ipc := ipConfig{}
|
||||||
|
if err := json.Unmarshal(data, &ipc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Interface = ipc.Interface
|
||||||
|
c.Address = net.IPNet(ipc.Address)
|
||||||
|
c.Gateway = ipc.Gateway
|
||||||
|
return nil
|
||||||
|
}
|
26
vendor/github.com/containernetworking/cni/pkg/types/create/create.go
generated
vendored
Normal file
26
vendor/github.com/containernetworking/cni/pkg/types/create/create.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2016 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package create
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
convert "github.com/containernetworking/cni/pkg/types/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create creates a CNI Result using the given JSON, or an error if the creation
|
||||||
|
// could not be performed
|
||||||
|
func Create(version string, bytes []byte) (types.Result, error) {
|
||||||
|
return convert.Create(version, bytes)
|
||||||
|
}
|
276
vendor/github.com/containernetworking/cni/pkg/types/current/types.go
generated
vendored
276
vendor/github.com/containernetworking/cni/pkg/types/current/types.go
generated
vendored
@ -1,276 +0,0 @@
|
|||||||
// Copyright 2016 CNI authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package current
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
|
||||||
"github.com/containernetworking/cni/pkg/types/020"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ImplementedSpecVersion string = "0.4.0"
|
|
||||||
|
|
||||||
var SupportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion}
|
|
||||||
|
|
||||||
func NewResult(data []byte) (types.Result, error) {
|
|
||||||
result := &Result{}
|
|
||||||
if err := json.Unmarshal(data, result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetResult(r types.Result) (*Result, error) {
|
|
||||||
resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result, ok := resultCurrent.(*Result)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("failed to convert result")
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultConverters = []struct {
|
|
||||||
versions []string
|
|
||||||
convert func(types.Result) (*Result, error)
|
|
||||||
}{
|
|
||||||
{types020.SupportedVersions, convertFrom020},
|
|
||||||
{SupportedVersions, convertFrom030},
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertFrom020(result types.Result) (*Result, error) {
|
|
||||||
oldResult, err := types020.GetResult(result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newResult := &Result{
|
|
||||||
CNIVersion: ImplementedSpecVersion,
|
|
||||||
DNS: oldResult.DNS,
|
|
||||||
Routes: []*types.Route{},
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldResult.IP4 != nil {
|
|
||||||
newResult.IPs = append(newResult.IPs, &IPConfig{
|
|
||||||
Version: "4",
|
|
||||||
Address: oldResult.IP4.IP,
|
|
||||||
Gateway: oldResult.IP4.Gateway,
|
|
||||||
})
|
|
||||||
for _, route := range oldResult.IP4.Routes {
|
|
||||||
newResult.Routes = append(newResult.Routes, &types.Route{
|
|
||||||
Dst: route.Dst,
|
|
||||||
GW: route.GW,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldResult.IP6 != nil {
|
|
||||||
newResult.IPs = append(newResult.IPs, &IPConfig{
|
|
||||||
Version: "6",
|
|
||||||
Address: oldResult.IP6.IP,
|
|
||||||
Gateway: oldResult.IP6.Gateway,
|
|
||||||
})
|
|
||||||
for _, route := range oldResult.IP6.Routes {
|
|
||||||
newResult.Routes = append(newResult.Routes, &types.Route{
|
|
||||||
Dst: route.Dst,
|
|
||||||
GW: route.GW,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newResult, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertFrom030(result types.Result) (*Result, error) {
|
|
||||||
newResult, ok := result.(*Result)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("failed to convert result")
|
|
||||||
}
|
|
||||||
newResult.CNIVersion = ImplementedSpecVersion
|
|
||||||
return newResult, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewResultFromResult(result types.Result) (*Result, error) {
|
|
||||||
version := result.Version()
|
|
||||||
for _, converter := range resultConverters {
|
|
||||||
for _, supportedVersion := range converter.versions {
|
|
||||||
if version == supportedVersion {
|
|
||||||
return converter.convert(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("unsupported CNI result22 version %q", version)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result is what gets returned from the plugin (via stdout) to the caller
|
|
||||||
type Result struct {
|
|
||||||
CNIVersion string `json:"cniVersion,omitempty"`
|
|
||||||
Interfaces []*Interface `json:"interfaces,omitempty"`
|
|
||||||
IPs []*IPConfig `json:"ips,omitempty"`
|
|
||||||
Routes []*types.Route `json:"routes,omitempty"`
|
|
||||||
DNS types.DNS `json:"dns,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to the older 0.2.0 CNI spec Result type
|
|
||||||
func (r *Result) convertTo020() (*types020.Result, error) {
|
|
||||||
oldResult := &types020.Result{
|
|
||||||
CNIVersion: types020.ImplementedSpecVersion,
|
|
||||||
DNS: r.DNS,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ip := range r.IPs {
|
|
||||||
// Only convert the first IP address of each version as 0.2.0
|
|
||||||
// and earlier cannot handle multiple IP addresses
|
|
||||||
if ip.Version == "4" && oldResult.IP4 == nil {
|
|
||||||
oldResult.IP4 = &types020.IPConfig{
|
|
||||||
IP: ip.Address,
|
|
||||||
Gateway: ip.Gateway,
|
|
||||||
}
|
|
||||||
} else if ip.Version == "6" && oldResult.IP6 == nil {
|
|
||||||
oldResult.IP6 = &types020.IPConfig{
|
|
||||||
IP: ip.Address,
|
|
||||||
Gateway: ip.Gateway,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldResult.IP4 != nil && oldResult.IP6 != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, route := range r.Routes {
|
|
||||||
is4 := route.Dst.IP.To4() != nil
|
|
||||||
if is4 && oldResult.IP4 != nil {
|
|
||||||
oldResult.IP4.Routes = append(oldResult.IP4.Routes, types.Route{
|
|
||||||
Dst: route.Dst,
|
|
||||||
GW: route.GW,
|
|
||||||
})
|
|
||||||
} else if !is4 && oldResult.IP6 != nil {
|
|
||||||
oldResult.IP6.Routes = append(oldResult.IP6.Routes, types.Route{
|
|
||||||
Dst: route.Dst,
|
|
||||||
GW: route.GW,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldResult.IP4 == nil && oldResult.IP6 == nil {
|
|
||||||
return nil, fmt.Errorf("cannot convert: no valid IP addresses")
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldResult, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Result) Version() string {
|
|
||||||
return ImplementedSpecVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
|
||||||
switch version {
|
|
||||||
case "0.3.0", "0.3.1", ImplementedSpecVersion:
|
|
||||||
r.CNIVersion = version
|
|
||||||
return r, nil
|
|
||||||
case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
|
|
||||||
return r.convertTo020()
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("cannot convert version 0.3.x to %q", version)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Result) Print() error {
|
|
||||||
return r.PrintTo(os.Stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Result) PrintTo(writer io.Writer) error {
|
|
||||||
data, err := json.MarshalIndent(r, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = writer.Write(data)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert this old version result to the current CNI version result
|
|
||||||
func (r *Result) Convert() (*Result, error) {
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface contains values about the created interfaces
|
|
||||||
type Interface struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Mac string `json:"mac,omitempty"`
|
|
||||||
Sandbox string `json:"sandbox,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Interface) String() string {
|
|
||||||
return fmt.Sprintf("%+v", *i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int returns a pointer to the int value passed in. Used to
|
|
||||||
// set the IPConfig.Interface field.
|
|
||||||
func Int(v int) *int {
|
|
||||||
return &v
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPConfig contains values necessary to configure an IP address on an interface
|
|
||||||
type IPConfig struct {
|
|
||||||
// IP version, either "4" or "6"
|
|
||||||
Version string
|
|
||||||
// Index into Result structs Interfaces list
|
|
||||||
Interface *int
|
|
||||||
Address net.IPNet
|
|
||||||
Gateway net.IP
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IPConfig) String() string {
|
|
||||||
return fmt.Sprintf("%+v", *i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON (un)marshallable types
|
|
||||||
type ipConfig struct {
|
|
||||||
Version string `json:"version"`
|
|
||||||
Interface *int `json:"interface,omitempty"`
|
|
||||||
Address types.IPNet `json:"address"`
|
|
||||||
Gateway net.IP `json:"gateway,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *IPConfig) MarshalJSON() ([]byte, error) {
|
|
||||||
ipc := ipConfig{
|
|
||||||
Version: c.Version,
|
|
||||||
Interface: c.Interface,
|
|
||||||
Address: types.IPNet(c.Address),
|
|
||||||
Gateway: c.Gateway,
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(ipc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *IPConfig) UnmarshalJSON(data []byte) error {
|
|
||||||
ipc := ipConfig{}
|
|
||||||
if err := json.Unmarshal(data, &ipc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Version = ipc.Version
|
|
||||||
c.Interface = ipc.Interface
|
|
||||||
c.Address = net.IPNet(ipc.Address)
|
|
||||||
c.Gateway = ipc.Gateway
|
|
||||||
return nil
|
|
||||||
}
|
|
88
vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go
generated
vendored
Normal file
88
vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2016 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConvertFn should convert from the given arbitrary Result type into a
|
||||||
|
// Result implementing CNI specification version passed in toVersion.
|
||||||
|
// The function is guaranteed to be passed a Result type matching the
|
||||||
|
// fromVersion it was registered with, and is guaranteed to be
|
||||||
|
// passed a toVersion matching one of the toVersions it was registered with.
|
||||||
|
type ConvertFn func(from types.Result, toVersion string) (types.Result, error)
|
||||||
|
|
||||||
|
type converter struct {
|
||||||
|
// fromVersion is the CNI Result spec version that convertFn accepts
|
||||||
|
fromVersion string
|
||||||
|
// toVersions is a list of versions that convertFn can convert to
|
||||||
|
toVersions []string
|
||||||
|
convertFn ConvertFn
|
||||||
|
}
|
||||||
|
|
||||||
|
var converters []*converter
|
||||||
|
|
||||||
|
func findConverter(fromVersion, toVersion string) *converter {
|
||||||
|
for _, c := range converters {
|
||||||
|
if c.fromVersion == fromVersion {
|
||||||
|
for _, v := range c.toVersions {
|
||||||
|
if v == toVersion {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert converts a CNI Result to the requested CNI specification version,
|
||||||
|
// or returns an error if the converstion could not be performed or failed
|
||||||
|
func Convert(from types.Result, toVersion string) (types.Result, error) {
|
||||||
|
fromVersion := from.Version()
|
||||||
|
|
||||||
|
// Shortcut for same version
|
||||||
|
if fromVersion == toVersion {
|
||||||
|
return from, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise find the right converter
|
||||||
|
c := findConverter(fromVersion, toVersion)
|
||||||
|
if c == nil {
|
||||||
|
return nil, fmt.Errorf("no converter for CNI result version %s to %s",
|
||||||
|
fromVersion, toVersion)
|
||||||
|
}
|
||||||
|
return c.convertFn(from, toVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterConverter registers a CNI Result converter. SHOULD NOT BE CALLED
|
||||||
|
// EXCEPT FROM CNI ITSELF.
|
||||||
|
func RegisterConverter(fromVersion string, toVersions []string, convertFn ConvertFn) {
|
||||||
|
// Make sure there is no converter already registered for these
|
||||||
|
// from and to versions
|
||||||
|
for _, v := range toVersions {
|
||||||
|
if findConverter(fromVersion, v) != nil {
|
||||||
|
panic(fmt.Sprintf("converter already registered for %s to %s",
|
||||||
|
fromVersion, v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
converters = append(converters, &converter{
|
||||||
|
fromVersion: fromVersion,
|
||||||
|
toVersions: toVersions,
|
||||||
|
convertFn: convertFn,
|
||||||
|
})
|
||||||
|
}
|
66
vendor/github.com/containernetworking/cni/pkg/types/internal/create.go
generated
vendored
Normal file
66
vendor/github.com/containernetworking/cni/pkg/types/internal/create.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2016 CNI authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResultFactoryFunc func([]byte) (types.Result, error)
|
||||||
|
|
||||||
|
type creator struct {
|
||||||
|
// CNI Result spec versions that createFn can create a Result for
|
||||||
|
versions []string
|
||||||
|
createFn ResultFactoryFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
var creators []*creator
|
||||||
|
|
||||||
|
func findCreator(version string) *creator {
|
||||||
|
for _, c := range creators {
|
||||||
|
for _, v := range c.versions {
|
||||||
|
if v == version {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a CNI Result using the given JSON, or an error if the creation
|
||||||
|
// could not be performed
|
||||||
|
func Create(version string, bytes []byte) (types.Result, error) {
|
||||||
|
if c := findCreator(version); c != nil {
|
||||||
|
return c.createFn(bytes)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unsupported CNI result version %q", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterCreator registers a CNI Result creator. SHOULD NOT BE CALLED
|
||||||
|
// EXCEPT FROM CNI ITSELF.
|
||||||
|
func RegisterCreator(versions []string, createFn ResultFactoryFunc) {
|
||||||
|
// Make sure there is no creator already registered for these versions
|
||||||
|
for _, v := range versions {
|
||||||
|
if findCreator(v) != nil {
|
||||||
|
panic(fmt.Sprintf("creator already registered for %s", v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
creators = append(creators, &creator{
|
||||||
|
versions: versions,
|
||||||
|
createFn: createFn,
|
||||||
|
})
|
||||||
|
}
|
31
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
31
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
@ -83,8 +83,6 @@ type NetConfList struct {
|
|||||||
Plugins []*NetConf `json:"plugins,omitempty"`
|
Plugins []*NetConf `json:"plugins,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResultFactoryFunc func([]byte) (Result, error)
|
|
||||||
|
|
||||||
// Result is an interface that provides the result of plugin execution
|
// Result is an interface that provides the result of plugin execution
|
||||||
type Result interface {
|
type Result interface {
|
||||||
// The highest CNI specification result version the result supports
|
// The highest CNI specification result version the result supports
|
||||||
@ -118,6 +116,24 @@ type DNS struct {
|
|||||||
Options []string `json:"options,omitempty"`
|
Options []string `json:"options,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DNS) Copy() *DNS {
|
||||||
|
if d == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
to := &DNS{Domain: d.Domain}
|
||||||
|
for _, ns := range d.Nameservers {
|
||||||
|
to.Nameservers = append(to.Nameservers, ns)
|
||||||
|
}
|
||||||
|
for _, s := range d.Search {
|
||||||
|
to.Search = append(to.Search, s)
|
||||||
|
}
|
||||||
|
for _, o := range d.Options {
|
||||||
|
to.Options = append(to.Options, o)
|
||||||
|
}
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Dst net.IPNet
|
Dst net.IPNet
|
||||||
GW net.IP
|
GW net.IP
|
||||||
@ -127,6 +143,17 @@ func (r *Route) String() string {
|
|||||||
return fmt.Sprintf("%+v", *r)
|
return fmt.Sprintf("%+v", *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Route) Copy() *Route {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Route{
|
||||||
|
Dst: r.Dst,
|
||||||
|
GW: r.GW,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Well known error codes
|
// Well known error codes
|
||||||
// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
|
// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
|
||||||
const (
|
const (
|
||||||
|
34
vendor/github.com/containernetworking/cni/pkg/version/version.go
generated
vendored
34
vendor/github.com/containernetworking/cni/pkg/version/version.go
generated
vendored
@ -19,13 +19,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
"github.com/containernetworking/cni/pkg/types/020"
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/cni/pkg/types/current"
|
"github.com/containernetworking/cni/pkg/types/create"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Current reports the version of the CNI spec implemented by this library
|
// Current reports the version of the CNI spec implemented by this library
|
||||||
func Current() string {
|
func Current() string {
|
||||||
return "0.4.0"
|
return types100.ImplementedSpecVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legacy PluginInfo describes a plugin that is backwards compatible with the
|
// Legacy PluginInfo describes a plugin that is backwards compatible with the
|
||||||
@ -36,29 +36,12 @@ func Current() string {
|
|||||||
// Any future CNI spec versions which meet this definition should be added to
|
// Any future CNI spec versions which meet this definition should be added to
|
||||||
// this list.
|
// this list.
|
||||||
var Legacy = PluginSupports("0.1.0", "0.2.0")
|
var Legacy = PluginSupports("0.1.0", "0.2.0")
|
||||||
var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0")
|
var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0", "1.0.0")
|
||||||
|
|
||||||
var resultFactories = []struct {
|
|
||||||
supportedVersions []string
|
|
||||||
newResult types.ResultFactoryFunc
|
|
||||||
}{
|
|
||||||
{current.SupportedVersions, current.NewResult},
|
|
||||||
{types020.SupportedVersions, types020.NewResult},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finds a Result object matching the requested version (if any) and asks
|
// Finds a Result object matching the requested version (if any) and asks
|
||||||
// that object to parse the plugin result, returning an error if parsing failed.
|
// that object to parse the plugin result, returning an error if parsing failed.
|
||||||
func NewResult(version string, resultBytes []byte) (types.Result, error) {
|
func NewResult(version string, resultBytes []byte) (types.Result, error) {
|
||||||
reconciler := &Reconciler{}
|
return create.Create(version, resultBytes)
|
||||||
for _, resultFactory := range resultFactories {
|
|
||||||
err := reconciler.CheckRaw(version, resultFactory.supportedVersions)
|
|
||||||
if err == nil {
|
|
||||||
// Result supports this version
|
|
||||||
return resultFactory.newResult(resultBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("unsupported CNI result version %q", version)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParsePrevResult parses a prevResult in a NetConf structure and sets
|
// ParsePrevResult parses a prevResult in a NetConf structure and sets
|
||||||
@ -68,6 +51,13 @@ func ParsePrevResult(conf *types.NetConf) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prior to 1.0.0, Result types may not marshal a CNIVersion. Since the
|
||||||
|
// result version must match the config version, if the Result's version
|
||||||
|
// is empty, inject the config version.
|
||||||
|
if ver, ok := conf.RawPrevResult["CNIVersion"]; !ok || ver == "" {
|
||||||
|
conf.RawPrevResult["CNIVersion"] = conf.CNIVersion
|
||||||
|
}
|
||||||
|
|
||||||
resultBytes, err := json.Marshal(conf.RawPrevResult)
|
resultBytes, err := json.Marshal(conf.RawPrevResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not serialize prevResult: %v", err)
|
return fmt.Errorf("could not serialize prevResult: %v", err)
|
||||||
|
9
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
9
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
@ -1,5 +1,12 @@
|
|||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*.go]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
Normal file
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
go.sum linguist-generated
|
20
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
20
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
@ -2,29 +2,35 @@ sudo: false
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.8.x
|
- "stable"
|
||||||
- 1.9.x
|
- "1.11.x"
|
||||||
- tip
|
- "1.10.x"
|
||||||
|
- "1.9.x"
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
include:
|
||||||
|
- go: "stable"
|
||||||
|
env: GOLINT=true
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- go: tip
|
- go: tip
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
before_script:
|
|
||||||
- go get -u github.com/golang/lint/golint
|
before_install:
|
||||||
|
- if [ ! -z "${GOLINT}" ]; then go get -u golang.org/x/lint/golint; fi
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- go test -v --race ./...
|
- go test --race ./...
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
|
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
|
||||||
- test -z "$(golint ./... | tee /dev/stderr)"
|
- if [ ! -z "${GOLINT}" ]; then echo running golint; golint --set_exit_status ./...; else echo skipping golint; fi
|
||||||
- go vet ./...
|
- go vet ./...
|
||||||
|
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
|
- windows
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
2
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
2
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
@ -1,5 +1,5 @@
|
|||||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
Copyright (c) 2012 fsnotify Authors. All rights reserved.
|
Copyright (c) 2012-2019 fsnotify Authors. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
71
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
71
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
@ -10,16 +10,16 @@ go get -u golang.org/x/sys/...
|
|||||||
|
|
||||||
Cross platform: Windows, Linux, BSD and macOS.
|
Cross platform: Windows, Linux, BSD and macOS.
|
||||||
|
|
||||||
|Adapter |OS |Status |
|
| Adapter | OS | Status |
|
||||||
|----------|----------|----------|
|
| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|inotify |Linux 2.6.27 or later, Android\*|Supported [](https://travis-ci.org/fsnotify/fsnotify)|
|
| inotify | Linux 2.6.27 or later, Android\* | Supported [](https://travis-ci.org/fsnotify/fsnotify) |
|
||||||
|kqueue |BSD, macOS, iOS\*|Supported [](https://travis-ci.org/fsnotify/fsnotify)|
|
| kqueue | BSD, macOS, iOS\* | Supported [](https://travis-ci.org/fsnotify/fsnotify) |
|
||||||
|ReadDirectoryChangesW|Windows|Supported [](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
|
| ReadDirectoryChangesW | Windows | Supported [](https://travis-ci.org/fsnotify/fsnotify) |
|
||||||
|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)|
|
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
|
||||||
|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)|
|
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
|
||||||
|fanotify |Linux 2.6.37+ | |
|
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||||
|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)|
|
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
|
||||||
|Polling |*All* |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)|
|
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
|
||||||
|
|
||||||
\* Android and iOS are untested.
|
\* Android and iOS are untested.
|
||||||
|
|
||||||
@ -33,6 +33,53 @@ All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based o
|
|||||||
|
|
||||||
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer watcher.Close()
|
||||||
|
|
||||||
|
done := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event, ok := <-watcher.Events:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("event:", event)
|
||||||
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
|
log.Println("modified file:", event.Name)
|
||||||
|
}
|
||||||
|
case err, ok := <-watcher.Errors:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("error:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = watcher.Add("/tmp/foo")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||||
@ -65,6 +112,10 @@ There are OS-specific limits as to how many watches can be created:
|
|||||||
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
|
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
|
||||||
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
||||||
|
|
||||||
|
**Why don't notifications work with NFS filesystems or filesystem in userspace (FUSE)?**
|
||||||
|
|
||||||
|
fsnotify requires support from underlying OS to work. The current NFS protocol does not provide network level support for file notifications.
|
||||||
|
|
||||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||||
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
||||||
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
||||||
|
4
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
4
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
@ -63,4 +63,6 @@ func (e Event) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Common errors that can be reported by a watcher
|
// Common errors that can be reported by a watcher
|
||||||
var ErrEventOverflow = errors.New("fsnotify queue overflow")
|
var (
|
||||||
|
ErrEventOverflow = errors.New("fsnotify queue overflow")
|
||||||
|
)
|
||||||
|
5
vendor/github.com/fsnotify/fsnotify/go.mod
generated
vendored
Normal file
5
vendor/github.com/fsnotify/fsnotify/go.mod
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module github.com/fsnotify/fsnotify
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9
|
2
vendor/github.com/fsnotify/fsnotify/go.sum
generated
vendored
Normal file
2
vendor/github.com/fsnotify/fsnotify/go.sum
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
4
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
4
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
@ -40,12 +40,12 @@ func newFdPoller(fd int) (*fdPoller, error) {
|
|||||||
poller.fd = fd
|
poller.fd = fd
|
||||||
|
|
||||||
// Create epoll fd
|
// Create epoll fd
|
||||||
poller.epfd, errno = unix.EpollCreate1(0)
|
poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||||
if poller.epfd == -1 {
|
if poller.epfd == -1 {
|
||||||
return nil, errno
|
return nil, errno
|
||||||
}
|
}
|
||||||
// Create pipe; pipe[0] is the read end, pipe[1] the write end.
|
// Create pipe; pipe[0] is the read end, pipe[1] the write end.
|
||||||
errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK)
|
errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK|unix.O_CLOEXEC)
|
||||||
if errno != nil {
|
if errno != nil {
|
||||||
return nil, errno
|
return nil, errno
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
generated
vendored
2
vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
generated
vendored
@ -8,4 +8,4 @@ package fsnotify
|
|||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
const openMode = unix.O_NONBLOCK | unix.O_RDONLY
|
const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC
|
||||||
|
2
vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
2
vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
@ -9,4 +9,4 @@ package fsnotify
|
|||||||
import "golang.org/x/sys/unix"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
// note: this constant is not defined on BSD
|
// note: this constant is not defined on BSD
|
||||||
const openMode = unix.O_EVTONLY
|
const openMode = unix.O_EVTONLY | unix.O_CLOEXEC
|
||||||
|
23
vendor/github.com/onsi/ginkgo/CHANGELOG.md
generated
vendored
23
vendor/github.com/onsi/ginkgo/CHANGELOG.md
generated
vendored
@ -1,3 +1,26 @@
|
|||||||
|
## 1.13.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Add a version of table.Entry that allows dumping the entry parameters. (#689) [21eaef2]
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Ensure integration tests pass in an environment sans GOPATH [606fba2]
|
||||||
|
- Add books package (#568) [fc0e44e]
|
||||||
|
- doc(readme): installation via "tools package" (#677) [83bb20e]
|
||||||
|
- Solve the undefined: unix.Dup2 compile error on mips64le (#680) [0624f75]
|
||||||
|
- Import package without dot (#687) [6321024]
|
||||||
|
- Fix integration tests to stop require GOPATH (#686) [a912ec5]
|
||||||
|
|
||||||
|
## 1.12.3
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Print correct code location of failing table test (#666) [c6d7afb]
|
||||||
|
|
||||||
|
## 1.12.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Update dependencies [ea4a036]
|
||||||
|
|
||||||
## 1.12.1
|
## 1.12.1
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
47
vendor/github.com/onsi/ginkgo/README.md
generated
vendored
47
vendor/github.com/onsi/ginkgo/README.md
generated
vendored
@ -4,7 +4,23 @@
|
|||||||
|
|
||||||
Jump to the [docs](https://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)!
|
Jump to the [docs](https://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)!
|
||||||
|
|
||||||
If you have a question, comment, bug report, feature request, etc. please open a GitHub issue.
|
If you have a question, comment, bug report, feature request, etc. please open a GitHub issue, or visit the [Ginkgo Slack channel](https://app.slack.com/client/T029RQSE6/CQQ50BBNW).
|
||||||
|
|
||||||
|
## TLDR
|
||||||
|
Ginkgo builds on Go's `testing` package, allowing expressive [Behavior-Driven Development](https://en.wikipedia.org/wiki/Behavior-driven_development) ("BDD") style tests.
|
||||||
|
It is typically (and optionally) paired with the [Gomega](https://github.com/onsi/gomega) matcher library.
|
||||||
|
|
||||||
|
```go
|
||||||
|
Describe("the strings package", func() {
|
||||||
|
Context("strings.Contains()", func() {
|
||||||
|
When("the string contains the substring in the middle", func() {
|
||||||
|
It("returns `true`", func() {
|
||||||
|
Expect(strings.Contains("Ginkgo is awesome", "is")).To(BeTrue())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Feature List
|
## Feature List
|
||||||
|
|
||||||
@ -59,15 +75,36 @@ Ginkgo is best paired with Gomega. Learn more about Gomega [here](https://onsi.
|
|||||||
|
|
||||||
Agouti allows you run WebDriver integration tests. Learn more about Agouti [here](https://agouti.org)
|
Agouti allows you run WebDriver integration tests. Learn more about Agouti [here](https://agouti.org)
|
||||||
|
|
||||||
## Set Me Up!
|
## Getting Started
|
||||||
|
|
||||||
You'll need the Go command-line tools. Ginkgo is tested with Go 1.6+, but preferably you should get the latest. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed.
|
You'll need the Go command-line tools. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed.
|
||||||
|
|
||||||
|
### Global installation
|
||||||
|
To install the Ginkgo command line interface into the `$PATH` (actually to `$GOBIN`):
|
||||||
```bash
|
```bash
|
||||||
|
go get -u github.com/onsi/ginkgo/ginkgo
|
||||||
|
```
|
||||||
|
|
||||||
go get -u github.com/onsi/ginkgo/ginkgo # installs the ginkgo CLI
|
### Go module ["tools package"](https://github.com/golang/go/issues/25922):
|
||||||
go get -u github.com/onsi/gomega/... # fetches the matcher library
|
Create (or update) a file called `tools/tools.go` with the following contents:
|
||||||
|
```go
|
||||||
|
// +build tools
|
||||||
|
|
||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/onsi/ginkgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file imports packages that are used when running go generate, or used
|
||||||
|
// during the development process but not otherwise depended on by built code.
|
||||||
|
```
|
||||||
|
The Ginkgo command can then be run via `go run github.com/onsi/ginkgo/ginkgo`.
|
||||||
|
This approach allows the version of Ginkgo to be maintained under source control for reproducible results,
|
||||||
|
and is well suited to automated test pipelines.
|
||||||
|
|
||||||
|
### Bootstrapping
|
||||||
|
```bash
|
||||||
cd path/to/package/you/want/to/test
|
cd path/to/package/you/want/to/test
|
||||||
|
|
||||||
ginkgo bootstrap # set up a new ginkgo suite
|
ginkgo bootstrap # set up a new ginkgo suite
|
||||||
|
2
vendor/github.com/onsi/ginkgo/config/config.go
generated
vendored
2
vendor/github.com/onsi/ginkgo/config/config.go
generated
vendored
@ -20,7 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
const VERSION = "1.12.1"
|
const VERSION = "1.13.0"
|
||||||
|
|
||||||
type GinkgoConfigType struct {
|
type GinkgoConfigType struct {
|
||||||
RandomSeed int64
|
RandomSeed int64
|
||||||
|
56
vendor/github.com/onsi/ginkgo/extensions/table/table.go
generated
vendored
56
vendor/github.com/onsi/ginkgo/extensions/table/table.go
generated
vendored
@ -12,7 +12,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/onsi/ginkgo"
|
"github.com/onsi/ginkgo/internal/codelocation"
|
||||||
|
"github.com/onsi/ginkgo/internal/global"
|
||||||
|
"github.com/onsi/ginkgo/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -40,9 +42,28 @@ Under the hood, `DescribeTable` simply generates a new Ginkgo `Describe`. Each
|
|||||||
It's important to understand that the `Describe`s and `It`s are generated at evaluation time (i.e. when Ginkgo constructs the tree of tests and before the tests run).
|
It's important to understand that the `Describe`s and `It`s are generated at evaluation time (i.e. when Ginkgo constructs the tree of tests and before the tests run).
|
||||||
|
|
||||||
Individual Entries can be focused (with FEntry) or marked pending (with PEntry or XEntry). In addition, the entire table can be focused or marked pending with FDescribeTable and PDescribeTable/XDescribeTable.
|
Individual Entries can be focused (with FEntry) or marked pending (with PEntry or XEntry). In addition, the entire table can be focused or marked pending with FDescribeTable and PDescribeTable/XDescribeTable.
|
||||||
|
|
||||||
|
A description function can be passed to Entry in place of the description. The function is then fed with the entry parameters to generate the description of the It corresponding to that particular Entry.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
describe := func(desc string) func(int, int, bool) string {
|
||||||
|
return func(x, y int, expected bool) string {
|
||||||
|
return fmt.Sprintf("%s x=%d y=%d expected:%t", desc, x, y, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DescribeTable("a simple table",
|
||||||
|
func(x int, y int, expected bool) {
|
||||||
|
Ω(x > y).Should(Equal(expected))
|
||||||
|
},
|
||||||
|
Entry(describe("x > y"), 1, 0, true),
|
||||||
|
Entry(describe("x == y"), 0, 0, false),
|
||||||
|
Entry(describe("x < y"), 0, 1, false),
|
||||||
|
)
|
||||||
*/
|
*/
|
||||||
func DescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
func DescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
||||||
describeTable(description, itBody, entries, false, false)
|
describeTable(description, itBody, entries, types.FlagTypeNone)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +71,7 @@ func DescribeTable(description string, itBody interface{}, entries ...TableEntry
|
|||||||
You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`.
|
You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`.
|
||||||
*/
|
*/
|
||||||
func FDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
func FDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
||||||
describeTable(description, itBody, entries, false, true)
|
describeTable(description, itBody, entries, types.FlagTypeFocused)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +79,7 @@ func FDescribeTable(description string, itBody interface{}, entries ...TableEntr
|
|||||||
You can mark a table as pending with `PDescribeTable`. This is equivalent to `PDescribe`.
|
You can mark a table as pending with `PDescribeTable`. This is equivalent to `PDescribe`.
|
||||||
*/
|
*/
|
||||||
func PDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
func PDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
||||||
describeTable(description, itBody, entries, true, false)
|
describeTable(description, itBody, entries, types.FlagTypePending)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,33 +87,24 @@ func PDescribeTable(description string, itBody interface{}, entries ...TableEntr
|
|||||||
You can mark a table as pending with `XDescribeTable`. This is equivalent to `XDescribe`.
|
You can mark a table as pending with `XDescribeTable`. This is equivalent to `XDescribe`.
|
||||||
*/
|
*/
|
||||||
func XDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
func XDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
|
||||||
describeTable(description, itBody, entries, true, false)
|
describeTable(description, itBody, entries, types.FlagTypePending)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func describeTable(description string, itBody interface{}, entries []TableEntry, pending bool, focused bool) {
|
func describeTable(description string, itBody interface{}, entries []TableEntry, flag types.FlagType) {
|
||||||
itBodyValue := reflect.ValueOf(itBody)
|
itBodyValue := reflect.ValueOf(itBody)
|
||||||
if itBodyValue.Kind() != reflect.Func {
|
if itBodyValue.Kind() != reflect.Func {
|
||||||
panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody))
|
panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pending {
|
global.Suite.PushContainerNode(
|
||||||
ginkgo.PDescribe(description, func() {
|
description,
|
||||||
|
func() {
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
entry.generateIt(itBodyValue)
|
entry.generateIt(itBodyValue)
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
} else if focused {
|
flag,
|
||||||
ginkgo.FDescribe(description, func() {
|
codelocation.New(2),
|
||||||
for _, entry := range entries {
|
)
|
||||||
entry.generateIt(itBodyValue)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ginkgo.Describe(description, func() {
|
|
||||||
for _, entry := range entries {
|
|
||||||
entry.generateIt(itBodyValue)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
111
vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go
generated
vendored
111
vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go
generated
vendored
@ -1,49 +1,82 @@
|
|||||||
package table
|
package table
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/onsi/ginkgo"
|
"github.com/onsi/ginkgo/internal/codelocation"
|
||||||
|
"github.com/onsi/ginkgo/internal/global"
|
||||||
|
"github.com/onsi/ginkgo/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TableEntry represents an entry in a table test. You generally use the `Entry` constructor.
|
TableEntry represents an entry in a table test. You generally use the `Entry` constructor.
|
||||||
*/
|
*/
|
||||||
type TableEntry struct {
|
type TableEntry struct {
|
||||||
Description string
|
Description interface{}
|
||||||
Parameters []interface{}
|
Parameters []interface{}
|
||||||
Pending bool
|
Pending bool
|
||||||
Focused bool
|
Focused bool
|
||||||
|
codeLocation types.CodeLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t TableEntry) generateIt(itBody reflect.Value) {
|
func (t TableEntry) generateIt(itBody reflect.Value) {
|
||||||
|
if t.codeLocation == (types.CodeLocation{}) {
|
||||||
|
// The user created the TableEntry struct directly instead of having used the (F/P/X)Entry constructors.
|
||||||
|
// Therefore default to the code location of the surrounding DescribeTable.
|
||||||
|
t.codeLocation = codelocation.New(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
var description string
|
||||||
|
descriptionValue := reflect.ValueOf(t.Description)
|
||||||
|
switch descriptionValue.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
description = descriptionValue.String()
|
||||||
|
case reflect.Func:
|
||||||
|
values := castParameters(descriptionValue, t.Parameters)
|
||||||
|
res := descriptionValue.Call(values)
|
||||||
|
if len(res) != 1 {
|
||||||
|
panic(fmt.Sprintf("The describe function should return only a value, returned %d", len(res)))
|
||||||
|
}
|
||||||
|
if res[0].Kind() != reflect.String {
|
||||||
|
panic(fmt.Sprintf("The describe function should return a string, returned %#v", res[0]))
|
||||||
|
}
|
||||||
|
description = res[0].String()
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Description can either be a string or a function, got %#v", descriptionValue))
|
||||||
|
}
|
||||||
|
|
||||||
if t.Pending {
|
if t.Pending {
|
||||||
ginkgo.PIt(t.Description)
|
global.Suite.PushItNode(description, func() {}, types.FlagTypePending, t.codeLocation, 0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
values := make([]reflect.Value, len(t.Parameters))
|
values := castParameters(itBody, t.Parameters)
|
||||||
iBodyType := itBody.Type()
|
|
||||||
for i, param := range t.Parameters {
|
|
||||||
if param == nil {
|
|
||||||
inType := iBodyType.In(i)
|
|
||||||
values[i] = reflect.Zero(inType)
|
|
||||||
} else {
|
|
||||||
values[i] = reflect.ValueOf(param)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body := func() {
|
body := func() {
|
||||||
itBody.Call(values)
|
itBody.Call(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Focused {
|
if t.Focused {
|
||||||
ginkgo.FIt(t.Description, body)
|
global.Suite.PushItNode(description, body, types.FlagTypeFocused, t.codeLocation, global.DefaultTimeout)
|
||||||
} else {
|
} else {
|
||||||
ginkgo.It(t.Description, body)
|
global.Suite.PushItNode(description, body, types.FlagTypeNone, t.codeLocation, global.DefaultTimeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func castParameters(function reflect.Value, parameters []interface{}) []reflect.Value {
|
||||||
|
res := make([]reflect.Value, len(parameters))
|
||||||
|
funcType := function.Type()
|
||||||
|
for i, param := range parameters {
|
||||||
|
if param == nil {
|
||||||
|
inType := funcType.In(i)
|
||||||
|
res[i] = reflect.Zero(inType)
|
||||||
|
} else {
|
||||||
|
res[i] = reflect.ValueOf(param)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Entry constructs a TableEntry.
|
Entry constructs a TableEntry.
|
||||||
|
|
||||||
@ -52,27 +85,51 @@ Subsequent parameters are saved off and sent to the callback passed in to `Descr
|
|||||||
|
|
||||||
Each Entry ends up generating an individual Ginkgo It.
|
Each Entry ends up generating an individual Ginkgo It.
|
||||||
*/
|
*/
|
||||||
func Entry(description string, parameters ...interface{}) TableEntry {
|
func Entry(description interface{}, parameters ...interface{}) TableEntry {
|
||||||
return TableEntry{description, parameters, false, false}
|
return TableEntry{
|
||||||
|
Description: description,
|
||||||
|
Parameters: parameters,
|
||||||
|
Pending: false,
|
||||||
|
Focused: false,
|
||||||
|
codeLocation: codelocation.New(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
You can focus a particular entry with FEntry. This is equivalent to FIt.
|
You can focus a particular entry with FEntry. This is equivalent to FIt.
|
||||||
*/
|
*/
|
||||||
func FEntry(description string, parameters ...interface{}) TableEntry {
|
func FEntry(description interface{}, parameters ...interface{}) TableEntry {
|
||||||
return TableEntry{description, parameters, false, true}
|
return TableEntry{
|
||||||
|
Description: description,
|
||||||
|
Parameters: parameters,
|
||||||
|
Pending: false,
|
||||||
|
Focused: true,
|
||||||
|
codeLocation: codelocation.New(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
You can mark a particular entry as pending with PEntry. This is equivalent to PIt.
|
You can mark a particular entry as pending with PEntry. This is equivalent to PIt.
|
||||||
*/
|
*/
|
||||||
func PEntry(description string, parameters ...interface{}) TableEntry {
|
func PEntry(description interface{}, parameters ...interface{}) TableEntry {
|
||||||
return TableEntry{description, parameters, true, false}
|
return TableEntry{
|
||||||
|
Description: description,
|
||||||
|
Parameters: parameters,
|
||||||
|
Pending: true,
|
||||||
|
Focused: false,
|
||||||
|
codeLocation: codelocation.New(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
You can mark a particular entry as pending with XEntry. This is equivalent to XIt.
|
You can mark a particular entry as pending with XEntry. This is equivalent to XIt.
|
||||||
*/
|
*/
|
||||||
func XEntry(description string, parameters ...interface{}) TableEntry {
|
func XEntry(description interface{}, parameters ...interface{}) TableEntry {
|
||||||
return TableEntry{description, parameters, true, false}
|
return TableEntry{
|
||||||
|
Description: description,
|
||||||
|
Parameters: parameters,
|
||||||
|
Pending: true,
|
||||||
|
Focused: false,
|
||||||
|
codeLocation: codelocation.New(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
85
vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
generated
vendored
85
vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
generated
vendored
@ -22,9 +22,8 @@ import (
|
|||||||
|
|
||||||
"github.com/onsi/ginkgo/config"
|
"github.com/onsi/ginkgo/config"
|
||||||
"github.com/onsi/ginkgo/internal/codelocation"
|
"github.com/onsi/ginkgo/internal/codelocation"
|
||||||
"github.com/onsi/ginkgo/internal/failer"
|
"github.com/onsi/ginkgo/internal/global"
|
||||||
"github.com/onsi/ginkgo/internal/remote"
|
"github.com/onsi/ginkgo/internal/remote"
|
||||||
"github.com/onsi/ginkgo/internal/suite"
|
|
||||||
"github.com/onsi/ginkgo/internal/testingtproxy"
|
"github.com/onsi/ginkgo/internal/testingtproxy"
|
||||||
"github.com/onsi/ginkgo/internal/writer"
|
"github.com/onsi/ginkgo/internal/writer"
|
||||||
"github.com/onsi/ginkgo/reporters"
|
"github.com/onsi/ginkgo/reporters"
|
||||||
@ -46,16 +45,10 @@ To circumvent this, you should call
|
|||||||
|
|
||||||
at the top of the goroutine that caused this panic.
|
at the top of the goroutine that caused this panic.
|
||||||
`
|
`
|
||||||
const defaultTimeout = 1
|
|
||||||
|
|
||||||
var globalSuite *suite.Suite
|
|
||||||
var globalFailer *failer.Failer
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
config.Flags(flag.CommandLine, "ginkgo", true)
|
config.Flags(flag.CommandLine, "ginkgo", true)
|
||||||
GinkgoWriter = writer.New(os.Stdout)
|
GinkgoWriter = writer.New(os.Stdout)
|
||||||
globalFailer = failer.New()
|
|
||||||
globalSuite = suite.New(globalFailer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//GinkgoWriter implements an io.Writer
|
//GinkgoWriter implements an io.Writer
|
||||||
@ -156,7 +149,7 @@ type GinkgoTestDescription struct {
|
|||||||
|
|
||||||
//CurrentGinkgoTestDescripton returns information about the current running test.
|
//CurrentGinkgoTestDescripton returns information about the current running test.
|
||||||
func CurrentGinkgoTestDescription() GinkgoTestDescription {
|
func CurrentGinkgoTestDescription() GinkgoTestDescription {
|
||||||
summary, ok := globalSuite.CurrentRunningSpecSummary()
|
summary, ok := global.Suite.CurrentRunningSpecSummary()
|
||||||
if !ok {
|
if !ok {
|
||||||
return GinkgoTestDescription{}
|
return GinkgoTestDescription{}
|
||||||
}
|
}
|
||||||
@ -223,7 +216,7 @@ func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specRepor
|
|||||||
for i, reporter := range specReporters {
|
for i, reporter := range specReporters {
|
||||||
reporters[i] = reporter
|
reporters[i] = reporter
|
||||||
}
|
}
|
||||||
passed, hasFocusedTests := globalSuite.Run(t, description, reporters, writer, config.GinkgoConfig)
|
passed, hasFocusedTests := global.Suite.Run(t, description, reporters, writer, config.GinkgoConfig)
|
||||||
if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" {
|
if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" {
|
||||||
fmt.Println("PASS | FOCUSED")
|
fmt.Println("PASS | FOCUSED")
|
||||||
os.Exit(types.GINKGO_FOCUS_EXIT_CODE)
|
os.Exit(types.GINKGO_FOCUS_EXIT_CODE)
|
||||||
@ -252,7 +245,7 @@ func Skip(message string, callerSkip ...int) {
|
|||||||
skip = callerSkip[0]
|
skip = callerSkip[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
globalFailer.Skip(message, codelocation.New(skip+1))
|
global.Failer.Skip(message, codelocation.New(skip+1))
|
||||||
panic(GINKGO_PANIC)
|
panic(GINKGO_PANIC)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +256,7 @@ func Fail(message string, callerSkip ...int) {
|
|||||||
skip = callerSkip[0]
|
skip = callerSkip[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
globalFailer.Fail(message, codelocation.New(skip+1))
|
global.Failer.Fail(message, codelocation.New(skip+1))
|
||||||
panic(GINKGO_PANIC)
|
panic(GINKGO_PANIC)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +273,7 @@ func Fail(message string, callerSkip ...int) {
|
|||||||
func GinkgoRecover() {
|
func GinkgoRecover() {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
globalFailer.Panic(codelocation.New(1), e)
|
global.Failer.Panic(codelocation.New(1), e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,25 +284,25 @@ func GinkgoRecover() {
|
|||||||
//equivalent. The difference is purely semantic -- you typically Describe the behavior of an object
|
//equivalent. The difference is purely semantic -- you typically Describe the behavior of an object
|
||||||
//or method and, within that Describe, outline a number of Contexts and Whens.
|
//or method and, within that Describe, outline a number of Contexts and Whens.
|
||||||
func Describe(text string, body func()) bool {
|
func Describe(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can focus the tests within a describe block using FDescribe
|
//You can focus the tests within a describe block using FDescribe
|
||||||
func FDescribe(text string, body func()) bool {
|
func FDescribe(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark the tests within a describe block as pending using PDescribe
|
//You can mark the tests within a describe block as pending using PDescribe
|
||||||
func PDescribe(text string, body func()) bool {
|
func PDescribe(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark the tests within a describe block as pending using XDescribe
|
//You can mark the tests within a describe block as pending using XDescribe
|
||||||
func XDescribe(text string, body func()) bool {
|
func XDescribe(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,25 +313,25 @@ func XDescribe(text string, body func()) bool {
|
|||||||
//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
|
//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
|
||||||
//or method and, within that Describe, outline a number of Contexts and Whens.
|
//or method and, within that Describe, outline a number of Contexts and Whens.
|
||||||
func Context(text string, body func()) bool {
|
func Context(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can focus the tests within a describe block using FContext
|
//You can focus the tests within a describe block using FContext
|
||||||
func FContext(text string, body func()) bool {
|
func FContext(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark the tests within a describe block as pending using PContext
|
//You can mark the tests within a describe block as pending using PContext
|
||||||
func PContext(text string, body func()) bool {
|
func PContext(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark the tests within a describe block as pending using XContext
|
//You can mark the tests within a describe block as pending using XContext
|
||||||
func XContext(text string, body func()) bool {
|
func XContext(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,25 +342,25 @@ func XContext(text string, body func()) bool {
|
|||||||
//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
|
//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
|
||||||
//or method and, within that Describe, outline a number of Contexts and Whens.
|
//or method and, within that Describe, outline a number of Contexts and Whens.
|
||||||
func When(text string, body func()) bool {
|
func When(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1))
|
global.Suite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can focus the tests within a describe block using FWhen
|
//You can focus the tests within a describe block using FWhen
|
||||||
func FWhen(text string, body func()) bool {
|
func FWhen(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1))
|
global.Suite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark the tests within a describe block as pending using PWhen
|
//You can mark the tests within a describe block as pending using PWhen
|
||||||
func PWhen(text string, body func()) bool {
|
func PWhen(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
|
global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark the tests within a describe block as pending using XWhen
|
//You can mark the tests within a describe block as pending using XWhen
|
||||||
func XWhen(text string, body func()) bool {
|
func XWhen(text string, body func()) bool {
|
||||||
globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
|
global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,25 +370,25 @@ func XWhen(text string, body func()) bool {
|
|||||||
//Ginkgo will normally run It blocks synchronously. To perform asynchronous tests, pass a
|
//Ginkgo will normally run It blocks synchronously. To perform asynchronous tests, pass a
|
||||||
//function that accepts a Done channel. When you do this, you can also provide an optional timeout.
|
//function that accepts a Done channel. When you do this, you can also provide an optional timeout.
|
||||||
func It(text string, body interface{}, timeout ...float64) bool {
|
func It(text string, body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can focus individual Its using FIt
|
//You can focus individual Its using FIt
|
||||||
func FIt(text string, body interface{}, timeout ...float64) bool {
|
func FIt(text string, body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark Its as pending using PIt
|
//You can mark Its as pending using PIt
|
||||||
func PIt(text string, _ ...interface{}) bool {
|
func PIt(text string, _ ...interface{}) bool {
|
||||||
globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark Its as pending using XIt
|
//You can mark Its as pending using XIt
|
||||||
func XIt(text string, _ ...interface{}) bool {
|
func XIt(text string, _ ...interface{}) bool {
|
||||||
globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,25 +396,25 @@ func XIt(text string, _ ...interface{}) bool {
|
|||||||
//which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks
|
//which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks
|
||||||
//which apply to It blocks.
|
//which apply to It blocks.
|
||||||
func Specify(text string, body interface{}, timeout ...float64) bool {
|
func Specify(text string, body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can focus individual Specifys using FSpecify
|
//You can focus individual Specifys using FSpecify
|
||||||
func FSpecify(text string, body interface{}, timeout ...float64) bool {
|
func FSpecify(text string, body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark Specifys as pending using PSpecify
|
//You can mark Specifys as pending using PSpecify
|
||||||
func PSpecify(text string, is ...interface{}) bool {
|
func PSpecify(text string, is ...interface{}) bool {
|
||||||
globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark Specifys as pending using XSpecify
|
//You can mark Specifys as pending using XSpecify
|
||||||
func XSpecify(text string, is ...interface{}) bool {
|
func XSpecify(text string, is ...interface{}) bool {
|
||||||
globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,25 +445,25 @@ func By(text string, callbacks ...func()) {
|
|||||||
//The body function must have the signature:
|
//The body function must have the signature:
|
||||||
// func(b Benchmarker)
|
// func(b Benchmarker)
|
||||||
func Measure(text string, body interface{}, samples int) bool {
|
func Measure(text string, body interface{}, samples int) bool {
|
||||||
globalSuite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples)
|
global.Suite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can focus individual Measures using FMeasure
|
//You can focus individual Measures using FMeasure
|
||||||
func FMeasure(text string, body interface{}, samples int) bool {
|
func FMeasure(text string, body interface{}, samples int) bool {
|
||||||
globalSuite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples)
|
global.Suite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark Measurements as pending using PMeasure
|
//You can mark Measurements as pending using PMeasure
|
||||||
func PMeasure(text string, _ ...interface{}) bool {
|
func PMeasure(text string, _ ...interface{}) bool {
|
||||||
globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
|
global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//You can mark Measurements as pending using XMeasure
|
//You can mark Measurements as pending using XMeasure
|
||||||
func XMeasure(text string, _ ...interface{}) bool {
|
func XMeasure(text string, _ ...interface{}) bool {
|
||||||
globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
|
global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,7 +474,7 @@ func XMeasure(text string, _ ...interface{}) bool {
|
|||||||
//
|
//
|
||||||
//You may only register *one* BeforeSuite handler per test suite. You typically do so in your bootstrap file at the top level.
|
//You may only register *one* BeforeSuite handler per test suite. You typically do so in your bootstrap file at the top level.
|
||||||
func BeforeSuite(body interface{}, timeout ...float64) bool {
|
func BeforeSuite(body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +487,7 @@ func BeforeSuite(body interface{}, timeout ...float64) bool {
|
|||||||
//
|
//
|
||||||
//You may only register *one* AfterSuite handler per test suite. You typically do so in your bootstrap file at the top level.
|
//You may only register *one* AfterSuite handler per test suite. You typically do so in your bootstrap file at the top level.
|
||||||
func AfterSuite(body interface{}, timeout ...float64) bool {
|
func AfterSuite(body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,7 +532,7 @@ func AfterSuite(body interface{}, timeout ...float64) bool {
|
|||||||
// Ω(err).ShouldNot(HaveOccurred())
|
// Ω(err).ShouldNot(HaveOccurred())
|
||||||
// })
|
// })
|
||||||
func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, timeout ...float64) bool {
|
func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, timeout ...float64) bool {
|
||||||
globalSuite.SetSynchronizedBeforeSuiteNode(
|
global.Suite.SetSynchronizedBeforeSuiteNode(
|
||||||
node1Body,
|
node1Body,
|
||||||
allNodesBody,
|
allNodesBody,
|
||||||
codelocation.New(1),
|
codelocation.New(1),
|
||||||
@ -566,7 +559,7 @@ func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, ti
|
|||||||
// dbRunner.Stop()
|
// dbRunner.Stop()
|
||||||
// })
|
// })
|
||||||
func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, timeout ...float64) bool {
|
func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.SetSynchronizedAfterSuiteNode(
|
global.Suite.SetSynchronizedAfterSuiteNode(
|
||||||
allNodesBody,
|
allNodesBody,
|
||||||
node1Body,
|
node1Body,
|
||||||
codelocation.New(1),
|
codelocation.New(1),
|
||||||
@ -581,7 +574,7 @@ func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, tim
|
|||||||
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
|
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
|
||||||
//a Done channel
|
//a Done channel
|
||||||
func BeforeEach(body interface{}, timeout ...float64) bool {
|
func BeforeEach(body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,7 +584,7 @@ func BeforeEach(body interface{}, timeout ...float64) bool {
|
|||||||
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
|
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
|
||||||
//a Done channel
|
//a Done channel
|
||||||
func JustBeforeEach(body interface{}, timeout ...float64) bool {
|
func JustBeforeEach(body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,7 +594,7 @@ func JustBeforeEach(body interface{}, timeout ...float64) bool {
|
|||||||
//Like It blocks, JustAfterEach blocks can be made asynchronous by providing a body function that accepts
|
//Like It blocks, JustAfterEach blocks can be made asynchronous by providing a body function that accepts
|
||||||
//a Done channel
|
//a Done channel
|
||||||
func JustAfterEach(body interface{}, timeout ...float64) bool {
|
func JustAfterEach(body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,13 +604,13 @@ func JustAfterEach(body interface{}, timeout ...float64) bool {
|
|||||||
//Like It blocks, AfterEach blocks can be made asynchronous by providing a body function that accepts
|
//Like It blocks, AfterEach blocks can be made asynchronous by providing a body function that accepts
|
||||||
//a Done channel
|
//a Done channel
|
||||||
func AfterEach(body interface{}, timeout ...float64) bool {
|
func AfterEach(body interface{}, timeout ...float64) bool {
|
||||||
globalSuite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
global.Suite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTimeout(timeout ...float64) time.Duration {
|
func parseTimeout(timeout ...float64) time.Duration {
|
||||||
if len(timeout) == 0 {
|
if len(timeout) == 0 {
|
||||||
return time.Duration(defaultTimeout * int64(time.Second))
|
return global.DefaultTimeout
|
||||||
} else {
|
} else {
|
||||||
return time.Duration(timeout[0] * float64(time.Second))
|
return time.Duration(timeout[0] * float64(time.Second))
|
||||||
}
|
}
|
||||||
|
9
vendor/github.com/onsi/ginkgo/go.mod
generated
vendored
9
vendor/github.com/onsi/ginkgo/go.mod
generated
vendored
@ -1,9 +1,12 @@
|
|||||||
module github.com/onsi/ginkgo
|
module github.com/onsi/ginkgo
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
github.com/nxadm/tail v1.4.4
|
github.com/nxadm/tail v1.4.4
|
||||||
github.com/onsi/gomega v1.7.1
|
github.com/onsi/gomega v1.10.1
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e
|
github.com/sclevine/agouti v3.0.0+incompatible // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299
|
||||||
|
golang.org/x/text v0.3.2 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.12
|
go 1.13
|
||||||
|
40
vendor/github.com/onsi/ginkgo/go.sum
generated
vendored
40
vendor/github.com/onsi/ginkgo/go.sum
generated
vendored
@ -1,24 +1,62 @@
|
|||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
|
github.com/sclevine/agouti v3.0.0+incompatible h1:8IBJS6PWz3uTlMP3YBIR5f+KAldcGuOeFkFbUWfBgK4=
|
||||||
|
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
@ -27,3 +65,5 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
|
|||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
18
vendor/github.com/onsi/ginkgo/internal/global/init.go
generated
vendored
Normal file
18
vendor/github.com/onsi/ginkgo/internal/global/init.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/onsi/ginkgo/internal/failer"
|
||||||
|
"github.com/onsi/ginkgo/internal/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DefaultTimeout = time.Duration(1 * time.Second)
|
||||||
|
|
||||||
|
var Suite *suite.Suite
|
||||||
|
var Failer *failer.Failer
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Failer = failer.New()
|
||||||
|
Suite = suite.New(Failer)
|
||||||
|
}
|
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_darwin.go
generated
vendored
Normal file
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_darwin.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup2(oldfd, newfd)
|
||||||
|
}
|
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_dragonfly.go
generated
vendored
Normal file
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_dragonfly.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build dragonfly
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup2(oldfd, newfd)
|
||||||
|
}
|
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_freebsd.go
generated
vendored
Normal file
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_freebsd.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build freebsd
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup2(oldfd, newfd)
|
||||||
|
}
|
12
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux.go
generated
vendored
Normal file
12
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// +build linux
|
||||||
|
// +build !mips64le
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup2(oldfd, newfd)
|
||||||
|
}
|
12
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux_mips64le.go
generated
vendored
Normal file
12
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux_mips64le.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// +build linux
|
||||||
|
// +build mips64le
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup3(oldfd, newfd, 0)
|
||||||
|
}
|
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_netbsd.go
generated
vendored
Normal file
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_netbsd.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build netbsd
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup2(oldfd, newfd)
|
||||||
|
}
|
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_openbsd.go
generated
vendored
Normal file
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_openbsd.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build openbsd
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup2(oldfd, newfd)
|
||||||
|
}
|
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_solaris.go
generated
vendored
Normal file
11
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_solaris.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func interceptorDupx(oldfd int, newfd int) {
|
||||||
|
unix.Dup2(oldfd, newfd)
|
||||||
|
}
|
7
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go
generated
vendored
7
vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go
generated
vendored
@ -8,7 +8,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/nxadm/tail"
|
"github.com/nxadm/tail"
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewOutputInterceptor() OutputInterceptor {
|
func NewOutputInterceptor() OutputInterceptor {
|
||||||
@ -36,10 +35,8 @@ func (interceptor *outputInterceptor) StartInterceptingOutput() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// This might call Dup3 if the dup2 syscall is not available, e.g. on
|
interceptorDupx(int(interceptor.redirectFile.Fd()), 1)
|
||||||
// linux/arm64 or linux/riscv64
|
interceptorDupx(int(interceptor.redirectFile.Fd()), 2)
|
||||||
unix.Dup2(int(interceptor.redirectFile.Fd()), 1)
|
|
||||||
unix.Dup2(int(interceptor.redirectFile.Fd()), 2)
|
|
||||||
|
|
||||||
if interceptor.streamTarget != nil {
|
if interceptor.streamTarget != nil {
|
||||||
interceptor.tailer, _ = tail.TailFile(interceptor.redirectFile.Name(), tail.Config{Follow: true})
|
interceptor.tailer, _ = tail.TailFile(interceptor.redirectFile.Name(), tail.Config{Follow: true})
|
||||||
|
12
vendor/modules.txt
vendored
12
vendor/modules.txt
vendored
@ -28,14 +28,17 @@ github.com/alexflint/go-filemutex
|
|||||||
# github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44
|
# github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44
|
||||||
## explicit
|
## explicit
|
||||||
github.com/buger/jsonparser
|
github.com/buger/jsonparser
|
||||||
# github.com/containernetworking/cni v0.8.1
|
# github.com/containernetworking/cni v0.8.1-0.20201216164644-62e54113f44a
|
||||||
## explicit
|
## explicit
|
||||||
github.com/containernetworking/cni/libcni
|
github.com/containernetworking/cni/libcni
|
||||||
github.com/containernetworking/cni/pkg/invoke
|
github.com/containernetworking/cni/pkg/invoke
|
||||||
github.com/containernetworking/cni/pkg/skel
|
github.com/containernetworking/cni/pkg/skel
|
||||||
github.com/containernetworking/cni/pkg/types
|
github.com/containernetworking/cni/pkg/types
|
||||||
github.com/containernetworking/cni/pkg/types/020
|
github.com/containernetworking/cni/pkg/types/020
|
||||||
github.com/containernetworking/cni/pkg/types/current
|
github.com/containernetworking/cni/pkg/types/040
|
||||||
|
github.com/containernetworking/cni/pkg/types/100
|
||||||
|
github.com/containernetworking/cni/pkg/types/create
|
||||||
|
github.com/containernetworking/cni/pkg/types/internal
|
||||||
github.com/containernetworking/cni/pkg/utils
|
github.com/containernetworking/cni/pkg/utils
|
||||||
github.com/containernetworking/cni/pkg/version
|
github.com/containernetworking/cni/pkg/version
|
||||||
# github.com/coreos/go-iptables v0.5.0
|
# github.com/coreos/go-iptables v0.5.0
|
||||||
@ -57,7 +60,7 @@ github.com/d2g/dhcp4server/leasepool
|
|||||||
github.com/d2g/dhcp4server/leasepool/memorypool
|
github.com/d2g/dhcp4server/leasepool/memorypool
|
||||||
# github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4
|
# github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4
|
||||||
## explicit
|
## explicit
|
||||||
# github.com/fsnotify/fsnotify v1.4.7
|
# github.com/fsnotify/fsnotify v1.4.9
|
||||||
github.com/fsnotify/fsnotify
|
github.com/fsnotify/fsnotify
|
||||||
# github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c
|
# github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c
|
||||||
## explicit
|
## explicit
|
||||||
@ -74,7 +77,7 @@ github.com/nxadm/tail/ratelimiter
|
|||||||
github.com/nxadm/tail/util
|
github.com/nxadm/tail/util
|
||||||
github.com/nxadm/tail/watch
|
github.com/nxadm/tail/watch
|
||||||
github.com/nxadm/tail/winfile
|
github.com/nxadm/tail/winfile
|
||||||
# github.com/onsi/ginkgo v1.12.1
|
# github.com/onsi/ginkgo v1.13.0
|
||||||
## explicit
|
## explicit
|
||||||
github.com/onsi/ginkgo
|
github.com/onsi/ginkgo
|
||||||
github.com/onsi/ginkgo/config
|
github.com/onsi/ginkgo/config
|
||||||
@ -82,6 +85,7 @@ github.com/onsi/ginkgo/extensions/table
|
|||||||
github.com/onsi/ginkgo/internal/codelocation
|
github.com/onsi/ginkgo/internal/codelocation
|
||||||
github.com/onsi/ginkgo/internal/containernode
|
github.com/onsi/ginkgo/internal/containernode
|
||||||
github.com/onsi/ginkgo/internal/failer
|
github.com/onsi/ginkgo/internal/failer
|
||||||
|
github.com/onsi/ginkgo/internal/global
|
||||||
github.com/onsi/ginkgo/internal/leafnodes
|
github.com/onsi/ginkgo/internal/leafnodes
|
||||||
github.com/onsi/ginkgo/internal/remote
|
github.com/onsi/ginkgo/internal/remote
|
||||||
github.com/onsi/ginkgo/internal/spec
|
github.com/onsi/ginkgo/internal/spec
|
||||||
|
Loading…
x
Reference in New Issue
Block a user