Compare commits

...

151 Commits

Author SHA1 Message Date
38f18d26ec Merge pull request #892 from e0ne/ignore-not-found
[sbr]: Ignore LinkNotFoundError during cmdDel
2023-05-03 21:53:21 +02:00
e51301765c Merge pull request #891 from containernetworking/dependabot/go_modules/github.com/Microsoft/hcsshim-0.9.9
build(deps): bump github.com/Microsoft/hcsshim from 0.9.8 to 0.9.9
2023-05-03 17:26:09 +02:00
7e918412d5 [sbr]: Ignore LinkNotFoundError during cmdDel
Signed-off-by: Ivan Kolodyazhny <e0ne@e0ne.info>
2023-05-02 14:08:11 +03:00
99b475ab1a build(deps): bump github.com/Microsoft/hcsshim from 0.9.8 to 0.9.9
Bumps [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) from 0.9.8 to 0.9.9.
- [Release notes](https://github.com/Microsoft/hcsshim/releases)
- [Commits](https://github.com/Microsoft/hcsshim/compare/v0.9.8...v0.9.9)

---
updated-dependencies:
- dependency-name: github.com/Microsoft/hcsshim
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 03:02:09 +00:00
10b5639361 Merge pull request #885 from champtar/tuning-CHECK
tuning: fix cmdCheck when using IFNAME
2023-04-24 10:46:37 -05:00
65fe256058 Merge pull request #883 from mmorel-35/linter-2
enable govet and unparam linters
2023-04-24 17:42:55 +02:00
00b82fb666 Merge pull request #887 from champtar/route-CHECK
Fix ValidateExpectedRoute with non default routes and nil GW
2023-04-24 10:41:24 -05:00
c795a3c6b1 Merge pull request #888 from jingyuanliang/go120
Bump to golang 1.20 to pick up go1.19.6 / go1.20.1 CVE fixes
2023-04-24 17:37:28 +02:00
c10af01dfb Merge pull request #880 from maiqueb/mac-spoof-improv-read-only-required-chain-on-cni-del
bridge: read only required chain on cni del instead of the entire ruleset
2023-04-24 17:32:32 +02:00
9cf1a09835 Merge pull request #829 from tjjh89017/bridge_vlan_trunk
bridge: add vlan trunk support
2023-04-24 10:25:16 -05:00
d8fc886bf0 Bump to golang 1.20 to pick up go1.19.6 / go1.20.1 CVE fixes
Go 1.18 is already EOL and doesn't have fixes available.

Signed-off-by: Jingyuan Liang <jingyuanliang@google.com>
2023-04-21 05:21:43 +00:00
c347755f87 Fix ValidateExpectedRoute with non default routes and nil GW
Using ptp plugin with non default routes, we get the following error
when cri-o call CheckNetworkList():
```
Expected Route {Dst:{IP:198.18.128.0 Mask:ffff8000} GW:<nil>} not found in routing table
```
Using cniVersion 0.3.1 to bypass the check, we can see that the
route is added with a gateway
```
$ ip r
198.18.0.0/17 via 198.18.0.1 dev eth0 src 198.18.3.102
198.18.0.1 dev eth0 scope link src 198.18.3.102
198.18.128.0/17 via 198.18.0.1 dev eth0
```

If GW is nil only check if we have a route with a DST that matches, and
ignore the GW.

Fixes #886
Signed-off-by: Etienne Champetier <e.champetier@ateme.com>
2023-04-20 15:24:20 -04:00
5b7a263e8f tuning: fix cmdCheck when using IFNAME
Fixes: c16cff9805
Signed-off-by: Etienne Champetier <e.champetier@ateme.com>
2023-04-20 11:19:23 -04:00
135292e050 bridge, del: timeout after 55 secs of trying to list rules
Making sure the exec'ed nft command is executed in 55 secs allows for
CNI to fail early, thus preventing CRI from sending another CNI DEL
while the previous NFT call is still being processed.

This fix prevents part of the behavior described in [0], in which:
> cnv-bridge and nft comes pile up in a loop, increasing every 60, never
completes

The timeout had to be less than 60 seconds (otherwise CRI would still
trigger CNI DEL again) but large enough for this feature to have a
chance of working on older kernels (e.g. centOS 8), where it takes
longer to access even a specific chain/table.

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
2023-04-20 11:19:07 +02:00
7dcd738d34 bridge, spoofcheck: only read the prerouting chain on CNI delete
Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
2023-04-20 10:35:42 +02:00
83fe87c5b0 build: consume specific tables/chains via go-nft
This go-nft version allows its users to only read particular
tables/chains when invoking `ReadConfig`, instead of the entire ruleset.

This will make deleting rules from a large ruleset faster, thus speeding
up CNI DELs.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2175041

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
2023-04-20 10:08:18 +02:00
090af7db9a bridge: add vlan trunk support
add vlan trunk support for veth
vlan trunk only support L2 only mode without any IPAM
refer ovs-cni design
https://github.com/k8snetworkplumbingwg/ovs-cni/blob/main/pkg/plugin/plugin.go

design:
origin "vlan" option will be PVID or untagged vlan for the network.
"vlanTrunk" will setup tagged vlan for veth.

entry type:
`{ "id": 100 }` will specify only tagged vlan 100
`{ "minID": 100, "maxID": 120 }` will specify tagged vlan from 100 to
120 (include 100 and 120)
vlanTrunk is a list of above entry type, so you can use this to add
tagged vlan
`[
  { "id": 100 },
  {
    "minID": 1000,
    "maxID": 2000
  }
]`

complete config will be like this
{
  "cniVersion": "0.3.1",
  "name": "mynet",
  "type": "bridge",
  "bridge": "mynet0",
  "vlan": 100,
  "vlanTrunk": [
    { "id": 101 },
    { "minID": 1000, "maxID": 2000 },
    { "minID": 3000, "maxID": 4000 }
  ],
  "ipam": {}
}

Signed-off-by: Date Huang <date.huang@suse.com>
2023-04-19 22:55:14 +08:00
9f1f9a588b Merge pull request #875 from mlguerrero12/adddefaultvlanparam
Add parameter to disable default vlan
2023-04-17 17:47:34 +02:00
71aa710196 Merge pull request #873 from maiqueb/mac-spoof-remove-index-when-adding-rules
bridge, spoof check: remove drop rule index
2023-04-17 17:07:11 +02:00
10ddd9e454 enable govet and unparam linters
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-04-11 12:07:04 +02:00
4a6147a155 Merge pull request #881 from containernetworking/dependabot/go_modules/golang.org/x/sys-0.7.0 2023-04-05 19:24:31 +00:00
435ef2235d build(deps): bump golang.org/x/sys from 0.6.0 to 0.7.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-05 19:14:01 +00:00
43db9cc063 Merge pull request #879 from squeed/bump-deps
go.mod: bump all deps
2023-04-05 21:13:05 +02:00
821982da1c Add parameter to disable default vlan
This new parameter allows users to remove the default vlan

Fixes: #667
Signed-off-by: Marcelo Guerrero Viveros <marguerr@redhat.com>
2023-04-05 18:20:40 +02:00
cac8230e7c bridge, spoof check: remove drop rule index
Rules are appendend by default, thus using an index is redundant.
Using an index also requires the full NFT cache, which causes a CNI ADD
to be extremely slow.

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
2023-04-04 17:10:08 +02:00
bc5f3defe7 go.mod: bump all deps
Bump all transitive and direct dependencies.

Signed-off-by: Casey Callendrello <c1@caseyc.net>
2023-04-04 16:31:14 +02:00
47a4319462 Merge pull request #861 from containernetworking/dependabot/github_actions/actions/setup-go-4
build(deps): bump actions/setup-go from 3 to 4
2023-04-04 16:27:44 +02:00
68a661999a Merge pull request #870 from containernetworking/dependabot/github_actions/actions/stale-8
build(deps): bump actions/stale from 7 to 8
2023-04-04 16:27:10 +02:00
63235a2531 Merge pull request #878 from maiqueb/fix-ginkgo-linter-warnings
linter: fix ginkgolinter errors
2023-04-04 16:23:41 +02:00
7bbd4d19e9 linter: fix ginkgolinter errors
Use:
- `BeEmpty` instead of `HaveLen(0)`
- `Expect(x).To(BeZero())` instead of `Expect(x == 0).To(BeTrue())`

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
2023-04-04 16:09:01 +02:00
deec68747e Merge pull request #853 from mmorel-35/ginkgolinter
enable ginkgolinter linter
2023-04-04 15:24:20 +02:00
6f6345ca05 Merge pull request #871 from mlguerrero12/fixwastedassignlinter
Fix wastedassign linter errors
2023-04-04 15:23:28 +02:00
6c0d73ecc0 Fix wastedassign linter errors
Signed-off-by: Marcelo Guerrero Viveros <marguerr@redhat.com>
2023-03-27 18:42:49 +02:00
8813bfea7b Merge pull request #855 from mmorel-35/linters
enable durationcheck,  predeclared, unconvert, unused and wastedassign linters
2023-03-27 10:53:34 -05:00
16d05ec100 Merge pull request #867 from mlguerrero12/fixlinters
Fix revive linter errors
2023-03-27 10:49:33 -05:00
086f7eb7a1 build(deps): bump actions/stale from 7 to 8
Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-27 03:04:07 +00:00
d71d0f2da1 Fix revive linter errors
Golangci-lint is now running version 1.52.1. This introduced some errors.

Signed-off-by: Marcelo Guerrero Viveros <marguerr@redhat.com>
2023-03-24 21:04:39 +01:00
00e0d3b758 build(deps): bump actions/setup-go from 3 to 4
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:01:39 +00:00
2fb0efe8a3 enable durationcheck, predeclared, unconvert, unused and wastedassign linters
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-16 07:29:37 +01:00
3bc00017e3 Merge pull request #854 from mmorel-35/clean-linters
remove govet and gofmt from test_linux.sh
2023-03-14 11:49:37 +01:00
c0fe3b7bde remove govet and gofmt from test_linux.sh
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-13 22:47:17 +00:00
09f36a295d enable ginkgolinter linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-13 22:27:21 +00:00
d3ee71f240 Merge pull request #843 from mmorel-35/golangci-lint
ci(lint): setup golangci-lint
2023-03-13 22:26:32 +01:00
a02bf4b463 enable revive linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-13 17:59:41 +01:00
79f524689c enable gocritic linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-13 17:59:33 +01:00
5a7619c019 enable gosimple linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-13 17:59:31 +01:00
709e775b13 enable nonamedreturns linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-13 17:59:28 +01:00
3a04eb00bb enable ineffassign linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-06 11:51:40 +01:00
16ba4222bc enable contextcheck linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-06 11:23:07 +01:00
177e0bf2d9 enable staticcheck linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-02 11:06:22 +01:00
d12b81dec5 ci(lint): setup golangci-lint
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-03-01 06:55:40 +00:00
86e39cfe3c Merge pull request #836 from mmorel-35/yamllint
ci(lint): setup yamllint linter
2023-02-28 16:35:10 +01:00
6223674f25 ci(lint): setup yamllint linter
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-02-25 12:10:11 +00:00
36e1e162fa Merge pull request #812 from liornoy/ginkgov2
Update ginkgo to v2
2023-02-20 10:58:24 -06:00
286064b9ec Merge pull request #831 from mlguerrero12/fixerrorignored
Fix overwritten error var in getMTUByName
2023-02-20 10:13:34 -06:00
9ee4d3225d Fix overwritten error var in getMTUByName
this prevents the error to be lost which was causing the
panic while accesing a nil var.

Fix #830

Signed-off-by: Marcelo Guerrero Viveros <marguerr@redhat.com>
2023-02-16 12:28:17 +01:00
2d1005ec02 Update tests to utilize ginkgo/v2
This commit updates the import of ginkgo to v2 in
all of the tests.

Signed-off-by: liornoy <lnoy@redhat.com>
Co-authored-by: Sascha Grunert <sgrunert@redhat.com>
2023-02-13 21:15:18 +02:00
23c2134110 Update ginkgo to v2 in go.mod, go.sum, vendor
This commit updates ginkgo to v2.
Note that because ginkgo/v2 requires go1.18, it was
updated as well.

Signed-off-by: liornoy <lnoy@redhat.com>
Co-authored-by: Sascha Grunert <sgrunert@redhat.com>
2023-02-13 21:15:18 +02:00
fb92605570 Merge pull request #784 from mmirecki/tap-plugin
Tap plugin
2023-02-13 17:26:06 +01:00
01d0031487 Tap plugin
This PR adds a plugin to create tap devices.
The plugin adds a tap device to the container.

The plugin has a workaround for a golang netlink library
which does not allow for tap devices with no owner/group
to be created. When no tap owner/group is requested, the
plugin will fall back to using the ip tool for creating
the tap device. A fix to the golang netlink lib is pending.

Signed-off-by: mmirecki <mmirecki@redhat.com>
2023-02-13 17:14:46 +01:00
98e01b7c80 Merge pull request #824 from containernetworking/dependabot/go_modules/github.com/onsi/gomega-1.26.0
build(deps): bump github.com/onsi/gomega from 1.24.2 to 1.26.0
2023-02-13 10:09:15 -06:00
9a2f763345 build(deps): bump github.com/onsi/gomega from 1.24.2 to 1.26.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.24.2 to 1.26.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.24.2...v1.26.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 10:23:59 +00:00
98359ff8b4 Merge pull request #828 from containernetworking/dependabot/go_modules/golang.org/x/sys-0.5.0
build(deps): bump golang.org/x/sys from 0.4.0 to 0.5.0
2023-02-13 11:23:00 +01:00
29e6486154 build(deps): bump golang.org/x/sys from 0.4.0 to 0.5.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 03:22:30 +00:00
bbf47c1083 Merge pull request #814 from mmirecki/macvlan_incontainermaster
Add support for in-container master for macvlans
2023-02-08 12:55:44 +01:00
5d02d91c96 Merge pull request #813 from mmirecki/ipvlan_incontainermaster
Add support for in-container master for ipvlan
2023-02-06 09:49:06 -06:00
755714d716 Merge pull request #781 from mmirecki/vlan_incontainermaster
Add support for in-container master for vlans
2023-02-06 09:47:58 -06:00
e2e14ee46f Merge pull request #821 from mccv1r0/portmapCheck
Only check or del ipv6 when an IPv6 is configured
2023-02-01 14:02:07 -06:00
fb5d195fc5 Only check ipv6 when an IPv6 is configured
Signed-off-by: Michael Cambria <mccv1r0@gmail.com>
2023-01-27 20:22:11 -05:00
ac7cf82531 Add support for in-container master for macvlans
Signed-off-by: mmirecki <mmirecki@redhat.com>
2023-01-25 12:58:28 +01:00
c798f80912 Add support for in-container master for ipvlan
Signed-off-by: mmirecki <mmirecki@redhat.com>
2023-01-25 12:11:06 +01:00
9fa80036d3 Add support for in-container master for vlans
Signed-off-by: mmirecki <mmirecki@redhat.com>
2023-01-25 11:50:12 +01:00
c4d24e80d6 Merge pull request #809 from squeed/bridge-refresh-mac
bridge: refresh host-veth mac after port add
2023-01-16 10:56:47 -06:00
2c4c27eb17 bridge: re-fetch mac address
It was noticed that, sometimes, the mac of the host-side of the veth
changes after setting up the bridge. So, just refresh it.

Fixes: #805
Signed-off-by: Casey Callendrello <c1@caseyc.net>
2023-01-16 17:36:40 +01:00
0924b71fc8 Merge pull request #790 from austinvazquez/remove-ioutil-references
Remove references to io/ioutil package
2023-01-16 10:45:56 +01:00
0af8153e9b Merge pull request #804 from mmorel-35/main
build(deps): bump github.com/safchain/ethtool to v0.2.0
2023-01-11 11:22:53 +01:00
83fe27748c Merge pull request #803 from containernetworking/dependabot/go_modules/golang.org/x/sys-0.4.0
build(deps): bump golang.org/x/sys from 0.3.0 to 0.4.0
2023-01-11 11:22:19 +01:00
bf9c25887a Merge pull request #792 from EmilyShepherd/check-dhcp
Update Allocate method to reuse lease if present
2023-01-10 14:47:54 +01:00
0fc229df5e Update Allocate method to reuse lease if present
Previously, the Allocate method of the daemon always created a new Lease
object. However, as both the CNI ADD and CHECK commands call Allocate,
and CHECK can be called multiple times, this resulted in multiple Lease
objects being created per pod.

Each of these leases was long lived with its own maintain() loop -
however the daemon only kept track of the most recent one, meaning any
old lease objects remained running forever (and held open their NetNS
files). After a long enough period, this resulted in the system crashing
out with "too many files" or a similar error limits-related error.

This commit updates the behaviour of Allocate() to first check if a
Lease already exists for the given clientID. If none is found, one is
created as before. If a Lease is found, a new Check() mechanism is
called, which simply wakes up the maintain() loop to cause it to check
the status of the lease.

This may fix #329.

Signed-off-by: Emily Shepherd <emily@redcoat.dev>
2023-01-10 13:10:21 +00:00
ec924a4be2 build(deps): bump github.com/safchain/ethtool to v0.2.0
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-01-09 18:17:27 +00:00
d27fabcd83 Merge pull request #782 from mars1024/bugfix/next-ip
fix bug on getting NextIP of addresses with first byte 0
2023-01-09 18:02:45 +01:00
20a92ff382 build(deps): bump golang.org/x/sys from 0.3.0 to 0.4.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 16:59:28 +00:00
5c29eb7fb5 Merge pull request #801 from mmorel-35/main
ci(deps): setup dependabot
2023-01-09 17:58:48 +01:00
f48a5ea512 Merge pull request #798 from mmirecki/pathissue_fix
Fix tuning path validation
2023-01-09 17:48:00 +01:00
a3b678ee03 Merge pull request #772 from BSWANG/master
`portmap` support masquerade all
2023-01-09 17:41:52 +01:00
87ccb8918b Merge pull request #802 from Y7n05h/main
Add IPv6 support for AddDefaultRoute
2023-01-09 17:38:37 +01:00
fa2ed0fd6e Add IPv6 support for AddDefaultRoute
Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
2022-12-28 15:37:29 +08:00
b769956cf4 build(deps): bump github.com/containernetworking/cni from 1.0.1 to 1.1.2
Bumps [github.com/containernetworking/cni](https://github.com/containernetworking/cni) from 1.0.1 to 1.1.2.
- [Release notes](https://github.com/containernetworking/cni/releases)
- [Commits](https://github.com/containernetworking/cni/compare/v1.0.1...v1.1.2)

---
updated-dependencies:
- dependency-name: github.com/containernetworking/cni
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
df141fc722 build(deps): bump github.com/coreos/go-systemd/v22 from 22.3.2 to 22.5.0
Bumps [github.com/coreos/go-systemd/v22](https://github.com/coreos/go-systemd) from 22.3.2 to 22.5.0.
- [Release notes](https://github.com/coreos/go-systemd/releases)
- [Commits](https://github.com/coreos/go-systemd/compare/v22.3.2...v22.5.0)

---
updated-dependencies:
- dependency-name: github.com/coreos/go-systemd/v22
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
35047644a8 build(deps): bump github.com/onsi/ginkgo from 1.16.4 to 1.16.5
Bumps [github.com/onsi/ginkgo](https://github.com/onsi/ginkgo) from 1.16.4 to 1.16.5.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v1.16.4...v1.16.5)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
352f181ff1 build(deps): bump alpine in /.github/actions/retest-action
Bumps alpine from 3.10 to 3.17.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
91b1a0e385 build(deps): bump github.com/godbus/dbus/v5 from 5.0.4 to 5.1.0
Bumps [github.com/godbus/dbus/v5](https://github.com/godbus/dbus) from 5.0.4 to 5.1.0.
- [Release notes](https://github.com/godbus/dbus/releases)
- [Commits](https://github.com/godbus/dbus/compare/v5.0.4...v5.1.0)

---
updated-dependencies:
- dependency-name: github.com/godbus/dbus/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
648dd2e14c build(deps): bump github.com/vishvananda/netlink
Bumps [github.com/vishvananda/netlink](https://github.com/vishvananda/netlink) from 1.2.0-beta to 1.2.1-beta.2.
- [Release notes](https://github.com/vishvananda/netlink/releases)
- [Commits](https://github.com/vishvananda/netlink/compare/v1.2.0-beta...v1.2.1-beta.2)

---
updated-dependencies:
- dependency-name: github.com/vishvananda/netlink
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
615420fa9f build(deps): bump github.com/alexflint/go-filemutex from 1.1.0 to 1.2.0
Bumps [github.com/alexflint/go-filemutex](https://github.com/alexflint/go-filemutex) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/alexflint/go-filemutex/releases)
- [Commits](https://github.com/alexflint/go-filemutex/compare/v1.1...v1.2.0)

---
updated-dependencies:
- dependency-name: github.com/alexflint/go-filemutex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
90ed30a55a build(deps): bump github.com/Microsoft/hcsshim from 0.8.20 to 0.9.6
Bumps [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) from 0.8.20 to 0.9.6.
- [Release notes](https://github.com/Microsoft/hcsshim/releases)
- [Commits](https://github.com/Microsoft/hcsshim/compare/v0.8.20...v0.9.6)

---
updated-dependencies:
- dependency-name: github.com/Microsoft/hcsshim
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
020b8db6ab build(deps): bump github.com/onsi/gomega from 1.15.0 to 1.24.2
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.15.0 to 1.24.2.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.15.0...v1.24.2)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
c5e81e3c05 Update dependabot.yml
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
3be17f4af7 build(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
f64652faf8 build(deps): bump actions/stale from 4 to 7
Bumps [actions/stale](https://github.com/actions/stale) from 4 to 7.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
edfd2274a5 build(deps): bump actions/setup-go from 2 to 3
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
d7efab18c0 Update dependabot.yml
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
12471312e1 Update dependabot.yml
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
c1e2be2765 ci(deps): setup dependabot
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2022-12-26 21:36:15 +00:00
fd9408bc97 Fix tuning path validation
Signed-off-by: mmirecki <mmirecki@redhat.com>
2022-12-16 11:55:33 +01:00
ec76e3c35c Merge pull request #793 from EmilyShepherd/fix-ci
Fix Tests: Update portmap test's iptables error check
2022-12-12 10:48:32 -06:00
c30b47a712 Merge pull request #795 from MikeZappa87/updateemailtogmail
Update email to gmail
2022-12-12 10:47:48 -06:00
9dc2ed2c0a Update email to gmail
Signed-off-by: Michael Zappa <michael.zappa@gmail.com>
2022-12-07 11:57:16 -07:00
6b30e290d2 Update portmap test's iptables error check
GitHub Actions recently updated ubuntu-latest to 22.04 [1], which now
defaults to nfttables (rather than iptables-legacy) [2]. The portmap
tests in this project are written with the expectation that expected
error message for one test is in the iptables-legacy format.

This commit updates the check to make it work for both the
iptables-legecy and iptables-nftables variants.

References:
[1]: 4aba37bd3b
[2]: https://ubuntu.com/blog/whats-new-in-security-for-ubuntu-22-04-lts

Signed-off-by: Emily Shepherd <emily@redcoat.dev>
2022-12-06 18:56:59 +00:00
1a6f478913 Remove references to io/ioutil package
Signed-off-by: Austin Vazquez <macedonv@amazon.com>
2022-12-01 22:27:05 +00:00
63a6dbcfd6 fix bug on getting NextIP of addresses with first byte 0
1. get the right next IP of addresses of first byte 0
2. refactor some methods to handle illegal IPs or IPNets
3. add some unit tests

Signed-off-by: Bruce Ma <brucema19901024@gmail.com>
2022-11-17 17:54:16 +08:00
7e9ada51e7 Merge pull request #779 from mmirecki/sysctl_on_vlan
Fix path substitution to enable setting sysctls on vlan interfaces
2022-11-14 10:51:25 -06:00
198ab129a1 Fix path substitution to enable setting sysctls on vlan interfaces
This commit changes the order of substituting sysctl path to first handle
. to / change, before substituting the interface name.
This is needed as vlan interfaces have a . in the name, which should not
be changed.

Signed-off-by: mmirecki <mmirecki@redhat.com>
2022-11-09 11:31:58 +01:00
0463fd19af support masquerade all config
Signed-off-by: bingshen.wbs <bingshen.wbs@alibaba-inc.com>
2022-11-07 13:50:21 +08:00
ac8673105a Merge pull request #743 from arista-eosplus/dummy-plugin
dummy: Create a Dummy CNI plugin that creates a virtual interface.
2022-10-10 17:51:00 +02:00
fcf14d39fd Merge pull request #769 from jingyuanliang/main
host-local: remove unused Release(ip) from type Store interface
2022-09-19 10:55:33 -05:00
54f69e0a59 Merge pull request #768 from EmilyShepherd/cleanup-socket-on-exit
Cleanup Socket and Pidfile on exit
2022-09-12 10:34:39 -05:00
87c3643d3c host-local: remove unused Release(ip) from type Store interface
Signed-off-by: Jingyuan Liang <jingyuanliang@google.com>
2022-09-06 21:39:54 +00:00
f89a005740 Cleanup Socket and Pidfile on exit
These were previously left intact, even when exiting gracefully. As the
daemon also fails if the socket already exists, it became the caller's
responsibilityto check for and cleanup old socket files when performing
graceful / deliberate restarts.

Signed-off-by: Emily Shepherd <emily@redcoat.dev>
2022-09-06 15:11:57 +01:00
7fcf8e4860 dummy: Create a Dummy CNI plugin that creates a virtual interface.
Leverages the Linux dummy interface type to create network interfaces
that permists routing packets through the Linux kernel without
them being transmitted.

This solution allows use of arbitrary non-loopback IP addresses within
the container.

Related to #466

Signed-off-by: Mircea Iordache-Sica <mircea@arista.com>
2022-08-11 13:50:37 +01:00
8c3664b2b1 Merge pull request #742 from lx1036/patch-1
bridge: update vlanFiltering variable to make code more readable
2022-07-28 09:13:29 -05:00
e2a71387ab Merge pull request #755 from akhilles/fix/dhcp-renew-hostname
Use the same options for acquiring, renewing lease
2022-07-27 10:37:31 -05:00
c78e1e4656 Use the same options for acquiring, renewing lease
Currently, hostname is set in the original DHCPREQUEST but not the
renewal. With some DHCP server implementations (such as FreeBSD dhcpd),
this leads to the hostname being cleared in the lease table.

This behavior is inconsistent with other DHCP clients such as dhclient
which set the hostname on the renewal request as well. To fix, use the
same options for acquire and renew.

This is compatible with RFC 2131 (see table 5).

Signed-off-by: Akhil Velagapudi <4@4khil.com>
2022-06-23 17:47:37 -07:00
9f4090dabf bridge: update vlanFiltering variable to make code more readable
Signed-off-by: Xiang Liu <lx1036@126.com>
2022-05-21 14:37:36 +08:00
9c59728d39 Merge pull request #730 from mmirecki/tuning_duplicate_check
Check for duplicated sysctl keys
2022-05-04 11:21:35 -05:00
6a94696205 Merge pull request #712 from mesosphere/joe/add_error_output
bug: return errors when iptables and ip6tables are unusable
2022-05-04 11:01:41 -05:00
356db54531 Merge pull request #740 from jpsim/patch-1
ci: only rerun failed jobs on `/retest`
2022-05-04 11:00:26 -05:00
f7dfa0f600 Merge pull request #739 from AkihiroSuda/riscv64
build: support riscv64
2022-05-04 17:44:44 +02:00
f1aa6c2622 ci: only rerun failed jobs on /retest
Unlike `rerun_url`, this endpoint isn't in the run API response,
but we can construct it manually easily.

Documentation for it is here:
https://docs.github.com/en/rest/actions/workflow-runs#re-run-failed-jobs-from-a-workflow-run

Signed-off-by: JP Simard <jp@jpsim.com>
2022-04-28 22:13:02 -04:00
bf4068e1cd build: support riscv64
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
2022-04-29 01:53:59 +09:00
7c452c77cd Check for duplicated sysctl keys
Signed-off-by: mmirecki <mmirecki@redhat.com>
2022-04-27 22:13:17 +02:00
6264f7bff9 Merge pull request #735 from martinetd/crash-LTE
Update github.com/vishvananda/netlink to v1.2.0-beta
2022-04-27 11:02:30 -05:00
6bcc877722 Merge pull request #732 from squeed/go-1.18
Bump to go 1.18
2022-04-27 10:59:28 -05:00
9114aa6d37 Merge pull request #733 from Kern--/bridge-ipam-dns
bridge: support IPAM DNS settings
2022-04-27 17:59:06 +02:00
f891722833 Update github.com/vishvananda/netlink to v1.2.0-beta
Latest version fixes a segfault when used on some ppp setup

Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
2022-04-27 10:58:34 +09:00
a70e87c3aa bridge: support IPAM DNS settings
Previously, the bridge plugin ignored DNS settings returned
from an IPAM plugin (e.g. the host-local plugin parsing
resolv.conf to configure DNS). With this change, the bridge plugin
uses IPAM DNS settings.

Similarly to #388, this change will use incoming DNS settings if set,
otherwise IPAM plugin returned DNS settings

Signed-off-by: Kern Walster <walster@amazon.com>
2022-04-21 05:12:01 +00:00
0a0853a756 Bump to go 1.18
Signed-off-by: Casey Callendrello <cdc@redhat.com>
2022-04-20 18:06:58 +02:00
0c39335765 Merge pull request #725 from selansen/v2api-suuport-win-overlay
V2 API support for win-overlay CNI
2022-04-14 13:13:37 -05:00
8b8825bcd8 V2 API support for win-overlay CNI
This PR bring V2 API support into win-overlay CNI. With the current V1
API, only docker runtime works for win-overlay. By bringing new changes, we
should be able to use containerd as the runtime.Below are the key
points regarding this implementation.
	1. Clear seperation for V1 & V2 API support
	2. New cni.conf sample that works for win-overlay

Signed-off-by: selansen <esiva@redhat.com>
Signed-off-by: mansikulkarni96 <mankulka@redhat.com>
2022-04-14 12:44:49 -04:00
93604ec20a Merge pull request #724 from squeed/stale-keep
github: ignore issues with "keep" label from stale closing
2022-04-13 11:14:47 -05:00
e3d563b0f0 bug: return errors when iptables and ip6tables are unusable
Signed-off-by: Joe Julian <me@joejulian.name>
2022-04-01 11:03:54 -07:00
16e4a82b32 Merge pull request #719 from benmcmahon100/patch-1
Make description for `static` plugin more exact
2022-03-30 18:03:34 +02:00
e952f16c75 github: ignore issues with "keep" label from stale closing
Signed-off-by: Casey Callendrello <cdc@redhat.com>
2022-03-30 18:02:45 +02:00
5ad4fcf85a Make description for static plugin more exact
Signed-off-by: Ben McMahon <benmcmahon100@gmail.com>
2022-03-18 23:18:57 +00:00
292f188e4e Merge pull request #717 from squeed/auto-close-stale
workflow: add something to auto-close stale PRs
2022-03-16 16:58:48 +01:00
57c1cb5058 workflow: add something to auto-close stale PRs
Signed-off-by: Casey Callendrello <cdc@redhat.com>
2022-03-09 18:05:17 +01:00
b8a10bbe11 Merge pull request #702 from gojoy/master
call ipam.ExecDel after clean up device in netns
2022-03-02 10:50:25 -06:00
600c58a54f Merge pull request #709 from fwiesel/ipam_dhcp_client_id
ipam/dhcp: Fix client id in renew/release
2022-03-02 17:49:12 +01:00
3512b10ff0 Merge pull request #693 from mmirecki/POC_sysctl_whitelist
Add sysctl allowList
2022-03-02 17:40:46 +01:00
7a98979487 ipam/dhcp: Fix client id in renew/release
The client id was constructed differently in the acquire
function compared to the release and renew functions,
which caused the dhcp-server to consider it a different client.
This is now encapsulated in a common function.

Signed-off-by: Fabian Wiesel <fabian.wiesel@sap.com>
2022-02-27 22:19:50 +01:00
7aa07efe29 call ipam.ExceDel after clean up device in netns
fix #666

Signed-off-by: gojoy <729324352@qq.com>
2022-02-27 10:55:42 +08:00
96c3af81e2 Add sysctl allowlist
Signed-off-by: mmirecki <mmirecki@redhat.com>
2022-02-24 15:41:04 +01:00
1050 changed files with 116555 additions and 30550 deletions

View File

@ -1,4 +1,4 @@
FROM alpine:3.10 FROM alpine:3.17
RUN apk add --no-cache curl jq RUN apk add --no-cache curl jq

View File

@ -27,10 +27,10 @@ curl --request GET \
--header "authorization: Bearer ${GITHUB_TOKEN}" \ --header "authorization: Bearer ${GITHUB_TOKEN}" \
--header "content-type: application/json" | jq '.workflow_runs | max_by(.run_number)' > run.json --header "content-type: application/json" | jq '.workflow_runs | max_by(.run_number)' > run.json
RERUN_URL=$(jq -r '.rerun_url' run.json) RUN_URL=$(jq -r '.rerun_url' run.json)
curl --request POST \ curl --request POST \
--url "${RERUN_URL}" \ --url "${RUN_URL}/rerun-failed-jobs" \
--header "authorization: Bearer ${GITHUB_TOKEN}" \ --header "authorization: Bearer ${GITHUB_TOKEN}" \
--header "content-type: application/json" --header "content-type: application/json"

19
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,19 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "docker" # See documentation for possible values
directory: "/.github/actions/retest-action" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

View File

@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Re-Test Action - name: Re-Test Action
uses: ./.github/actions/retest-action uses: ./.github/actions/retest-action

13
.github/workflows/stale.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
stale-pr-message: 'This PR has been untouched for too long without an update. It will be closed in 7 days.'
exempt-issue-labels: 'keep'

View File

@ -4,19 +4,35 @@ name: test
on: ["push", "pull_request"] on: ["push", "pull_request"]
env: env:
GO_VERSION: "1.17" GO_VERSION: "1.20"
LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le" LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le riscv64"
jobs: jobs:
build: lint:
name: Build all linux architectures name: Lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: setup go - name: setup go
uses: actions/setup-go@v2 uses: actions/setup-go@v4
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: ibiqlik/action-yamllint@v3
with:
format: auto
- uses: golangci/golangci-lint-action@v3
with:
args: -v
build:
name: Build all linux architectures
needs: lint
runs-on: ubuntu-latest
steps:
- name: setup go
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v3
- name: Build on all supported architectures - name: Build on all supported architectures
run: | run: |
@ -26,9 +42,9 @@ jobs:
GOARCH=$arch ./build_linux.sh GOARCH=$arch ./build_linux.sh
rm bin/* rm bin/*
done done
test-linux: test-linux:
name: Run tests on Linux amd64 name: Run tests on Linux amd64
needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install kernel module - name: Install kernel module
@ -39,14 +55,14 @@ jobs:
run: sudo apt-get install nftables run: sudo apt-get install nftables
- name: setup go - name: setup go
uses: actions/setup-go@v2 uses: actions/setup-go@v4
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
- name: Set up Go for root - name: Set up Go for root
run: | run: |
sudo ln -sf `which go` `sudo which go` || true sudo ln -sf `which go` `sudo which go` || true
sudo go version sudo go version
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install test binaries - name: Install test binaries
env: env:
@ -66,15 +82,15 @@ jobs:
PATH=$PATH:$(go env GOPATH)/bin PATH=$PATH:$(go env GOPATH)/bin
gover gover
goveralls -coverprofile=gover.coverprofile -service=github goveralls -coverprofile=gover.coverprofile -service=github
test-win: test-win:
name: Build and run tests on Windows name: Build and run tests on Windows
needs: build
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- name: setup go - name: setup go
uses: actions/setup-go@v2 uses: actions/setup-go@v4
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: test - name: test
run: bash ./test_windows.sh run: bash ./test_windows.sh

42
.golangci.yml Normal file
View File

@ -0,0 +1,42 @@
issues:
exclude-rules:
- linters:
- revive
text: "don't use ALL_CAPS in Go names; use CamelCase"
- linters:
- revive
text: " and that stutters;"
linters:
disable:
- errcheck
enable:
- contextcheck
- durationcheck
- gci
- ginkgolinter
- gocritic
- gofumpt
- gosimple
- govet
- ineffassign
- misspell
- nonamedreturns
- predeclared
- revive
- staticcheck
- unconvert
- unparam
- unused
- wastedassign
linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/containernetworking)
run:
skip-dirs:
- vendor

12
.yamllint.yml Normal file
View File

@ -0,0 +1,12 @@
extends: default
ignore: |
vendor
rules:
document-start: disable
line-length: disable
truthy:
ignore: |
.github/workflows/*.yml
.github/workflows/*.yaml

View File

@ -7,3 +7,4 @@ This is the official list of the CNI network plugins owners:
- Matt Dupre <matt@tigera.io> (@matthewdupre) - Matt Dupre <matt@tigera.io> (@matthewdupre)
- Michael Cambria <mcambria@redhat.com> (@mccv1r0) - Michael Cambria <mcambria@redhat.com> (@mccv1r0)
- Piotr Skarmuk <piotr.skarmuk@gmail.com> (@jellonek) - Piotr Skarmuk <piotr.skarmuk@gmail.com> (@jellonek)
- Michael Zappa <michael.zappa@gmail.com> (@MikeZappa87)

View File

@ -14,13 +14,14 @@ Read [CONTRIBUTING](CONTRIBUTING.md) for build and test instructions.
* `ptp`: Creates a veth pair. * `ptp`: Creates a veth pair.
* `vlan`: Allocates a vlan device. * `vlan`: Allocates a vlan device.
* `host-device`: Move an already-existing device into a container. * `host-device`: Move an already-existing device into a container.
* `dummy`: Creates a new Dummy device in the container.
#### Windows: Windows specific #### Windows: Windows specific
* `win-bridge`: Creates a bridge, adds the host and the container to it. * `win-bridge`: Creates a bridge, adds the host and the container to it.
* `win-overlay`: Creates an overlay interface to the container. * `win-overlay`: Creates an overlay interface to the container.
### IPAM: IP address allocation ### IPAM: IP address allocation
* `dhcp`: Runs a daemon on the host to make DHCP requests on behalf of the container * `dhcp`: Runs a daemon on the host to make DHCP requests on behalf of the container
* `host-local`: Maintains a local database of allocated IPs * `host-local`: Maintains a local database of allocated IPs
* `static`: Allocate a static IPv4/IPv6 addresses to container and it's useful in debugging purpose. * `static`: Allocate a single static IPv4/IPv6 address to container. It's useful in debugging purpose.
### Meta: other plugins ### Meta: other plugins
* `tuning`: Tweaks sysctl parameters of an existing interface * `tuning`: Tweaks sysctl parameters of an existing interface

52
go.mod
View File

@ -1,40 +1,44 @@
module github.com/containernetworking/plugins module github.com/containernetworking/plugins
go 1.17 go 1.20
require ( require (
github.com/Microsoft/hcsshim v0.8.20 github.com/Microsoft/hcsshim v0.9.9
github.com/alexflint/go-filemutex v1.1.0 github.com/alexflint/go-filemutex v1.2.0
github.com/buger/jsonparser v1.1.1 github.com/buger/jsonparser v1.1.1
github.com/containernetworking/cni v1.0.1 github.com/containernetworking/cni v1.1.2
github.com/coreos/go-iptables v0.6.0 github.com/coreos/go-iptables v0.6.0
github.com/coreos/go-systemd/v22 v22.3.2 github.com/coreos/go-systemd/v22 v22.5.0
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c
github.com/d2g/dhcp4client v1.0.0 github.com/d2g/dhcp4client v1.0.0
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5 github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5
github.com/godbus/dbus/v5 v5.0.4 github.com/godbus/dbus/v5 v5.1.0
github.com/mattn/go-shellwords v1.0.12 github.com/mattn/go-shellwords v1.0.12
github.com/networkplumbing/go-nft v0.2.0 github.com/networkplumbing/go-nft v0.3.0
github.com/onsi/ginkgo v1.16.4 github.com/onsi/ginkgo/v2 v2.9.2
github.com/onsi/gomega v1.15.0 github.com/onsi/gomega v1.27.6
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1 github.com/opencontainers/selinux v1.11.0
github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 github.com/safchain/ethtool v0.3.0
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e github.com/vishvananda/netlink v1.2.1-beta.2
golang.org/x/sys v0.7.0
) )
require ( require (
github.com/Microsoft/go-winio v0.4.17 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/containerd/cgroups v1.0.1 // indirect github.com/containerd/cgroups v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-logr/logr v1.2.4 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/nxadm/tail v1.4.8 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.9.0 // indirect
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect github.com/vishvananda/netns v0.0.4 // indirect
go.opencensus.io v0.22.3 // indirect go.opencensus.io v0.24.0 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect golang.org/x/mod v0.9.0 // indirect
golang.org/x/text v0.3.6 // indirect golang.org/x/net v0.8.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect golang.org/x/text v0.8.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect golang.org/x/tools v0.7.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

206
go.sum
View File

@ -10,6 +10,7 @@ cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6T
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -43,8 +44,9 @@ github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w=
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
@ -52,13 +54,16 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.20 h1:ZTwcx3NS8n07kPf/JZ1qwU6vnjhVPMUWlXBF8r9UxrE= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.9.9 h1:FYrTiCNOc8ZddNBVkJBxWZYm22rgxHFmxMoGK66sDF0=
github.com/Microsoft/hcsshim v0.9.9/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -66,8 +71,9 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
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/alexflint/go-filemutex v1.1.0 h1:IAWuUuRYL2hETx5b8vCgwnD+xSdlsTQY6s2JjBsqLdg= github.com/alexflint/go-filemutex v1.2.0 h1:1v0TJPDtlhgpW4nJ+GvxCLSlUDC3+gW0CQQvlmfDR/s=
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= github.com/alexflint/go-filemutex v1.2.0/go.mod h1:mYyQSWvw9Tx2/H2n9qXPb52tTYfE0pZAWcBq5mK025c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
@ -77,6 +83,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
@ -87,10 +94,12 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -98,8 +107,11 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
@ -114,8 +126,9 @@ github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1
github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ=
github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
@ -134,6 +147,7 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@ -161,11 +175,13 @@ github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJ
github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
@ -178,8 +194,8 @@ github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNR
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v1.0.1 h1:9OIL/sZmMYDBe+G8svzILAlulUpaDTUjeAbtH/JNLBo= github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y= github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
@ -196,17 +212,18 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c h1:Xo2rK1pzOm0jO6abTPIQwbAmqBIOj132otexc1mmzFc= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c h1:Xo2rK1pzOm0jO6abTPIQwbAmqBIOj132otexc1mmzFc=
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
@ -224,9 +241,13 @@ github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
@ -243,13 +264,14 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
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/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
@ -265,22 +287,30 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
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/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -295,13 +325,16 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
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.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -317,8 +350,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -328,8 +361,13 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@ -338,6 +376,10 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk=
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -349,6 +391,7 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -358,6 +401,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
@ -367,14 +411,17 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -395,13 +442,15 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
@ -410,10 +459,12 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@ -428,37 +479,45 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/networkplumbing/go-nft v0.2.0 h1:eKapmyVUt/3VGfhYaDos5yeprm+LPt881UeksmKKZHY= github.com/networkplumbing/go-nft v0.3.0 h1:IIc6yHjN85KyJx21p3ZEsO0iBMYHNXux22rc9Q8TfFw=
github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs= github.com/networkplumbing/go-nft v0.3.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
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.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
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/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
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.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -471,14 +530,19 @@ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59P
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@ -520,13 +584,14 @@ github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
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/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1 h1:ZFfeKAhIQiiOrQaI3/znw0gOmYpO28Tcu1YaqMa/jtQ= github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
@ -536,8 +601,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@ -560,14 +626,19 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+
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=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@ -582,13 +653,13 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs=
github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@ -605,13 +676,16 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@ -660,6 +734,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -677,6 +753,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -688,16 +765,20 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
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/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -709,10 +790,12 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -731,6 +814,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -757,7 +841,7 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/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=
@ -765,6 +849,7 @@ golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/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-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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=
@ -776,9 +861,14 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -786,15 +876,18 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -810,6 +903,7 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -828,10 +922,17 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -847,11 +948,13 @@ google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -873,7 +976,10 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@ -887,8 +993,12 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 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-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 v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -900,15 +1010,17 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
@ -919,19 +1031,19 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
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.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
@ -953,6 +1065,7 @@ k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0=
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
@ -961,8 +1074,12 @@ k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
@ -971,6 +1088,7 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@ -14,21 +14,20 @@
package integration_test package integration_test
import ( import (
"bytes"
"fmt" "fmt"
"io"
"math/rand" "math/rand"
"net"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"bytes"
"io"
"net"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"time" "time"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec" "github.com/onsi/gomega/gexec"
@ -148,8 +147,8 @@ var _ = Describe("Basic PTP using cnitool", func() {
basicBridgeEnv.runInNS(hostNS, cnitoolBin, "del", "network-chain-test", contNS2.LongName()) basicBridgeEnv.runInNS(hostNS, cnitoolBin, "del", "network-chain-test", contNS2.LongName())
}) })
Measure("limits traffic only on the restricted bandwith veth device", func(b Benchmarker) { Measure("limits traffic only on the restricted bandwidth veth device", func(b Benchmarker) {
ipRegexp := regexp.MustCompile("10\\.1[12]\\.2\\.\\d{1,3}") ipRegexp := regexp.MustCompile(`10\.1[12]\.2\.\d{1,3}`)
By(fmt.Sprintf("adding %s to %s\n\n", "chained-bridge-bandwidth", contNS1.ShortName())) By(fmt.Sprintf("adding %s to %s\n\n", "chained-bridge-bandwidth", contNS1.ShortName()))
chainedBridgeBandwidthEnv.runInNS(hostNS, cnitoolBin, "add", "network-chain-test", contNS1.LongName()) chainedBridgeBandwidthEnv.runInNS(hostNS, cnitoolBin, "add", "network-chain-test", contNS1.LongName())
@ -162,27 +161,24 @@ var _ = Describe("Basic PTP using cnitool", func() {
Expect(basicBridgeIP).To(ContainSubstring("10.11.2.")) Expect(basicBridgeIP).To(ContainSubstring("10.11.2."))
var chainedBridgeBandwidthPort, basicBridgePort int var chainedBridgeBandwidthPort, basicBridgePort int
var err error
By(fmt.Sprintf("starting echo server in %s\n\n", contNS1.ShortName())) By(fmt.Sprintf("starting echo server in %s\n\n", contNS1.ShortName()))
chainedBridgeBandwidthPort, chainedBridgeBandwidthSession, err = startEchoServerInNamespace(contNS1) chainedBridgeBandwidthPort, chainedBridgeBandwidthSession = startEchoServerInNamespace(contNS1)
Expect(err).ToNot(HaveOccurred())
By(fmt.Sprintf("starting echo server in %s\n\n", contNS2.ShortName())) By(fmt.Sprintf("starting echo server in %s\n\n", contNS2.ShortName()))
basicBridgePort, basicBridgeSession, err = startEchoServerInNamespace(contNS2) basicBridgePort, basicBridgeSession = startEchoServerInNamespace(contNS2)
Expect(err).ToNot(HaveOccurred())
packetInBytes := 20000 // The shaper needs to 'warm'. Send enough to cause it to throttle, packetInBytes := 20000 // The shaper needs to 'warm'. Send enough to cause it to throttle,
// balanced by run time. // balanced by run time.
By(fmt.Sprintf("sending tcp traffic to the chained, bridged, traffic shaped container on ip address '%s:%d'\n\n", chainedBridgeIP, chainedBridgeBandwidthPort)) By(fmt.Sprintf("sending tcp traffic to the chained, bridged, traffic shaped container on ip address '%s:%d'\n\n", chainedBridgeIP, chainedBridgeBandwidthPort))
runtimeWithLimit := b.Time("with chained bridge and bandwidth plugins", func() { runtimeWithLimit := b.Time("with chained bridge and bandwidth plugins", func() {
makeTcpClientInNS(hostNS.ShortName(), chainedBridgeIP, chainedBridgeBandwidthPort, packetInBytes) makeTCPClientInNS(hostNS.ShortName(), chainedBridgeIP, chainedBridgeBandwidthPort, packetInBytes)
}) })
By(fmt.Sprintf("sending tcp traffic to the basic bridged container on ip address '%s:%d'\n\n", basicBridgeIP, basicBridgePort)) By(fmt.Sprintf("sending tcp traffic to the basic bridged container on ip address '%s:%d'\n\n", basicBridgeIP, basicBridgePort))
runtimeWithoutLimit := b.Time("with basic bridged plugin", func() { runtimeWithoutLimit := b.Time("with basic bridged plugin", func() {
makeTcpClientInNS(hostNS.ShortName(), basicBridgeIP, basicBridgePort, packetInBytes) makeTCPClientInNS(hostNS.ShortName(), basicBridgeIP, basicBridgePort, packetInBytes)
}) })
Expect(runtimeWithLimit).To(BeNumerically(">", runtimeWithoutLimit+1000*time.Millisecond)) Expect(runtimeWithLimit).To(BeNumerically(">", runtimeWithoutLimit+1000*time.Millisecond))
@ -224,7 +220,7 @@ func (n Namespace) Del() {
(TestEnv{}).run("ip", "netns", "del", string(n)) (TestEnv{}).run("ip", "netns", "del", string(n))
} }
func makeTcpClientInNS(netns string, address string, port int, numBytes int) { func makeTCPClientInNS(netns string, address string, port int, numBytes int) {
payload := bytes.Repeat([]byte{'a'}, numBytes) payload := bytes.Repeat([]byte{'a'}, numBytes)
message := string(payload) message := string(payload)
@ -243,7 +239,7 @@ func makeTcpClientInNS(netns string, address string, port int, numBytes int) {
Expect(string(out)).To(Equal(message)) Expect(string(out)).To(Equal(message))
} }
func startEchoServerInNamespace(netNS Namespace) (int, *gexec.Session, error) { func startEchoServerInNamespace(netNS Namespace) (int, *gexec.Session) {
session, err := startInNetNS(echoServerBinaryPath, netNS) session, err := startInNetNS(echoServerBinaryPath, netNS)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -260,7 +256,7 @@ func startEchoServerInNamespace(netNS Namespace) (int, *gexec.Session, error) {
io.Copy(GinkgoWriter, io.MultiReader(session.Out, session.Err)) io.Copy(GinkgoWriter, io.MultiReader(session.Out, session.Err))
}() }()
return port, session, nil return port, session
} }
func startInNetNS(binPath string, namespace Namespace) (*gexec.Session, error) { func startInNetNS(binPath string, namespace Namespace) (*gexec.Session, error) {

View File

@ -17,7 +17,7 @@ import (
"strings" "strings"
"testing" "testing"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec" "github.com/onsi/gomega/gexec"
) )

View File

@ -39,6 +39,7 @@ type EndpointInfo struct {
NetworkId string NetworkId string
Gateway net.IP Gateway net.IP
IpAddress net.IP IpAddress net.IP
MacAddress string
} }
// GetSandboxContainerID returns the sandbox ID of this pod. // GetSandboxContainerID returns the sandbox ID of this pod.
@ -248,6 +249,7 @@ func GenerateHcnEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcn.HostComputeEndp
Minor: 0, Minor: 0,
}, },
Name: epInfo.EndpointName, Name: epInfo.EndpointName,
MacAddress: epInfo.MacAddress,
HostComputeNetwork: epInfo.NetworkId, HostComputeNetwork: epInfo.NetworkId,
Dns: hcn.Dns{ Dns: hcn.Dns{
Domain: epInfo.DNS.Domain, Domain: epInfo.DNS.Domain,
@ -280,6 +282,16 @@ func RemoveHcnEndpoint(epName string) error {
} }
return errors.Annotatef(err, "failed to find HostComputeEndpoint %s", epName) return errors.Annotatef(err, "failed to find HostComputeEndpoint %s", epName)
} }
epNamespace, err := hcn.GetNamespaceByID(hcnEndpoint.HostComputeNamespace)
if err != nil && !hcn.IsNotFoundError(err) {
return errors.Annotatef(err, "failed to get HostComputeNamespace %s", epName)
}
if epNamespace != nil {
err = hcn.RemoveNamespaceEndpoint(hcnEndpoint.HostComputeNamespace, hcnEndpoint.Id)
if err != nil && !hcn.IsNotFoundError(err) {
return errors.Annotatef(err,"error removing endpoint: %s from namespace", epName)
}
}
err = hcnEndpoint.Delete() err = hcnEndpoint.Delete()
if err != nil { if err != nil {

View File

@ -14,7 +14,7 @@
package hns package hns
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"testing" "testing"

View File

@ -18,7 +18,7 @@ import (
"net" "net"
"github.com/Microsoft/hcsshim/hcn" "github.com/Microsoft/hcsshim/hcn"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )

View File

@ -19,43 +19,87 @@ import (
"net" "net"
) )
// NextIP returns IP incremented by 1 // NextIP returns IP incremented by 1, if IP is invalid, return nil
func NextIP(ip net.IP) net.IP { func NextIP(ip net.IP) net.IP {
i := ipToInt(ip) normalizedIP := normalizeIP(ip)
return intToIP(i.Add(i, big.NewInt(1))) if normalizedIP == nil {
return nil
}
i := ipToInt(normalizedIP)
return intToIP(i.Add(i, big.NewInt(1)), len(normalizedIP) == net.IPv6len)
} }
// PrevIP returns IP decremented by 1 // PrevIP returns IP decremented by 1, if IP is invalid, return nil
func PrevIP(ip net.IP) net.IP { func PrevIP(ip net.IP) net.IP {
i := ipToInt(ip) normalizedIP := normalizeIP(ip)
return intToIP(i.Sub(i, big.NewInt(1))) if normalizedIP == nil {
return nil
}
i := ipToInt(normalizedIP)
return intToIP(i.Sub(i, big.NewInt(1)), len(normalizedIP) == net.IPv6len)
} }
// Cmp compares two IPs, returning the usual ordering: // Cmp compares two IPs, returning the usual ordering:
// a < b : -1 // a < b : -1
// a == b : 0 // a == b : 0
// a > b : 1 // a > b : 1
// incomparable : -2
func Cmp(a, b net.IP) int { func Cmp(a, b net.IP) int {
aa := ipToInt(a) normalizedA := normalizeIP(a)
bb := ipToInt(b) normalizedB := normalizeIP(b)
return aa.Cmp(bb)
if len(normalizedA) == len(normalizedB) && len(normalizedA) != 0 {
return ipToInt(normalizedA).Cmp(ipToInt(normalizedB))
}
return -2
} }
func ipToInt(ip net.IP) *big.Int { func ipToInt(ip net.IP) *big.Int {
if v := ip.To4(); v != nil { return big.NewInt(0).SetBytes(ip)
return big.NewInt(0).SetBytes(v) }
func intToIP(i *big.Int, isIPv6 bool) net.IP {
intBytes := i.Bytes()
if len(intBytes) == net.IPv4len || len(intBytes) == net.IPv6len {
return intBytes
} }
return big.NewInt(0).SetBytes(ip.To16())
if isIPv6 {
return append(make([]byte, net.IPv6len-len(intBytes)), intBytes...)
}
return append(make([]byte, net.IPv4len-len(intBytes)), intBytes...)
} }
func intToIP(i *big.Int) net.IP { // normalizeIP will normalize IP by family,
return net.IP(i.Bytes()) // IPv4 : 4-byte form
// IPv6 : 16-byte form
// others : nil
func normalizeIP(ip net.IP) net.IP {
if ipTo4 := ip.To4(); ipTo4 != nil {
return ipTo4
}
return ip.To16()
} }
// Network masks off the host portion of the IP // Network masks off the host portion of the IP, if IPNet is invalid,
// return nil
func Network(ipn *net.IPNet) *net.IPNet { func Network(ipn *net.IPNet) *net.IPNet {
if ipn == nil {
return nil
}
maskedIP := ipn.IP.Mask(ipn.Mask)
if maskedIP == nil {
return nil
}
return &net.IPNet{ return &net.IPNet{
IP: ipn.IP.Mask(ipn.Mask), IP: maskedIP,
Mask: ipn.Mask, Mask: ipn.Mask,
} }
} }

247
pkg/ip/cidr_test.go Normal file
View File

@ -0,0 +1,247 @@
// Copyright 2022 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 ip
import (
"net"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("CIDR functions", func() {
It("NextIP", func() {
testCases := []struct {
ip net.IP
nextIP net.IP
}{
{
[]byte{192, 0, 2},
nil,
},
{
net.ParseIP("192.168.0.1"),
net.IPv4(192, 168, 0, 2).To4(),
},
{
net.ParseIP("192.168.0.255"),
net.IPv4(192, 168, 1, 0).To4(),
},
{
net.ParseIP("0.1.0.5"),
net.IPv4(0, 1, 0, 6).To4(),
},
{
net.ParseIP("AB12::123"),
net.ParseIP("AB12::124"),
},
{
net.ParseIP("AB12::FFFF"),
net.ParseIP("AB12::1:0"),
},
{
net.ParseIP("0::123"),
net.ParseIP("0::124"),
},
}
for _, test := range testCases {
ip := NextIP(test.ip)
Expect(ip).To(Equal(test.nextIP))
}
})
It("PrevIP", func() {
testCases := []struct {
ip net.IP
prevIP net.IP
}{
{
[]byte{192, 0, 2},
nil,
},
{
net.ParseIP("192.168.0.2"),
net.IPv4(192, 168, 0, 1).To4(),
},
{
net.ParseIP("192.168.1.0"),
net.IPv4(192, 168, 0, 255).To4(),
},
{
net.ParseIP("0.1.0.5"),
net.IPv4(0, 1, 0, 4).To4(),
},
{
net.ParseIP("AB12::123"),
net.ParseIP("AB12::122"),
},
{
net.ParseIP("AB12::1:0"),
net.ParseIP("AB12::FFFF"),
},
{
net.ParseIP("0::124"),
net.ParseIP("0::123"),
},
}
for _, test := range testCases {
ip := PrevIP(test.ip)
Expect(ip).To(Equal(test.prevIP))
}
})
It("Cmp", func() {
testCases := []struct {
a net.IP
b net.IP
result int
}{
{
net.ParseIP("192.168.0.2"),
nil,
-2,
},
{
net.ParseIP("192.168.0.2"),
[]byte{192, 168, 5},
-2,
},
{
net.ParseIP("192.168.0.2"),
net.ParseIP("AB12::123"),
-2,
},
{
net.ParseIP("192.168.0.2"),
net.ParseIP("192.168.0.5"),
-1,
},
{
net.ParseIP("192.168.0.2"),
net.ParseIP("192.168.0.5").To4(),
-1,
},
{
net.ParseIP("192.168.0.10"),
net.ParseIP("192.168.0.5"),
1,
},
{
net.ParseIP("192.168.0.10"),
net.ParseIP("192.168.0.10"),
0,
},
{
net.ParseIP("192.168.0.10"),
net.ParseIP("192.168.0.10").To4(),
0,
},
{
net.ParseIP("AB12::122"),
net.ParseIP("AB12::123"),
-1,
},
{
net.ParseIP("AB12::210"),
net.ParseIP("AB12::123"),
1,
},
{
net.ParseIP("AB12::210"),
net.ParseIP("AB12::210"),
0,
},
}
for _, test := range testCases {
result := Cmp(test.a, test.b)
Expect(result).To(Equal(test.result))
}
})
It("Network", func() {
testCases := []struct {
ipNet *net.IPNet
result *net.IPNet
}{
{
nil,
nil,
},
{
&net.IPNet{
IP: nil,
Mask: net.IPv4Mask(255, 255, 255, 0),
},
nil,
},
{
&net.IPNet{
IP: net.IPv4(192, 168, 0, 1),
Mask: nil,
},
nil,
},
{
&net.IPNet{
IP: net.ParseIP("AB12::123"),
Mask: net.IPv4Mask(255, 255, 255, 0),
},
nil,
},
{
&net.IPNet{
IP: net.IPv4(192, 168, 0, 100).To4(),
Mask: net.CIDRMask(120, 128),
},
&net.IPNet{
IP: net.IPv4(192, 168, 0, 0).To4(),
Mask: net.CIDRMask(120, 128),
},
},
{
&net.IPNet{
IP: net.IPv4(192, 168, 0, 100),
Mask: net.CIDRMask(24, 32),
},
&net.IPNet{
IP: net.IPv4(192, 168, 0, 0).To4(),
Mask: net.CIDRMask(24, 32),
},
},
{
&net.IPNet{
IP: net.ParseIP("AB12::123"),
Mask: net.CIDRMask(120, 128),
},
&net.IPNet{
IP: net.ParseIP("AB12::100"),
Mask: net.CIDRMask(120, 128),
},
},
}
for _, test := range testCases {
result := Network(test.ipNet)
Expect(result).To(Equal(test.result))
}
})
})

View File

@ -47,13 +47,12 @@ func ParseIP(s string) *IP {
return nil return nil
} }
return newIP(ip, ipNet.Mask) return newIP(ip, ipNet.Mask)
} else { }
ip := net.ParseIP(s) ip := net.ParseIP(s)
if ip == nil { if ip == nil {
return nil return nil
} }
return newIP(ip, nil) return newIP(ip, nil)
}
} }
// ToIP will return a net.IP in standard form from this IP. // ToIP will return a net.IP in standard form from this IP.

View File

@ -15,10 +15,10 @@
package ip_test package ip_test
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestIp(t *testing.T) { func TestIp(t *testing.T) {

View File

@ -19,7 +19,7 @@ import (
"fmt" "fmt"
"net" "net"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
@ -124,7 +124,7 @@ var _ = Describe("IP Operations", func() {
} }
for _, test := range testCases { for _, test := range testCases {
Expect(len(test.ip.ToIP())).To(Equal(test.expectedLen)) Expect(test.ip.ToIP()).To(HaveLen(test.expectedLen))
Expect(test.ip.ToIP()).To(Equal(test.expectedIP)) Expect(test.ip.ToIP()).To(Equal(test.expectedIP))
} }
}) })
@ -174,8 +174,8 @@ var _ = Describe("IP Operations", func() {
} }
}) })
It("Decode", func() { Context("Decode", func() {
Context("valid IP", func() { It("valid IP", func() {
testCases := []struct { testCases := []struct {
text string text string
expected *IP expected *IP
@ -205,10 +205,9 @@ var _ = Describe("IP Operations", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(ip).To(Equal(test.expected)) Expect(ip).To(Equal(test.expected))
} }
}) })
Context("empty text", func() { It("empty text", func() {
ip := &IP{} ip := &IP{}
err := json.Unmarshal([]byte(`""`), ip) err := json.Unmarshal([]byte(`""`), ip)
@ -216,7 +215,7 @@ var _ = Describe("IP Operations", func() {
Expect(ip).To(Equal(newIP(nil, nil))) Expect(ip).To(Equal(newIP(nil, nil)))
}) })
Context("invalid IP", func() { It("invalid IP", func() {
testCases := []struct { testCases := []struct {
text string text string
expectedErr error expectedErr error
@ -243,7 +242,7 @@ var _ = Describe("IP Operations", func() {
} }
}) })
Context("IP slice", func() { It("IP slice", func() {
testCases := []struct { testCases := []struct {
text string text string
expected []*IP expected []*IP

View File

@ -16,7 +16,7 @@ package ip
import ( import (
"bytes" "bytes"
"io/ioutil" "os"
current "github.com/containernetworking/cni/pkg/types/100" current "github.com/containernetworking/cni/pkg/types/100"
) )
@ -53,10 +53,10 @@ func EnableForward(ips []*current.IPConfig) error {
} }
func echo1(f string) error { func echo1(f string) error {
if content, err := ioutil.ReadFile(f); err == nil { if content, err := os.ReadFile(f); err == nil {
if bytes.Equal(bytes.TrimSpace(content), []byte("1")) { if bytes.Equal(bytes.TrimSpace(content), []byte("1")) {
return nil return nil
} }
} }
return ioutil.WriteFile(f, []byte("1"), 0644) return os.WriteFile(f, []byte("1"), 0o644)
} }

View File

@ -1,17 +1,16 @@
package ip package ip
import ( import (
"io/ioutil"
"os" "os"
"time" "time"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("IpforwardLinux", func() { var _ = Describe("IpforwardLinux", func() {
It("echo1 must not write the file if content is 1", func() { It("echo1 must not write the file if content is 1", func() {
file, err := ioutil.TempFile(os.TempDir(), "containernetworking") file, err := os.CreateTemp("", "containernetworking")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
defer os.Remove(file.Name()) defer os.Remove(file.Name())
err = echo1(file.Name()) err = echo1(file.Name())

View File

@ -104,7 +104,6 @@ func TeardownIPMasq(ipn *net.IPNet, chain string, comment string) error {
err = ipt.ClearChain("nat", chain) err = ipt.ClearChain("nat", chain)
if err != nil && !isNotExist(err) { if err != nil && !isNotExist(err) {
return err return err
} }
err = ipt.DeleteChain("nat", chain) err = ipt.DeleteChain("nat", chain)

View File

@ -28,9 +28,7 @@ import (
"github.com/containernetworking/plugins/pkg/utils/sysctl" "github.com/containernetworking/plugins/pkg/utils/sysctl"
) )
var ( var ErrLinkNotFound = errors.New("link not found")
ErrLinkNotFound = errors.New("link not found")
)
// makeVethPair is called from within the container's network namespace // makeVethPair is called from within the container's network namespace
func makeVethPair(name, peer string, mtu int, mac string, hostNS ns.NetNS) (netlink.Link, error) { func makeVethPair(name, peer string, mtu int, mac string, hostNS ns.NetNS) (netlink.Link, error) {
@ -69,38 +67,37 @@ func peerExists(name string) bool {
return true return true
} }
func makeVeth(name, vethPeerName string, mtu int, mac string, hostNS ns.NetNS) (peerName string, veth netlink.Link, err error) { func makeVeth(name, vethPeerName string, mtu int, mac string, hostNS ns.NetNS) (string, netlink.Link, error) {
var peerName string
var veth netlink.Link
var err error
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
if vethPeerName != "" { if vethPeerName != "" {
peerName = vethPeerName peerName = vethPeerName
} else { } else {
peerName, err = RandomVethName() peerName, err = RandomVethName()
if err != nil { if err != nil {
return return peerName, nil, err
} }
} }
veth, err = makeVethPair(name, peerName, mtu, mac, hostNS) veth, err = makeVethPair(name, peerName, mtu, mac, hostNS)
switch { switch {
case err == nil: case err == nil:
return return peerName, veth, nil
case os.IsExist(err): case os.IsExist(err):
if peerExists(peerName) && vethPeerName == "" { if peerExists(peerName) && vethPeerName == "" {
continue continue
} }
err = fmt.Errorf("container veth name provided (%v) already exists", name) return peerName, veth, fmt.Errorf("container veth name provided (%v) already exists", name)
return
default: default:
err = fmt.Errorf("failed to make veth pair: %v", err) return peerName, veth, fmt.Errorf("failed to make veth pair: %v", err)
return
} }
} }
// should really never be hit // should really never be hit
err = fmt.Errorf("failed to find a unique veth name") return peerName, nil, fmt.Errorf("failed to find a unique veth name")
return
} }
// RandomVethName returns string "veth" with random prefix (hashed from entropy) // RandomVethName returns string "veth" with random prefix (hashed from entropy)

View File

@ -20,22 +20,15 @@ import (
"fmt" "fmt"
"net" "net"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"github.com/containernetworking/plugins/pkg/ip" "github.com/containernetworking/plugins/pkg/ip"
"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/vishvananda/netlink"
) )
func getHwAddr(linkname string) string {
veth, err := netlink.LinkByName(linkname)
Expect(err).NotTo(HaveOccurred())
return fmt.Sprintf("%s", veth.Attrs().HardwareAddr)
}
var _ = Describe("Link", func() { var _ = Describe("Link", func() {
const ( const (
ifaceFormatString string = "i%d" ifaceFormatString string = "i%d"
@ -64,7 +57,7 @@ var _ = Describe("Link", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
fakeBytes := make([]byte, 20) fakeBytes := make([]byte, 20)
//to be reset in AfterEach block // to be reset in AfterEach block
rand.Reader = bytes.NewReader(fakeBytes) rand.Reader = bytes.NewReader(fakeBytes)
_ = containerNetNS.Do(func(ns.NetNS) error { _ = containerNetNS.Do(func(ns.NetNS) error {
@ -181,7 +174,7 @@ var _ = Describe("Link", func() {
Context("when there is no name available for the host-side", func() { Context("when there is no name available for the host-side", func() {
BeforeEach(func() { BeforeEach(func() {
//adding different interface to container ns // adding different interface to container ns
containerVethName += "0" containerVethName += "0"
}) })
It("returns useful error", func() { It("returns useful error", func() {
@ -197,7 +190,7 @@ var _ = Describe("Link", func() {
Context("when there is no name conflict for the host or container interfaces", func() { Context("when there is no name conflict for the host or container interfaces", func() {
BeforeEach(func() { BeforeEach(func() {
//adding different interface to container and host ns // adding different interface to container and host ns
containerVethName += "0" containerVethName += "0"
rand.Reader = originalRandReader rand.Reader = originalRandReader
}) })
@ -211,7 +204,7 @@ var _ = Describe("Link", func() {
return nil return nil
}) })
//verify veths are in different namespaces // verify veths are in different namespaces
_ = containerNetNS.Do(func(ns.NetNS) error { _ = containerNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
@ -290,7 +283,7 @@ var _ = Describe("Link", func() {
// this will delete the host endpoint too // this will delete the host endpoint too
addr, err := ip.DelLinkByNameAddr(containerVethName) addr, err := ip.DelLinkByNameAddr(containerVethName)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(addr).To(HaveLen(0)) Expect(addr).To(BeEmpty())
return nil return nil
}) })
}) })

View File

@ -42,6 +42,11 @@ func AddHostRoute(ipn *net.IPNet, gw net.IP, dev netlink.Link) error {
// AddDefaultRoute sets the default route on the given gateway. // AddDefaultRoute sets the default route on the given gateway.
func AddDefaultRoute(gw net.IP, dev netlink.Link) error { func AddDefaultRoute(gw net.IP, dev netlink.Link) error {
_, defNet, _ := net.ParseCIDR("0.0.0.0/0") var defNet *net.IPNet
if gw.To4() != nil {
_, defNet, _ = net.ParseCIDR("0.0.0.0/0")
} else {
_, defNet, _ = net.ParseCIDR("::/0")
}
return AddRoute(defNet, gw, dev) return AddRoute(defNet, gw, dev)
} }

View File

@ -21,13 +21,13 @@ import (
"fmt" "fmt"
"net" "net"
"github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" current "github.com/containernetworking/cni/pkg/types/100"
"github.com/vishvananda/netlink"
) )
func ValidateExpectedInterfaceIPs(ifName string, resultIPs []*current.IPConfig) error { func ValidateExpectedInterfaceIPs(ifName string, resultIPs []*current.IPConfig) error {
// Ensure ips // Ensure ips
for _, ips := range resultIPs { for _, ips := range resultIPs {
ourAddr := netlink.Addr{IPNet: &ips.Address} ourAddr := netlink.Addr{IPNet: &ips.Address}
@ -49,12 +49,15 @@ func ValidateExpectedInterfaceIPs(ifName string, resultIPs []*current.IPConfig)
break break
} }
} }
if match == false { if !match {
return fmt.Errorf("Failed to match addr %v on interface %v", ourAddr, ifName) return fmt.Errorf("Failed to match addr %v on interface %v", ourAddr, ifName)
} }
// Convert the host/prefixlen to just prefix for route lookup. // Convert the host/prefixlen to just prefix for route lookup.
_, ourPrefix, err := net.ParseCIDR(ourAddr.String()) _, ourPrefix, err := net.ParseCIDR(ourAddr.String())
if err != nil {
return err
}
findGwy := &netlink.Route{Dst: ourPrefix} findGwy := &netlink.Route{Dst: ourPrefix}
routeFilter := netlink.RT_FILTER_DST routeFilter := netlink.RT_FILTER_DST
@ -77,11 +80,13 @@ func ValidateExpectedInterfaceIPs(ifName string, resultIPs []*current.IPConfig)
} }
func ValidateExpectedRoute(resultRoutes []*types.Route) error { func ValidateExpectedRoute(resultRoutes []*types.Route) error {
// Ensure that each static route in prevResults is found in the routing table // Ensure that each static route in prevResults is found in the routing table
for _, route := range resultRoutes { for _, route := range resultRoutes {
find := &netlink.Route{Dst: &route.Dst, Gw: route.GW} find := &netlink.Route{Dst: &route.Dst, Gw: route.GW}
routeFilter := netlink.RT_FILTER_DST | netlink.RT_FILTER_GW routeFilter := netlink.RT_FILTER_DST
if route.GW != nil {
routeFilter |= netlink.RT_FILTER_GW
}
var family int var family int
switch { switch {

View File

@ -16,6 +16,7 @@ package ipam
import ( import (
"context" "context"
"github.com/containernetworking/cni/pkg/invoke" "github.com/containernetworking/cni/pkg/invoke"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
) )

View File

@ -19,11 +19,11 @@ import (
"net" "net"
"os" "os"
"github.com/vishvananda/netlink"
current "github.com/containernetworking/cni/pkg/types/100" 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"
"github.com/vishvananda/netlink"
) )
const ( const (
@ -44,7 +44,7 @@ func ConfigureIface(ifName string, res *current.Result) error {
} }
var v4gw, v6gw net.IP var v4gw, v6gw net.IP
var has_enabled_ipv6 bool = false hasEnabledIpv6 := false
for _, ipc := range res.IPs { for _, ipc := range res.IPs {
if ipc.Interface == nil { if ipc.Interface == nil {
continue continue
@ -57,7 +57,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.Address.IP.To4() == nil { if !hasEnabledIpv6 && 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} {
@ -79,7 +79,7 @@ func ConfigureIface(ifName string, res *current.Result) error {
return fmt.Errorf("failed to enable IPv6 for interface %q (%s=%s): %v", iface, ipv6SysctlValueName, value, err) return fmt.Errorf("failed to enable IPv6 for interface %q (%s=%s): %v", iface, ipv6SysctlValueName, value, err)
} }
} }
has_enabled_ipv6 = true hasEnabledIpv6 = true
} }
addr := &netlink.Addr{IPNet: &ipc.Address, Label: ""} addr := &netlink.Addr{IPNet: &ipc.Address, Label: ""}

View File

@ -18,15 +18,14 @@ import (
"net" "net"
"syscall" "syscall"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" 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/vishvananda/netlink"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
) )
const LINK_NAME = "eth0" const LINK_NAME = "eth0"
@ -143,12 +142,12 @@ var _ = Describe("ConfigureIface", func() {
v4addrs, err := netlink.AddrList(link, syscall.AF_INET) v4addrs, err := netlink.AddrList(link, syscall.AF_INET)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(v4addrs)).To(Equal(1)) Expect(v4addrs).To(HaveLen(1))
Expect(ipNetEqual(v4addrs[0].IPNet, ipv4)).To(Equal(true)) Expect(ipNetEqual(v4addrs[0].IPNet, ipv4)).To(BeTrue())
v6addrs, err := netlink.AddrList(link, syscall.AF_INET6) v6addrs, err := netlink.AddrList(link, syscall.AF_INET6)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(v6addrs)).To(Equal(2)) Expect(v6addrs).To(HaveLen(2))
var found bool var found bool
for _, a := range v6addrs { for _, a := range v6addrs {
@ -157,7 +156,7 @@ var _ = Describe("ConfigureIface", func() {
break break
} }
} }
Expect(found).To(Equal(true)) Expect(found).To(BeTrue())
// Ensure the v4 route, v6 route, and subnet route // Ensure the v4 route, v6 route, and subnet route
routes, err := netlink.RouteList(link, 0) routes, err := netlink.RouteList(link, 0)
@ -177,8 +176,8 @@ var _ = Describe("ConfigureIface", func() {
break break
} }
} }
Expect(v4found).To(Equal(true)) Expect(v4found).To(BeTrue())
Expect(v6found).To(Equal(true)) Expect(v6found).To(BeTrue())
return nil return nil
}) })
@ -216,8 +215,8 @@ var _ = Describe("ConfigureIface", func() {
break break
} }
} }
Expect(v4found).To(Equal(true)) Expect(v4found).To(BeTrue())
Expect(v6found).To(Equal(true)) Expect(v6found).To(BeTrue())
return nil return nil
}) })

View File

@ -15,10 +15,10 @@
package ipam_test package ipam_test
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestIpam(t *testing.T) { func TestIpam(t *testing.T) {

View File

@ -17,7 +17,7 @@ package link_test
import ( import (
"testing" "testing"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )

View File

@ -15,8 +15,10 @@
package link package link
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"time"
"github.com/networkplumbing/go-nft/nft" "github.com/networkplumbing/go-nft/nft"
"github.com/networkplumbing/go-nft/nft/schema" "github.com/networkplumbing/go-nft/nft/schema"
@ -29,7 +31,7 @@ const (
type NftConfigurer interface { type NftConfigurer interface {
Apply(*nft.Config) error Apply(*nft.Config) error
Read() (*nft.Config, error) Read(filterCommands ...string) (*nft.Config, error)
} }
type SpoofChecker struct { type SpoofChecker struct {
@ -41,12 +43,15 @@ type SpoofChecker struct {
type defaultNftConfigurer struct{} type defaultNftConfigurer struct{}
func (_ defaultNftConfigurer) Apply(cfg *nft.Config) error { func (dnc defaultNftConfigurer) Apply(cfg *nft.Config) error {
return nft.ApplyConfig(cfg) return nft.ApplyConfig(cfg)
} }
func (_ defaultNftConfigurer) Read() (*nft.Config, error) { func (dnc defaultNftConfigurer) Read(filterCommands ...string) (*nft.Config, error) {
return nft.ReadConfig() const timeout = 55 * time.Second
ctxWithTimeout, cancelFunc := context.WithTimeout(context.Background(), timeout)
defer cancelFunc()
return nft.ReadConfigContext(ctxWithTimeout, filterCommands...)
} }
func NewSpoofChecker(iface, macAddress, refID string) *SpoofChecker { func NewSpoofChecker(iface, macAddress, refID string) *SpoofChecker {
@ -109,7 +114,7 @@ func (sc *SpoofChecker) Setup() error {
// interface is removed. // interface is removed.
func (sc *SpoofChecker) Teardown() error { func (sc *SpoofChecker) Teardown() error {
ifaceChain := sc.ifaceChain() ifaceChain := sc.ifaceChain()
currentConfig, ifaceMatchRuleErr := sc.configurer.Read() currentConfig, ifaceMatchRuleErr := sc.configurer.Read(listChainBridgeNatPrerouting()...)
if ifaceMatchRuleErr == nil { if ifaceMatchRuleErr == nil {
expectedRuleToFind := sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name) expectedRuleToFind := sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name)
// It is safer to exclude the statement matching, avoiding cases where a current statement includes // It is safer to exclude the statement matching, avoiding cases where a current statement includes
@ -195,12 +200,10 @@ func (sc *SpoofChecker) matchMacRule(chain string) *schema.Rule {
} }
func (sc *SpoofChecker) dropRule(chain string) *schema.Rule { func (sc *SpoofChecker) dropRule(chain string) *schema.Rule {
macRulesIndex := nft.NewRuleIndex()
return &schema.Rule{ return &schema.Rule{
Family: schema.FamilyBridge, Family: schema.FamilyBridge,
Table: natTableName, Table: natTableName,
Chain: chain, Chain: chain,
Index: macRulesIndex.Next(),
Expr: []schema.Statement{ Expr: []schema.Statement{
{Verdict: schema.Verdict{SimpleVerdict: schema.SimpleVerdict{Drop: true}}}, {Verdict: schema.Verdict{SimpleVerdict: schema.SimpleVerdict{Drop: true}}},
}, },
@ -208,7 +211,7 @@ func (sc *SpoofChecker) dropRule(chain string) *schema.Rule {
} }
} }
func (_ *SpoofChecker) baseChain() *schema.Chain { func (sc *SpoofChecker) baseChain() *schema.Chain {
chainPriority := -300 chainPriority := -300
return &schema.Chain{ return &schema.Chain{
Family: schema.FamilyBridge, Family: schema.FamilyBridge,
@ -230,7 +233,7 @@ func (sc *SpoofChecker) ifaceChain() *schema.Chain {
} }
} }
func (_ *SpoofChecker) macChain(ifaceChainName string) *schema.Chain { func (sc *SpoofChecker) macChain(ifaceChainName string) *schema.Chain {
macChainName := ifaceChainName + "-mac" macChainName := ifaceChainName + "-mac"
return &schema.Chain{ return &schema.Chain{
Family: schema.FamilyBridge, Family: schema.FamilyBridge,
@ -243,3 +246,7 @@ func ruleComment(id string) string {
const refIDPrefix = "macspoofchk-" const refIDPrefix = "macspoofchk-"
return refIDPrefix + id return refIDPrefix + id
} }
func listChainBridgeNatPrerouting() []string {
return []string{"chain", "bridge", natTableName, preRoutingBaseChainName}
}

View File

@ -16,9 +16,9 @@ package link_test
import ( import (
"fmt" "fmt"
"github.com/networkplumbing/go-nft/nft"
. "github.com/onsi/ginkgo" "github.com/networkplumbing/go-nft/nft"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/containernetworking/plugins/pkg/link" "github.com/containernetworking/plugins/pkg/link"
@ -116,10 +116,10 @@ var _ = Describe("spoofcheck", func() {
}) })
func assertExpectedRegularChainsDeletionInTeardownConfig(action configurerStub) { func assertExpectedRegularChainsDeletionInTeardownConfig(action configurerStub) {
deleteRegularChainRulesJsonConfig, err := action.applyConfig[1].ToJSON() deleteRegularChainRulesJSONConfig, err := action.applyConfig[1].ToJSON()
ExpectWithOffset(1, err).NotTo(HaveOccurred()) ExpectWithOffset(1, err).NotTo(HaveOccurred())
expectedDeleteRegularChainRulesJsonConfig := ` expectedDeleteRegularChainRulesJSONConfig := `
{"nftables": [ {"nftables": [
{"delete": {"chain": { {"delete": {"chain": {
"family": "bridge", "family": "bridge",
@ -133,14 +133,14 @@ func assertExpectedRegularChainsDeletionInTeardownConfig(action configurerStub)
}}} }}}
]}` ]}`
ExpectWithOffset(1, string(deleteRegularChainRulesJsonConfig)).To(MatchJSON(expectedDeleteRegularChainRulesJsonConfig)) ExpectWithOffset(1, string(deleteRegularChainRulesJSONConfig)).To(MatchJSON(expectedDeleteRegularChainRulesJSONConfig))
} }
func assertExpectedBaseChainRuleDeletionInTeardownConfig(action configurerStub) { func assertExpectedBaseChainRuleDeletionInTeardownConfig(action configurerStub) {
deleteBaseChainRuleJsonConfig, err := action.applyConfig[0].ToJSON() deleteBaseChainRuleJSONConfig, err := action.applyConfig[0].ToJSON()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
expectedDeleteIfaceMatchRuleJsonConfig := ` expectedDeleteIfaceMatchRuleJSONConfig := `
{"nftables": [ {"nftables": [
{"delete": {"rule": { {"delete": {"rule": {
"family": "bridge", "family": "bridge",
@ -157,7 +157,7 @@ func assertExpectedBaseChainRuleDeletionInTeardownConfig(action configurerStub)
"comment": "macspoofchk-container99-net1" "comment": "macspoofchk-container99-net1"
}}} }}}
]}` ]}`
Expect(string(deleteBaseChainRuleJsonConfig)).To(MatchJSON(expectedDeleteIfaceMatchRuleJsonConfig)) Expect(string(deleteBaseChainRuleJSONConfig)).To(MatchJSON(expectedDeleteIfaceMatchRuleJSONConfig))
} }
func rowConfigWithRulesOnly() string { func rowConfigWithRulesOnly() string {
@ -254,7 +254,6 @@ func assertExpectedRulesInSetupConfig(c configurerStub) {
"comment":"macspoofchk-container99-net1"}}, "comment":"macspoofchk-container99-net1"}},
{"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1-mac", {"rule":{"family":"bridge","table":"nat","chain":"cni-br-iface-container99-net1-mac",
"expr":[{"drop":null}], "expr":[{"drop":null}],
"index":0,
"comment":"macspoofchk-container99-net1"}} "comment":"macspoofchk-container99-net1"}}
]}` ]}`
ExpectWithOffset(1, string(jsonConfig)).To(MatchJSON(expectedConfig)) ExpectWithOffset(1, string(jsonConfig)).To(MatchJSON(expectedConfig))
@ -289,7 +288,7 @@ func (a *configurerStub) Apply(c *nft.Config) error {
return nil return nil
} }
func (a *configurerStub) Read() (*nft.Config, error) { func (a *configurerStub) Read(_ ...string) (*nft.Config, error) {
if a.failReadConfig { if a.failReadConfig {
return nil, fmt.Errorf(errorReadText) return nil, fmt.Errorf(errorReadText)
} }

View File

@ -17,16 +17,16 @@ package ns_test
import ( import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/containernetworking/plugins/pkg/ns" . "github.com/onsi/ginkgo/v2"
"github.com/containernetworking/plugins/pkg/testutils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"
) )
func getInodeCurNetNS() (uint64, error) { func getInodeCurNetNS() (uint64, error) {
@ -208,7 +208,7 @@ var _ = Describe("Linux namespace operations", func() {
}) })
It("fails when the path is not a namespace", func() { It("fails when the path is not a namespace", func() {
tempFile, err := ioutil.TempFile("", "nstest") tempFile, err := os.CreateTemp("", "nstest")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
defer tempFile.Close() defer tempFile.Close()
@ -262,7 +262,7 @@ var _ = Describe("Linux namespace operations", func() {
}) })
It("should refuse other paths", func() { It("should refuse other paths", func() {
tempFile, err := ioutil.TempFile("", "nstest") tempFile, err := os.CreateTemp("", "nstest")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
defer tempFile.Close() defer tempFile.Close()

View File

@ -15,18 +15,14 @@
package ns_test package ns_test
import ( import (
"math/rand"
"runtime" "runtime"
. "github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestNs(t *testing.T) { func TestNs(t *testing.T) {
rand.Seed(config.GinkgoConfig.RandomSeed)
runtime.LockOSThread() runtime.LockOSThread()
RegisterFailHandler(Fail) RegisterFailHandler(Fail)

View File

@ -21,7 +21,7 @@ type BadReader struct {
Error error Error error
} }
func (r *BadReader) Read(buffer []byte) (int, error) { func (r *BadReader) Read(_ []byte) (int, error) {
if r.Error != nil { if r.Error != nil {
return 0, r.Error return 0, r.Error
} }

View File

@ -15,7 +15,7 @@
package testutils package testutils
import ( import (
"io/ioutil" "io"
"os" "os"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
@ -52,7 +52,7 @@ func CmdAdd(cniNetns, cniContainerID, cniIfname string, conf []byte, f func() er
var out []byte var out []byte
if err == nil { if err == nil {
out, err = ioutil.ReadAll(r) out, err = io.ReadAll(r)
} }
os.Stdout = oldStdout os.Stdout = oldStdout
@ -81,7 +81,7 @@ func CmdAddWithArgs(args *skel.CmdArgs, f func() error) (types.Result, []byte, e
return CmdAdd(args.Netns, args.ContainerID, args.IfName, args.StdinData, f) return CmdAdd(args.Netns, args.ContainerID, args.IfName, args.StdinData, f)
} }
func CmdCheck(cniNetns, cniContainerID, cniIfname string, conf []byte, f func() error) error { func CmdCheck(cniNetns, cniContainerID, cniIfname string, f func() error) error {
os.Setenv("CNI_COMMAND", "CHECK") os.Setenv("CNI_COMMAND", "CHECK")
os.Setenv("CNI_PATH", os.Getenv("PATH")) os.Setenv("CNI_PATH", os.Getenv("PATH"))
os.Setenv("CNI_NETNS", cniNetns) os.Setenv("CNI_NETNS", cniNetns)
@ -93,7 +93,7 @@ func CmdCheck(cniNetns, cniContainerID, cniIfname string, conf []byte, f func()
} }
func CmdCheckWithArgs(args *skel.CmdArgs, f func() error) error { func CmdCheckWithArgs(args *skel.CmdArgs, f func() error) error {
return CmdCheck(args.Netns, args.ContainerID, args.IfName, args.StdinData, f) return CmdCheck(args.Netns, args.ContainerID, args.IfName, f)
} }
func CmdDel(cniNetns, cniContainerID, cniIfname string, f func() error) error { func CmdDel(cniNetns, cniContainerID, cniIfname string, f func() error) error {

View File

@ -16,7 +16,6 @@ package testutils
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"strings" "strings"
@ -28,7 +27,7 @@ import (
// an error if any occurs while creating/writing the file. It is the caller's // an error if any occurs while creating/writing the file. It is the caller's
// responsibility to remove the file. // responsibility to remove the file.
func TmpResolvConf(dnsConf types.DNS) (string, error) { func TmpResolvConf(dnsConf types.DNS) (string, error) {
f, err := ioutil.TempFile("", "cni_test_resolv.conf") f, err := os.CreateTemp("", "cni_test_resolv.conf")
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get temp file for CNI test resolv.conf: %v", err) return "", fmt.Errorf("failed to get temp file for CNI test resolv.conf: %v", err)
} }

View File

@ -2,12 +2,12 @@ package main_test
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"net" "net"
"os/exec" "os/exec"
"strings" "strings"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec" "github.com/onsi/gomega/gexec"
@ -74,7 +74,7 @@ var _ = Describe("Echosvr", func() {
defer conn.Close() defer conn.Close()
fmt.Fprintf(conn, "hello\n") fmt.Fprintf(conn, "hello\n")
Expect(ioutil.ReadAll(conn)).To(Equal([]byte("hello"))) Expect(io.ReadAll(conn)).To(Equal([]byte("hello")))
}) })
}) })
@ -86,7 +86,7 @@ var _ = Describe("Echosvr", func() {
It("connects successfully using echo client", func() { It("connects successfully using echo client", func() {
Eventually(session.Out).Should(gbytes.Say("\n")) Eventually(session.Out).Should(gbytes.Say("\n"))
serverAddress := strings.TrimSpace(string(session.Out.Contents())) serverAddress := strings.TrimSpace(string(session.Out.Contents()))
fmt.Println("Server address", string(serverAddress)) fmt.Println("Server address", serverAddress)
cmd := exec.Command(clientBinaryPath, "-target", serverAddress, "-message", "hello") cmd := exec.Command(clientBinaryPath, "-target", serverAddress, "-message", "hello")
clientSession, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) clientSession, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)

View File

@ -1,10 +1,10 @@
package main_test package main_test
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestEchosvr(t *testing.T) { func TestEchosvr(t *testing.T) {

View File

@ -1,6 +1,7 @@
// Echosvr is a simple TCP echo server // Echosvr is a simple TCP echo server
// //
// It prints its listen address on stdout // It prints its listen address on stdout
//
// 127.0.0.1:xxxxx // 127.0.0.1:xxxxx
// A test should wait for this line, parse it // A test should wait for this line, parse it
// and may then attempt to connect. // and may then attempt to connect.
@ -43,11 +44,13 @@ func main() {
// Start UDP server // Start UDP server
addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%s", port)) addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%s", port))
if err != nil { if err != nil {
log.Fatalf("Error from net.ResolveUDPAddr(): %s", err) log.Printf("Error from net.ResolveUDPAddr(): %s", err)
return
} }
sock, err := net.ListenUDP("udp", addr) sock, err := net.ListenUDP("udp", addr)
if err != nil { if err != nil {
log.Fatalf("Error from ListenUDP(): %s", err) log.Printf("Error from ListenUDP(): %s", err)
return
} }
defer sock.Close() defer sock.Close()
@ -55,10 +58,11 @@ func main() {
for { for {
n, addr, err := sock.ReadFrom(buffer) n, addr, err := sock.ReadFrom(buffer)
if err != nil { if err != nil {
log.Fatalf("Error from ReadFrom(): %s", err) log.Printf("Error from ReadFrom(): %s", err)
return
} }
sock.SetWriteDeadline(time.Now().Add(1 * time.Minute)) sock.SetWriteDeadline(time.Now().Add(1 * time.Minute))
n, err = sock.WriteTo(buffer[0:n], addr) _, err = sock.WriteTo(buffer[0:n], addr)
if err != nil { if err != nil {
return return
} }

View File

@ -24,8 +24,9 @@ import (
"sync" "sync"
"syscall" "syscall"
"github.com/containernetworking/plugins/pkg/ns"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/containernetworking/plugins/pkg/ns"
) )
func getNsRunDir() string { func getNsRunDir() string {
@ -49,7 +50,6 @@ func getNsRunDir() string {
// Creates a new persistent (bind-mounted) network namespace and returns an object // Creates a new persistent (bind-mounted) network namespace and returns an object
// representing that namespace, without switching to it. // representing that namespace, without switching to it.
func NewNS() (ns.NetNS, error) { func NewNS() (ns.NetNS, error) {
nsRunDir := getNsRunDir() nsRunDir := getNsRunDir()
b := make([]byte, 16) b := make([]byte, 16)
@ -61,7 +61,7 @@ func NewNS() (ns.NetNS, error) {
// Create the directory for mounting network namespaces // Create the directory for mounting network namespaces
// This needs to be a shared mountpoint in case it is mounted in to // This needs to be a shared mountpoint in case it is mounted in to
// other namespaces (containers) // other namespaces (containers)
err = os.MkdirAll(nsRunDir, 0755) err = os.MkdirAll(nsRunDir, 0o755)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -133,7 +133,6 @@ func InsertUnique(ipt *iptables.IPTables, table, chain string, prepend bool, rul
if prepend { if prepend {
return ipt.Insert(table, chain, 1, rule...) return ipt.Insert(table, chain, 1, rule...)
} else {
return ipt.Append(table, chain, rule...)
} }
return ipt.Append(table, chain, rule...)
} }

View File

@ -19,11 +19,12 @@ import (
"math/rand" "math/rand"
"runtime" "runtime"
"github.com/coreos/go-iptables/iptables"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"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/onsi/ginkgo"
. "github.com/onsi/gomega"
) )
const TABLE = "filter" // We'll monkey around here const TABLE = "filter" // We'll monkey around here
@ -34,7 +35,6 @@ var _ = Describe("chain tests", func() {
var cleanup func() var cleanup func()
BeforeEach(func() { BeforeEach(func() {
// Save a reference to the original namespace, // Save a reference to the original namespace,
// Add a new NS // Add a new NS
currNs, err := ns.GetCurrentNS() currNs, err := ns.GetCurrentNS()
@ -60,7 +60,6 @@ var _ = Describe("chain tests", func() {
ipt.DeleteChain(TABLE, testChain) ipt.DeleteChain(TABLE, testChain)
currNs.Set() currNs.Set()
} }
}) })
AfterEach(func() { AfterEach(func() {
@ -93,5 +92,4 @@ var _ = Describe("chain tests", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
}) })
}) })

View File

@ -16,7 +16,7 @@ package sysctl
import ( import (
"fmt" "fmt"
"io/ioutil" "os"
"path/filepath" "path/filepath"
"strings" "strings"
) )
@ -36,7 +36,7 @@ func Sysctl(name string, params ...string) (string, error) {
func getSysctl(name string) (string, error) { func getSysctl(name string) (string, error) {
fullName := filepath.Join("/proc/sys", toNormalName(name)) fullName := filepath.Join("/proc/sys", toNormalName(name))
data, err := ioutil.ReadFile(fullName) data, err := os.ReadFile(fullName)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -46,7 +46,7 @@ func getSysctl(name string) (string, error) {
func setSysctl(name, value string) (string, error) { func setSysctl(name, value string) (string, error) {
fullName := filepath.Join("/proc/sys", toNormalName(name)) fullName := filepath.Join("/proc/sys", toNormalName(name))
if err := ioutil.WriteFile(fullName, []byte(value), 0644); err != nil { if err := os.WriteFile(fullName, []byte(value), 0o644); err != nil {
return "", err return "", err
} }

View File

@ -20,12 +20,13 @@ import (
"runtime" "runtime"
"strings" "strings"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"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/containernetworking/plugins/pkg/utils/sysctl" "github.com/containernetworking/plugins/pkg/utils/sysctl"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
) )
const ( const (
@ -37,8 +38,7 @@ var _ = Describe("Sysctl tests", func() {
var testIfaceName string var testIfaceName string
var cleanup func() var cleanup func()
BeforeEach(func() { beforeEach := func() {
// Save a reference to the original namespace, // Save a reference to the original namespace,
// Add a new NS // Add a new NS
currNs, err := ns.GetCurrentNS() currNs, err := ns.GetCurrentNS()
@ -66,8 +66,7 @@ var _ = Describe("Sysctl tests", func() {
netlink.LinkDel(testIface) netlink.LinkDel(testIface)
currNs.Set() currNs.Set()
} }
}
})
AfterEach(func() { AfterEach(func() {
cleanup() cleanup()
@ -75,7 +74,8 @@ var _ = Describe("Sysctl tests", func() {
Describe("Sysctl", func() { Describe("Sysctl", func() {
It("reads keys with dot separators", func() { It("reads keys with dot separators", func() {
sysctlIfaceName := strings.Replace(testIfaceName, ".", "/", -1) beforeEach()
sysctlIfaceName := strings.ReplaceAll(testIfaceName, ".", "/")
sysctlKey := fmt.Sprintf(sysctlDotKeyTemplate, sysctlIfaceName) sysctlKey := fmt.Sprintf(sysctlDotKeyTemplate, sysctlIfaceName)
_, err := sysctl.Sysctl(sysctlKey) _, err := sysctl.Sysctl(sysctlKey)
@ -85,6 +85,7 @@ var _ = Describe("Sysctl tests", func() {
Describe("Sysctl", func() { Describe("Sysctl", func() {
It("reads keys with slash separators", func() { It("reads keys with slash separators", func() {
beforeEach()
sysctlKey := fmt.Sprintf(sysctlSlashKeyTemplate, testIfaceName) sysctlKey := fmt.Sprintf(sysctlSlashKeyTemplate, testIfaceName)
_, err := sysctl.Sysctl(sysctlKey) _, err := sysctl.Sysctl(sysctlKey)
@ -94,7 +95,8 @@ var _ = Describe("Sysctl tests", func() {
Describe("Sysctl", func() { Describe("Sysctl", func() {
It("writes keys with dot separators", func() { It("writes keys with dot separators", func() {
sysctlIfaceName := strings.Replace(testIfaceName, ".", "/", -1) beforeEach()
sysctlIfaceName := strings.ReplaceAll(testIfaceName, ".", "/")
sysctlKey := fmt.Sprintf(sysctlDotKeyTemplate, sysctlIfaceName) sysctlKey := fmt.Sprintf(sysctlDotKeyTemplate, sysctlIfaceName)
_, err := sysctl.Sysctl(sysctlKey, "1") _, err := sysctl.Sysctl(sysctlKey, "1")
@ -104,11 +106,11 @@ var _ = Describe("Sysctl tests", func() {
Describe("Sysctl", func() { Describe("Sysctl", func() {
It("writes keys with slash separators", func() { It("writes keys with slash separators", func() {
beforeEach()
sysctlKey := fmt.Sprintf(sysctlSlashKeyTemplate, testIfaceName) sysctlKey := fmt.Sprintf(sysctlSlashKeyTemplate, testIfaceName)
_, err := sysctl.Sysctl(sysctlKey, "1") _, err := sysctl.Sysctl(sysctlKey, "1")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
}) })
}) })

View File

@ -17,7 +17,7 @@ package sysctl_test
import ( import (
"testing" "testing"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )

View File

@ -15,10 +15,10 @@
package utils_test package utils_test
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestUtils(t *testing.T) { func TestUtils(t *testing.T) {

View File

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"strings" "strings"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
@ -26,29 +26,29 @@ var _ = Describe("Utils", func() {
Describe("FormatChainName", func() { Describe("FormatChainName", func() {
It("must format a short name", func() { It("must format a short name", func() {
chain := FormatChainName("test", "1234") chain := FormatChainName("test", "1234")
Expect(len(chain)).To(Equal(maxChainLength)) Expect(chain).To(HaveLen(maxChainLength))
Expect(chain).To(Equal("CNI-2bbe0c48b91a7d1b8a6753a8")) Expect(chain).To(Equal("CNI-2bbe0c48b91a7d1b8a6753a8"))
}) })
It("must truncate a long name", func() { It("must truncate a long name", func() {
chain := FormatChainName("testalongnamethatdoesnotmakesense", "1234") chain := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
Expect(len(chain)).To(Equal(maxChainLength)) Expect(chain).To(HaveLen(maxChainLength))
Expect(chain).To(Equal("CNI-374f33fe84ab0ed84dcdebe3")) Expect(chain).To(Equal("CNI-374f33fe84ab0ed84dcdebe3"))
}) })
It("must be predictable", func() { It("must be predictable", func() {
chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
Expect(len(chain1)).To(Equal(maxChainLength)) Expect(chain1).To(HaveLen(maxChainLength))
Expect(len(chain2)).To(Equal(maxChainLength)) Expect(chain2).To(HaveLen(maxChainLength))
Expect(chain1).To(Equal(chain2)) Expect(chain1).To(Equal(chain2))
}) })
It("must change when a character changes", func() { It("must change when a character changes", func() {
chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1235") chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1235")
Expect(len(chain1)).To(Equal(maxChainLength)) Expect(chain1).To(HaveLen(maxChainLength))
Expect(len(chain2)).To(Equal(maxChainLength)) Expect(chain2).To(HaveLen(maxChainLength))
Expect(chain1).To(Equal("CNI-374f33fe84ab0ed84dcdebe3")) Expect(chain1).To(Equal("CNI-374f33fe84ab0ed84dcdebe3"))
Expect(chain1).NotTo(Equal(chain2)) Expect(chain1).NotTo(Equal(chain2))
}) })
@ -57,35 +57,35 @@ var _ = Describe("Utils", func() {
Describe("MustFormatChainNameWithPrefix", func() { Describe("MustFormatChainNameWithPrefix", func() {
It("generates a chain name with a prefix", func() { It("generates a chain name with a prefix", func() {
chain := MustFormatChainNameWithPrefix("test", "1234", "PREFIX-") chain := MustFormatChainNameWithPrefix("test", "1234", "PREFIX-")
Expect(len(chain)).To(Equal(maxChainLength)) Expect(chain).To(HaveLen(maxChainLength))
Expect(chain).To(Equal("CNI-PREFIX-2bbe0c48b91a7d1b8")) Expect(chain).To(Equal("CNI-PREFIX-2bbe0c48b91a7d1b8"))
}) })
It("must format a short name", func() { It("must format a short name", func() {
chain := MustFormatChainNameWithPrefix("test", "1234", "PREFIX-") chain := MustFormatChainNameWithPrefix("test", "1234", "PREFIX-")
Expect(len(chain)).To(Equal(maxChainLength)) Expect(chain).To(HaveLen(maxChainLength))
Expect(chain).To(Equal("CNI-PREFIX-2bbe0c48b91a7d1b8")) Expect(chain).To(Equal("CNI-PREFIX-2bbe0c48b91a7d1b8"))
}) })
It("must truncate a long name", func() { It("must truncate a long name", func() {
chain := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-") chain := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-")
Expect(len(chain)).To(Equal(maxChainLength)) Expect(chain).To(HaveLen(maxChainLength))
Expect(chain).To(Equal("CNI-PREFIX-374f33fe84ab0ed84")) Expect(chain).To(Equal("CNI-PREFIX-374f33fe84ab0ed84"))
}) })
It("must be predictable", func() { It("must be predictable", func() {
chain1 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-") chain1 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-")
chain2 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-") chain2 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-")
Expect(len(chain1)).To(Equal(maxChainLength)) Expect(chain1).To(HaveLen(maxChainLength))
Expect(len(chain2)).To(Equal(maxChainLength)) Expect(chain2).To(HaveLen(maxChainLength))
Expect(chain1).To(Equal(chain2)) Expect(chain1).To(Equal(chain2))
}) })
It("must change when a character changes", func() { It("must change when a character changes", func() {
chain1 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-") chain1 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1234", "PREFIX-")
chain2 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1235", "PREFIX-") chain2 := MustFormatChainNameWithPrefix("testalongnamethatdoesnotmakesense", "1235", "PREFIX-")
Expect(len(chain1)).To(Equal(maxChainLength)) Expect(chain1).To(HaveLen(maxChainLength))
Expect(len(chain2)).To(Equal(maxChainLength)) Expect(chain2).To(HaveLen(maxChainLength))
Expect(chain1).To(Equal("CNI-PREFIX-374f33fe84ab0ed84")) Expect(chain1).To(Equal("CNI-PREFIX-374f33fe84ab0ed84"))
Expect(chain1).NotTo(Equal(chain2)) Expect(chain1).NotTo(Equal(chain2))
}) })
@ -161,5 +161,4 @@ var _ = Describe("Utils", func() {
) )
}) })
}) })
}) })

View File

@ -23,7 +23,7 @@ const (
MaxDHCPLen = 576 MaxDHCPLen = 576
) )
//Send the Discovery Packet to the Broadcast Channel // Send the Discovery Packet to the Broadcast Channel
func DhcpSendDiscoverPacket(c *dhcp4client.Client, options dhcp4.Options) (dhcp4.Packet, error) { func DhcpSendDiscoverPacket(c *dhcp4client.Client, options dhcp4.Options) (dhcp4.Packet, error) {
discoveryPacket := c.DiscoverPacket() discoveryPacket := c.DiscoverPacket()
@ -35,7 +35,7 @@ func DhcpSendDiscoverPacket(c *dhcp4client.Client, options dhcp4.Options) (dhcp4
return discoveryPacket, c.SendPacket(discoveryPacket) return discoveryPacket, c.SendPacket(discoveryPacket)
} }
//Send Request Based On the offer Received. // Send Request Based On the offer Received.
func DhcpSendRequest(c *dhcp4client.Client, options dhcp4.Options, offerPacket *dhcp4.Packet) (dhcp4.Packet, error) { func DhcpSendRequest(c *dhcp4client.Client, options dhcp4.Options, offerPacket *dhcp4.Packet) (dhcp4.Packet, error) {
requestPacket := c.RequestPacket(offerPacket) requestPacket := c.RequestPacket(offerPacket)
@ -48,7 +48,7 @@ func DhcpSendRequest(c *dhcp4client.Client, options dhcp4.Options, offerPacket *
return requestPacket, c.SendPacket(requestPacket) return requestPacket, c.SendPacket(requestPacket)
} }
//Send Decline to the received acknowledgement. // Send Decline to the received acknowledgement.
func DhcpSendDecline(c *dhcp4client.Client, acknowledgementPacket *dhcp4.Packet, options dhcp4.Options) (dhcp4.Packet, error) { func DhcpSendDecline(c *dhcp4client.Client, acknowledgementPacket *dhcp4.Packet, options dhcp4.Options) (dhcp4.Packet, error) {
declinePacket := c.DeclinePacket(acknowledgementPacket) declinePacket := c.DeclinePacket(acknowledgementPacket)
@ -61,7 +61,7 @@ func DhcpSendDecline(c *dhcp4client.Client, acknowledgementPacket *dhcp4.Packet,
return declinePacket, c.SendPacket(declinePacket) return declinePacket, c.SendPacket(declinePacket)
} }
//Lets do a Full DHCP Request. // Lets do a Full DHCP Request.
func DhcpRequest(c *dhcp4client.Client, options dhcp4.Options) (bool, dhcp4.Packet, error) { func DhcpRequest(c *dhcp4client.Client, options dhcp4.Options) (bool, dhcp4.Packet, error) {
discoveryPacket, err := DhcpSendDiscoverPacket(c, options) discoveryPacket, err := DhcpSendDiscoverPacket(c, options)
if err != nil { if err != nil {
@ -91,8 +91,8 @@ func DhcpRequest(c *dhcp4client.Client, options dhcp4.Options) (bool, dhcp4.Pack
return true, acknowledgement, nil return true, acknowledgement, nil
} }
//Renew a lease backed on the Acknowledgement Packet. // Renew a lease backed on the Acknowledgement Packet.
//Returns Successful, The AcknoledgementPacket, Any Errors // Returns Successful, The AcknoledgementPacket, Any Errors
func DhcpRenew(c *dhcp4client.Client, acknowledgement dhcp4.Packet, options dhcp4.Options) (bool, dhcp4.Packet, error) { func DhcpRenew(c *dhcp4client.Client, acknowledgement dhcp4.Packet, options dhcp4.Options) (bool, dhcp4.Packet, error) {
renewRequest := c.RenewalRequestPacket(&acknowledgement) renewRequest := c.RenewalRequestPacket(&acknowledgement)
@ -120,8 +120,8 @@ func DhcpRenew(c *dhcp4client.Client, acknowledgement dhcp4.Packet, options dhcp
return true, newAcknowledgement, nil return true, newAcknowledgement, nil
} }
//Release a lease backed on the Acknowledgement Packet. // Release a lease backed on the Acknowledgement Packet.
//Returns Any Errors // Returns Any Errors
func DhcpRelease(c *dhcp4client.Client, acknowledgement dhcp4.Packet, options dhcp4.Options) error { func DhcpRelease(c *dhcp4client.Client, acknowledgement dhcp4.Packet, options dhcp4.Options) error {
release := c.ReleasePacket(&acknowledgement) release := c.ReleasePacket(&acknowledgement)

View File

@ -15,22 +15,25 @@
package main package main
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"net/rpc" "net/rpc"
"os" "os"
"os/signal"
"path/filepath" "path/filepath"
"runtime" "runtime"
"sync" "sync"
"syscall"
"time" "time"
"github.com/coreos/go-systemd/v22/activation"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
current "github.com/containernetworking/cni/pkg/types/100" current "github.com/containernetworking/cni/pkg/types/100"
"github.com/coreos/go-systemd/v22/activation"
) )
var errNoMoreTries = errors.New("no more tries") var errNoMoreTries = errors.New("no more tries")
@ -53,7 +56,7 @@ func newDHCP(clientTimeout, clientResendMax time.Duration) *DHCP {
} }
// TODO: current client ID is too long. At least the container ID should not be used directly. // TODO: current client ID is too long. At least the container ID should not be used directly.
// A seperate issue is necessary to ensure no breaking change is affecting other users. // A separate issue is necessary to ensure no breaking change is affecting other users.
func generateClientID(containerID string, netName string, ifName string) string { func generateClientID(containerID string, netName string, ifName string) string {
clientID := containerID + "/" + netName + "/" + ifName clientID := containerID + "/" + netName + "/" + ifName
// defined in RFC 2132, length size can not be larger than 1 octet. So we truncate 254 to make everyone happy. // defined in RFC 2132, length size can not be larger than 1 octet. So we truncate 254 to make everyone happy.
@ -77,13 +80,21 @@ 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)
// If we already have an active lease for this clientID, do not create
// another one
l := d.getLease(clientID)
if l != nil {
l.Check()
} else {
hostNetns := d.hostNetnsPrefix + args.Netns hostNetns := d.hostNetnsPrefix + args.Netns
l, err := AcquireLease(clientID, hostNetns, args.IfName, l, err = AcquireLease(clientID, hostNetns, args.IfName,
optsRequesting, optsProviding, optsRequesting, optsProviding,
d.clientTimeout, d.clientResendMax, d.broadcast) d.clientTimeout, d.clientResendMax, d.broadcast)
if err != nil { if err != nil {
return err return err
} }
}
ipn, err := l.IPNet() ipn, err := l.IPNet()
if err != nil { if err != nil {
@ -104,7 +115,7 @@ func (d *DHCP) Allocate(args *skel.CmdArgs, result *current.Result) error {
// Release stops maintenance of the lease acquired in Allocate() // Release stops maintenance of the lease acquired in Allocate()
// and sends a release msg to the DHCP server. // and sends a release msg to the DHCP server.
func (d *DHCP) Release(args *skel.CmdArgs, reply *struct{}) error { func (d *DHCP) Release(args *skel.CmdArgs, _ *struct{}) error {
conf := NetConf{} conf := NetConf{}
if err := json.Unmarshal(args.StdinData, &conf); err != nil { if err := json.Unmarshal(args.StdinData, &conf); err != nil {
return fmt.Errorf("error parsing netconf: %v", err) return fmt.Errorf("error parsing netconf: %v", err)
@ -139,7 +150,7 @@ func (d *DHCP) setLease(clientID string, l *DHCPLease) {
d.leases[clientID] = l d.leases[clientID] = l
} }
//func (d *DHCP) clearLease(contID, netName, ifName string) { // func (d *DHCP) clearLease(contID, netName, ifName string) {
func (d *DHCP) clearLease(clientID string) { func (d *DHCP) clearLease(clientID string) {
d.mux.Lock() d.mux.Lock()
defer d.mux.Unlock() defer d.mux.Unlock()
@ -156,7 +167,7 @@ func getListener(socketPath string) (net.Listener, error) {
switch { switch {
case len(l) == 0: case len(l) == 0:
if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil { if err := os.MkdirAll(filepath.Dir(socketPath), 0o700); err != nil {
return nil, err return nil, err
} }
return net.Listen("unix", socketPath) return net.Listen("unix", socketPath)
@ -185,7 +196,7 @@ func runDaemon(
if !filepath.IsAbs(pidfilePath) { if !filepath.IsAbs(pidfilePath) {
return fmt.Errorf("Error writing pidfile %q: path not absolute", pidfilePath) return fmt.Errorf("Error writing pidfile %q: path not absolute", pidfilePath)
} }
if err := ioutil.WriteFile(pidfilePath, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil { if err := os.WriteFile(pidfilePath, []byte(fmt.Sprintf("%d", os.Getpid())), 0o644); err != nil {
return fmt.Errorf("Error writing pidfile %q: %v", pidfilePath, err) return fmt.Errorf("Error writing pidfile %q: %v", pidfilePath, err)
} }
} }
@ -195,11 +206,27 @@ func runDaemon(
return fmt.Errorf("Error getting listener: %v", err) return fmt.Errorf("Error getting listener: %v", err)
} }
srv := http.Server{}
exit := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(exit, os.Interrupt, syscall.SIGTERM)
go func() {
<-exit
srv.Shutdown(context.TODO())
os.Remove(hostPrefix + socketPath)
os.Remove(pidfilePath)
done <- true
}()
dhcp := newDHCP(dhcpClientTimeout, resendMax) dhcp := newDHCP(dhcpClientTimeout, resendMax)
dhcp.hostNetnsPrefix = hostPrefix dhcp.hostNetnsPrefix = hostPrefix
dhcp.broadcast = broadcast dhcp.broadcast = broadcast
rpc.Register(dhcp) rpc.Register(dhcp)
rpc.HandleHTTP() rpc.HandleHTTP()
http.Serve(l, nil) srv.Serve(l)
<-done
return nil return nil
} }

View File

@ -16,21 +16,19 @@ package main
import ( import (
"fmt" "fmt"
"net"
"os" "os"
"os/exec" "os/exec"
"sync" "sync"
"time" "time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
current "github.com/containernetworking/cni/pkg/types/100" 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/vishvananda/netlink"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
) )
var _ = Describe("DHCP Multiple Lease Operations", func() { var _ = Describe("DHCP Multiple Lease Operations", func() {
@ -40,11 +38,10 @@ var _ = Describe("DHCP Multiple Lease Operations", func() {
var clientCmd *exec.Cmd var clientCmd *exec.Cmd
var socketPath string var socketPath string
var tmpDir string var tmpDir string
var serverIP net.IPNet
var err error var err error
BeforeEach(func() { BeforeEach(func() {
dhcpServerStopCh, serverIP, socketPath, originalNS, targetNS, err = dhcpSetupOriginalNS() dhcpServerStopCh, socketPath, originalNS, targetNS, err = dhcpSetupOriginalNS()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Move the container side to the container's NS // Move the container side to the container's NS
@ -64,7 +61,7 @@ var _ = Describe("DHCP Multiple Lease Operations", func() {
}) })
// Start the DHCP server // Start the DHCP server
dhcpServerDone, err = dhcpServerStart(originalNS, net.IPv4(192, 168, 1, 5), serverIP.IP, 2, dhcpServerStopCh) dhcpServerDone, err = dhcpServerStart(originalNS, 2, dhcpServerStopCh)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Start the DHCP client daemon // Start the DHCP client daemon
@ -123,7 +120,7 @@ var _ = Describe("DHCP Multiple Lease Operations", func() {
addResult, err = current.GetResult(r) addResult, err = current.GetResult(r)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addResult.IPs)).To(Equal(1)) Expect(addResult.IPs).To(HaveLen(1))
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24")) Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
return nil return nil
}) })
@ -146,7 +143,7 @@ var _ = Describe("DHCP Multiple Lease Operations", func() {
addResult, err = current.GetResult(r) addResult, err = current.GetResult(r)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addResult.IPs)).To(Equal(1)) Expect(addResult.IPs).To(HaveLen(1))
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.6/24")) Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.6/24"))
return nil return nil
}) })

View File

@ -15,10 +15,10 @@
package main package main
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestDHCP(t *testing.T) { func TestDHCP(t *testing.T) {

View File

@ -18,7 +18,6 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net" "net"
"os" "os"
"os/exec" "os/exec"
@ -26,24 +25,22 @@ import (
"sync" "sync"
"time" "time"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"
"github.com/vishvananda/netlink"
"github.com/d2g/dhcp4" "github.com/d2g/dhcp4"
"github.com/d2g/dhcp4server" "github.com/d2g/dhcp4server"
"github.com/d2g/dhcp4server/leasepool" "github.com/d2g/dhcp4server/leasepool"
"github.com/d2g/dhcp4server/leasepool/memorypool" "github.com/d2g/dhcp4server/leasepool/memorypool"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/skel"
types100 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"
) )
func getTmpDir() (string, error) { func getTmpDir() (string, error) {
tmpDir, err := ioutil.TempDir(cniDirPrefix, "dhcp") tmpDir, err := os.MkdirTemp(cniDirPrefix, "dhcp")
if err == nil { if err == nil {
tmpDir = filepath.ToSlash(tmpDir) tmpDir = filepath.ToSlash(tmpDir)
} }
@ -51,7 +48,7 @@ func getTmpDir() (string, error) {
return tmpDir, err return tmpDir, err
} }
func dhcpServerStart(netns ns.NetNS, leaseIP, serverIP net.IP, numLeases int, stopCh <-chan bool) (*sync.WaitGroup, error) { func dhcpServerStart(netns ns.NetNS, numLeases int, stopCh <-chan bool) (*sync.WaitGroup, error) {
// Add the expected IP to the pool // Add the expected IP to the pool
lp := memorypool.MemoryPool{} lp := memorypool.MemoryPool{}
@ -121,7 +118,7 @@ const (
) )
var _ = BeforeSuite(func() { var _ = BeforeSuite(func() {
err := os.MkdirAll(cniDirPrefix, 0700) err := os.MkdirAll(cniDirPrefix, 0o700)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -203,7 +200,7 @@ var _ = Describe("DHCP Operations", func() {
}) })
// Start the DHCP server // Start the DHCP server
dhcpServerDone, err = dhcpServerStart(originalNS, net.IPv4(192, 168, 1, 5), serverIP.IP, 1, dhcpServerStopCh) dhcpServerDone, err = dhcpServerStart(originalNS, 1, dhcpServerStopCh)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Start the DHCP client daemon // Start the DHCP client daemon
@ -274,7 +271,7 @@ var _ = Describe("DHCP Operations", func() {
addResult, err = types100.GetResult(r) addResult, err = types100.GetResult(r)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addResult.IPs)).To(Equal(1)) Expect(addResult.IPs).To(HaveLen(1))
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24")) Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
return nil return nil
}) })
@ -317,7 +314,7 @@ var _ = Describe("DHCP Operations", func() {
addResult, err = types100.GetResult(r) addResult, err = types100.GetResult(r)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addResult.IPs)).To(Equal(1)) Expect(addResult.IPs).To(HaveLen(1))
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24")) Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
return nil return nil
}) })
@ -364,7 +361,7 @@ const (
contVethName1 string = "eth1" contVethName1 string = "eth1"
) )
func dhcpSetupOriginalNS() (chan bool, net.IPNet, string, ns.NetNS, ns.NetNS, error) { func dhcpSetupOriginalNS() (chan bool, string, ns.NetNS, ns.NetNS, error) {
var originalNS, targetNS ns.NetNS var originalNS, targetNS ns.NetNS
var dhcpServerStopCh chan bool var dhcpServerStopCh chan bool
var socketPath string var socketPath string
@ -385,11 +382,6 @@ func dhcpSetupOriginalNS() (chan bool, net.IPNet, string, ns.NetNS, ns.NetNS, er
targetNS, err = testutils.NewNS() targetNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
serverIP := net.IPNet{
IP: net.IPv4(192, 168, 1, 1),
Mask: net.IPv4Mask(255, 255, 255, 0),
}
// Use (original) NS // Use (original) NS
err = originalNS.Do(func(ns.NetNS) error { err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
@ -484,7 +476,7 @@ func dhcpSetupOriginalNS() (chan bool, net.IPNet, string, ns.NetNS, ns.NetNS, er
return nil return nil
}) })
return dhcpServerStopCh, serverIP, socketPath, originalNS, targetNS, err return dhcpServerStopCh, socketPath, originalNS, targetNS, err
} }
var _ = Describe("DHCP Lease Unavailable Operations", func() { var _ = Describe("DHCP Lease Unavailable Operations", func() {
@ -494,11 +486,10 @@ var _ = Describe("DHCP Lease Unavailable Operations", func() {
var clientCmd *exec.Cmd var clientCmd *exec.Cmd
var socketPath string var socketPath string
var tmpDir string var tmpDir string
var serverIP net.IPNet
var err error var err error
BeforeEach(func() { BeforeEach(func() {
dhcpServerStopCh, serverIP, socketPath, originalNS, targetNS, err = dhcpSetupOriginalNS() dhcpServerStopCh, socketPath, originalNS, targetNS, err = dhcpSetupOriginalNS()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Move the container side to the container's NS // Move the container side to the container's NS
@ -518,7 +509,7 @@ var _ = Describe("DHCP Lease Unavailable Operations", func() {
}) })
// Start the DHCP server // Start the DHCP server
dhcpServerDone, err = dhcpServerStart(originalNS, net.IPv4(192, 168, 1, 5), serverIP.IP, 1, dhcpServerStopCh) dhcpServerDone, err = dhcpServerStart(originalNS, 1, dhcpServerStopCh)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Start the DHCP client daemon // Start the DHCP client daemon
@ -597,7 +588,7 @@ var _ = Describe("DHCP Lease Unavailable Operations", func() {
addResult, err = types100.GetResult(r) addResult, err = types100.GetResult(r)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addResult.IPs)).To(Equal(1)) Expect(addResult.IPs).To(HaveLen(1))
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24")) Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
return nil return nil
}) })

View File

@ -34,13 +34,17 @@ import (
// RFC 2131 suggests using exponential backoff, starting with 4sec // RFC 2131 suggests using exponential backoff, starting with 4sec
// and randomized to +/- 1sec // and randomized to +/- 1sec
const resendDelay0 = 4 * time.Second const (
const resendDelayMax = 62 * time.Second resendDelay0 = 4 * time.Second
resendDelayMax = 62 * time.Second
)
// To speed up the retry for first few failures, we retry without // To speed up the retry for first few failures, we retry without
// backoff for a few times // backoff for a few times
const resendFastDelay = 2 * time.Second const (
const resendFastMax = 4 resendFastDelay = 2 * time.Second
resendFastMax = 4
)
const ( const (
leaseStateBound = iota leaseStateBound = iota
@ -67,6 +71,7 @@ type DHCPLease struct {
broadcast bool broadcast bool
stopping uint32 stopping uint32
stop chan struct{} stop chan struct{}
check chan struct{}
wg sync.WaitGroup wg sync.WaitGroup
// list of requesting and providing options and if they are necessary / their value // list of requesting and providing options and if they are necessary / their value
optsRequesting map[dhcp4.OptionCode]bool optsRequesting map[dhcp4.OptionCode]bool
@ -78,9 +83,12 @@ var requestOptionsDefault = map[dhcp4.OptionCode]bool{
dhcp4.OptionSubnetMask: true, dhcp4.OptionSubnetMask: true,
} }
func prepareOptions(cniArgs string, ProvideOptions []ProvideOption, RequestOptions []RequestOption) ( func prepareOptions(cniArgs string, provideOptions []ProvideOption, requestOptions []RequestOption) (
optsRequesting map[dhcp4.OptionCode]bool, optsProviding map[dhcp4.OptionCode][]byte, err error) { map[dhcp4.OptionCode]bool, map[dhcp4.OptionCode][]byte, error,
) {
var optsRequesting map[dhcp4.OptionCode]bool
var optsProviding map[dhcp4.OptionCode][]byte
var err error
// parse CNI args // parse CNI args
cniArgsParsed := map[string]string{} cniArgsParsed := map[string]string{}
for _, argPair := range strings.Split(cniArgs, ";") { for _, argPair := range strings.Split(cniArgs, ";") {
@ -93,23 +101,20 @@ func prepareOptions(cniArgs string, ProvideOptions []ProvideOption, RequestOptio
// parse providing options map // parse providing options map
var optParsed dhcp4.OptionCode var optParsed dhcp4.OptionCode
optsProviding = make(map[dhcp4.OptionCode][]byte) optsProviding = make(map[dhcp4.OptionCode][]byte)
for _, opt := range ProvideOptions { for _, opt := range provideOptions {
optParsed, err = parseOptionName(string(opt.Option)) optParsed, err = parseOptionName(string(opt.Option))
if err != nil { if err != nil {
err = fmt.Errorf("Can not parse option %q: %w", opt.Option, err) return nil, nil, fmt.Errorf("Can not parse option %q: %w", opt.Option, err)
return
} }
if len(opt.Value) > 0 { if len(opt.Value) > 0 {
if len(opt.Value) > 255 { if len(opt.Value) > 255 {
err = fmt.Errorf("value too long for option %q: %q", opt.Option, opt.Value) return nil, nil, fmt.Errorf("value too long for option %q: %q", opt.Option, opt.Value)
return
} }
optsProviding[optParsed] = []byte(opt.Value) optsProviding[optParsed] = []byte(opt.Value)
} }
if value, ok := cniArgsParsed[opt.ValueFromCNIArg]; ok { if value, ok := cniArgsParsed[opt.ValueFromCNIArg]; ok {
if len(value) > 255 { if len(value) > 255 {
err = fmt.Errorf("value too long for option %q from CNI_ARGS %q: %q", opt.Option, opt.ValueFromCNIArg, opt.Value) return nil, nil, fmt.Errorf("value too long for option %q from CNI_ARGS %q: %q", opt.Option, opt.ValueFromCNIArg, opt.Value)
return
} }
optsProviding[optParsed] = []byte(value) optsProviding[optParsed] = []byte(value)
} }
@ -118,14 +123,13 @@ func prepareOptions(cniArgs string, ProvideOptions []ProvideOption, RequestOptio
// parse necessary options map // parse necessary options map
optsRequesting = make(map[dhcp4.OptionCode]bool) optsRequesting = make(map[dhcp4.OptionCode]bool)
skipRequireDefault := false skipRequireDefault := false
for _, opt := range RequestOptions { for _, opt := range requestOptions {
if opt.SkipDefault { if opt.SkipDefault {
skipRequireDefault = true skipRequireDefault = true
} }
optParsed, err = parseOptionName(string(opt.Option)) optParsed, err = parseOptionName(string(opt.Option))
if err != nil { if err != nil {
err = fmt.Errorf("Can not parse option %q: %w", opt.Option, err) return nil, nil, fmt.Errorf("Can not parse option %q: %w", opt.Option, err)
return
} }
optsRequesting[optParsed] = true optsRequesting[optParsed] = true
} }
@ -135,7 +139,7 @@ func prepareOptions(cniArgs string, ProvideOptions []ProvideOption, RequestOptio
optsRequesting[k] = v optsRequesting[k] = v
} }
} }
return return optsRequesting, optsProviding, err
} }
// AcquireLease gets an DHCP lease and then maintains it in the background // AcquireLease gets an DHCP lease and then maintains it in the background
@ -150,6 +154,7 @@ func AcquireLease(
l := &DHCPLease{ l := &DHCPLease{
clientID: clientID, clientID: clientID,
stop: make(chan struct{}), stop: make(chan struct{}),
check: make(chan struct{}),
timeout: timeout, timeout: timeout,
resendMax: resendMax, resendMax: resendMax,
broadcast: broadcast, broadcast: broadcast,
@ -200,8 +205,36 @@ func (l *DHCPLease) Stop() {
l.wg.Wait() l.wg.Wait()
} }
func (l *DHCPLease) Check() {
l.check <- struct{}{}
}
func (l *DHCPLease) getOptionsWithClientID() dhcp4.Options {
opts := make(dhcp4.Options)
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
// client identifier's first byte is "type"
newClientID := []byte{0}
newClientID = append(newClientID, opts[dhcp4.OptionClientIdentifier]...)
opts[dhcp4.OptionClientIdentifier] = newClientID
return opts
}
func (l *DHCPLease) getAllOptions() dhcp4.Options {
opts := l.getOptionsWithClientID()
for k, v := range l.optsProviding {
opts[k] = v
}
opts[dhcp4.OptionParameterRequestList] = []byte{}
for k := range l.optsRequesting {
opts[dhcp4.OptionParameterRequestList] = append(opts[dhcp4.OptionParameterRequestList], byte(k))
}
return opts
}
func (l *DHCPLease) acquire() error { func (l *DHCPLease) acquire() error {
c, err := newDHCPClient(l.link, l.clientID, l.timeout, l.broadcast) c, err := newDHCPClient(l.link, l.timeout, l.broadcast)
if err != nil { if err != nil {
return err return err
} }
@ -214,19 +247,7 @@ func (l *DHCPLease) acquire() error {
} }
} }
opts := make(dhcp4.Options) opts := l.getAllOptions()
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
opts[dhcp4.OptionParameterRequestList] = []byte{}
for k := range l.optsRequesting {
opts[dhcp4.OptionParameterRequestList] = append(opts[dhcp4.OptionParameterRequestList], byte(k))
}
for k, v := range l.optsProviding {
opts[k] = v
}
// client identifier's first byte is "type"
newClientID := []byte{0}
newClientID = append(newClientID, opts[dhcp4.OptionClientIdentifier]...)
opts[dhcp4.OptionClientIdentifier] = newClientID
pkt, err := backoffRetry(l.resendMax, 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)
@ -284,7 +305,7 @@ func (l *DHCPLease) maintain() {
switch state { switch state {
case leaseStateBound: case leaseStateBound:
sleepDur = l.renewalTime.Sub(time.Now()) sleepDur = time.Until(l.renewalTime)
if sleepDur <= 0 { if sleepDur <= 0 {
log.Printf("%v: renewing lease", l.clientID) log.Printf("%v: renewing lease", l.clientID)
state = leaseStateRenewing state = leaseStateRenewing
@ -296,7 +317,7 @@ func (l *DHCPLease) maintain() {
log.Printf("%v: %v", l.clientID, err) log.Printf("%v: %v", l.clientID, err)
if time.Now().After(l.rebindingTime) { if time.Now().After(l.rebindingTime) {
log.Printf("%v: renawal time expired, rebinding", l.clientID) log.Printf("%v: renewal time expired, rebinding", l.clientID)
state = leaseStateRebinding state = leaseStateRebinding
} }
} else { } else {
@ -322,6 +343,9 @@ func (l *DHCPLease) maintain() {
select { select {
case <-time.After(sleepDur): case <-time.After(sleepDur):
case <-l.check:
log.Printf("%v: Checking lease", l.clientID)
case <-l.stop: case <-l.stop:
if err := l.release(); err != nil { if err := l.release(); err != nil {
log.Printf("%v: failed to release DHCP lease: %v", l.clientID, err) log.Printf("%v: failed to release DHCP lease: %v", l.clientID, err)
@ -338,15 +362,13 @@ func (l *DHCPLease) downIface() {
} }
func (l *DHCPLease) renew() error { func (l *DHCPLease) renew() error {
c, err := newDHCPClient(l.link, l.clientID, l.timeout, l.broadcast) c, err := newDHCPClient(l.link, l.timeout, l.broadcast)
if err != nil { if err != nil {
return err return err
} }
defer c.Close() defer c.Close()
opts := make(dhcp4.Options) opts := l.getAllOptions()
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
pkt, err := backoffRetry(l.resendMax, 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 {
@ -369,14 +391,13 @@ func (l *DHCPLease) renew() error {
func (l *DHCPLease) release() error { func (l *DHCPLease) release() error {
log.Printf("%v: releasing lease", l.clientID) log.Printf("%v: releasing lease", l.clientID)
c, err := newDHCPClient(l.link, l.clientID, l.timeout, l.broadcast) c, err := newDHCPClient(l.link, l.timeout, l.broadcast)
if err != nil { if err != nil {
return err return err
} }
defer c.Close() defer c.Close()
opts := make(dhcp4.Options) opts := l.getOptionsWithClientID()
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
if err = DhcpRelease(c, *l.ack, opts); err != nil { if err = DhcpRelease(c, *l.ack, opts); err != nil {
return fmt.Errorf("failed to send DHCPRELEASE") return fmt.Errorf("failed to send DHCPRELEASE")
@ -406,9 +427,9 @@ func (l *DHCPLease) Routes() []*types.Route {
// RFC 3442 states that if Classless Static Routes (option 121) // RFC 3442 states that if Classless Static Routes (option 121)
// exist, we ignore Static Routes (option 33) and the Router/Gateway. // exist, we ignore Static Routes (option 33) and the Router/Gateway.
opt121_routes := parseCIDRRoutes(l.opts) opt121Routes := parseCIDRRoutes(l.opts)
if len(opt121_routes) > 0 { if len(opt121Routes) > 0 {
return append(routes, opt121_routes...) return append(routes, opt121Routes...)
} }
// Append Static Routes // Append Static Routes
@ -430,9 +451,9 @@ func jitter(span time.Duration) time.Duration {
} }
func backoffRetry(resendMax time.Duration, 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 baseDelay := resendDelay0
var sleepTime time.Duration var sleepTime time.Duration
var fastRetryLimit = resendFastMax fastRetryLimit := resendFastMax
for { for {
pkt, err := f() pkt, err := f()
if err == nil { if err == nil {
@ -464,7 +485,7 @@ func backoffRetry(resendMax time.Duration, f func() (*dhcp4.Packet, error)) (*dh
} }
func newDHCPClient( func newDHCPClient(
link netlink.Link, clientID string, link netlink.Link,
timeout time.Duration, timeout time.Duration,
broadcast bool, broadcast bool,
) (*dhcp4client.Client, error) { ) (*dhcp4client.Client, error) {

View File

@ -118,27 +118,20 @@ func cmdAdd(args *skel.CmdArgs) error {
func cmdDel(args *skel.CmdArgs) error { func cmdDel(args *skel.CmdArgs) error {
result := struct{}{} result := struct{}{}
if err := rpcCall("DHCP.Release", args, &result); err != nil { return rpcCall("DHCP.Release", args, &result)
return err
}
return nil
} }
func cmdCheck(args *skel.CmdArgs) error { func cmdCheck(args *skel.CmdArgs) error {
// Plugin must return result in same version as specified in netconf // Plugin must return result in same version as specified in netconf
versionDecoder := &version.ConfigDecoder{} versionDecoder := &version.ConfigDecoder{}
//confVersion, err := versionDecoder.Decode(args.StdinData) // confVersion, err := versionDecoder.Decode(args.StdinData)
_, err := versionDecoder.Decode(args.StdinData) _, err := versionDecoder.Decode(args.StdinData)
if err != nil { if err != nil {
return err return err
} }
result := &current.Result{CNIVersion: current.ImplementedSpecVersion} result := &current.Result{CNIVersion: current.ImplementedSpecVersion}
if err := rpcCall("DHCP.Allocate", args, result); err != nil { return rpcCall("DHCP.Allocate", args, result)
return err
}
return nil
} }
func getSocketPath(stdinData []byte) (string, error) { func getSocketPath(stdinData []byte) (string, error) {

View File

@ -21,8 +21,9 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/containernetworking/cni/pkg/types"
"github.com/d2g/dhcp4" "github.com/d2g/dhcp4"
"github.com/containernetworking/cni/pkg/types"
) )
var optionNameToID = map[string]dhcp4.OptionCode{ var optionNameToID = map[string]dhcp4.OptionCode{

View File

@ -19,8 +19,9 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/containernetworking/cni/pkg/types"
"github.com/d2g/dhcp4" "github.com/d2g/dhcp4"
"github.com/containernetworking/cni/pkg/types"
) )
func validateRoutes(t *testing.T, routes []*types.Route) { func validateRoutes(t *testing.T, routes []*types.Route) {

View File

@ -22,7 +22,6 @@ import (
"strconv" "strconv"
current "github.com/containernetworking/cni/pkg/types/100" 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"
) )
@ -197,7 +196,7 @@ func (i *RangeIter) Next() (*net.IPNet, net.IP) {
// If we've reached the end of this range, we need to advance the range // If we've reached the end of this range, we need to advance the range
// RangeEnd is inclusive as well // RangeEnd is inclusive as well
if i.cur.Equal(r.RangeEnd) { if i.cur.Equal(r.RangeEnd) {
i.rangeIdx += 1 i.rangeIdx++
i.rangeIdx %= len(*i.rangeset) i.rangeIdx %= len(*i.rangeset)
r = (*i.rangeset)[i.rangeIdx] r = (*i.rangeset)[i.rangeIdx]

View File

@ -15,10 +15,10 @@
package allocator_test package allocator_test
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestAllocator(t *testing.T) { func TestAllocator(t *testing.T) {

View File

@ -18,12 +18,12 @@ import (
"fmt" "fmt"
"net" "net"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" 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/gomega"
) )
type AllocatorTestCase struct { type AllocatorTestCase struct {
@ -77,7 +77,7 @@ func (t AllocatorTestCase) run(idx int) (*current.IPConfig, error) {
p = append(p, Range{Subnet: types.IPNet(*subnet)}) p = append(p, Range{Subnet: types.IPNet(*subnet)})
} }
Expect(p.Canonicalize()).To(BeNil()) Expect(p.Canonicalize()).To(Succeed())
store := fakestore.NewFakeStore(t.ipmap, map[string]net.IP{"rangeid": net.ParseIP(t.lastIP)}) store := fakestore.NewFakeStore(t.ipmap, map[string]net.IP{"rangeid": net.ParseIP(t.lastIP)})
@ -262,7 +262,6 @@ var _ = Describe("host-local ip allocator", func() {
res, err = alloc.Get("ID", "eth0", nil) res, err = alloc.Get("ID", "eth0", nil)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(res.Address.String()).To(Equal("192.168.1.3/29")) Expect(res.Address.String()).To(Equal("192.168.1.3/29"))
}) })
Context("when requesting a specific IP", func() { Context("when requesting a specific IP", func() {
@ -301,7 +300,6 @@ var _ = Describe("host-local ip allocator", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
}) })
}) })
Context("when out of ips", func() { Context("when out of ips", func() {
It("returns a meaningful error", func() { It("returns a meaningful error", func() {
@ -332,7 +330,7 @@ var _ = Describe("host-local ip allocator", func() {
} }
for idx, tc := range testCases { for idx, tc := range testCases {
_, err := tc.run(idx) _, err := tc.run(idx)
Expect(err).NotTo(BeNil()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(HavePrefix("no IP addresses available in range set")) Expect(err.Error()).To(HavePrefix("no IP addresses available in range set"))
} }
}) })

View File

@ -21,7 +21,6 @@ import (
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/version" "github.com/containernetworking/cni/pkg/version"
"github.com/containernetworking/plugins/pkg/ip" "github.com/containernetworking/plugins/pkg/ip"
) )
@ -43,7 +42,7 @@ type Net struct {
// IPAMConfig represents the IP related network configuration. // IPAMConfig represents the IP related network configuration.
// This nests Range because we initially only supported a single // This nests Range because we initially only supported a single
// range directly, and wish to preserve backwards compatability // range directly, and wish to preserve backwards compatibility
type IPAMConfig struct { type IPAMConfig struct {
*Range *Range
Name string Name string

View File

@ -17,9 +17,10 @@ package allocator
import ( import (
"net" "net"
"github.com/containernetworking/cni/pkg/types" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/containernetworking/cni/pkg/types"
) )
var _ = Describe("IPAM config", func() { var _ = Describe("IPAM config", func() {
@ -415,7 +416,6 @@ var _ = Describe("IPAM config", func() {
}` }`
_, _, err := LoadIPAMConfig([]byte(input), "") _, _, err := LoadIPAMConfig([]byte(input), "")
Expect(err).To(MatchError("invalid range set 0: mixed address families")) Expect(err).To(MatchError("invalid range set 0: mixed address families"))
}) })
It("Should should error on too many ranges", func() { It("Should should error on too many ranges", func() {

View File

@ -125,7 +125,7 @@ func (r *Range) Contains(addr net.IP) bool {
// Overlaps returns true if there is any overlap between ranges // Overlaps returns true if there is any overlap between ranges
func (r *Range) Overlaps(r1 *Range) bool { func (r *Range) Overlaps(r1 *Range) bool {
// different familes // different families
if len(r.RangeStart) != len(r1.RangeStart) { if len(r.RangeStart) != len(r1.RangeStart) {
return false return false
} }

View File

@ -67,12 +67,10 @@ func (s *RangeSet) Canonicalize() error {
} }
if i == 0 { if i == 0 {
fam = len((*s)[i].RangeStart) fam = len((*s)[i].RangeStart)
} else { } else if fam != len((*s)[i].RangeStart) {
if fam != len((*s)[i].RangeStart) {
return fmt.Errorf("mixed address families") return fmt.Errorf("mixed address families")
} }
} }
}
// Make sure none of the ranges in the set overlap // Make sure none of the ranges in the set overlap
l := len(*s) l := len(*s)

View File

@ -17,7 +17,7 @@ package allocator
import ( import (
"net" "net"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
@ -40,7 +40,6 @@ var _ = Describe("range sets", func() {
r, err = p.RangeFor(net.IP{192, 168, 99, 99}) r, err = p.RangeFor(net.IP{192, 168, 99, 99})
Expect(r).To(BeNil()) Expect(r).To(BeNil())
Expect(err).To(MatchError("192.168.99.99 not in range set 192.168.0.1-192.168.0.254,172.16.1.1-172.16.1.254")) Expect(err).To(MatchError("192.168.99.99 not in range set 192.168.0.1-192.168.0.254,172.16.1.1-172.16.1.254"))
}) })
It("should discover overlaps within a set", func() { It("should discover overlaps within a set", func() {

View File

@ -17,11 +17,10 @@ package allocator
import ( import (
"net" "net"
"github.com/containernetworking/cni/pkg/types" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/containernetworking/cni/pkg/types"
) )
var _ = Describe("IP ranges", func() { var _ = Describe("IP ranges", func() {

View File

@ -15,7 +15,6 @@
package disk package disk
import ( import (
"io/ioutil"
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
@ -25,8 +24,10 @@ import (
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend" "github.com/containernetworking/plugins/plugins/ipam/host-local/backend"
) )
const lastIPFilePrefix = "last_reserved_ip." const (
const LineBreak = "\r\n" lastIPFilePrefix = "last_reserved_ip."
LineBreak = "\r\n"
)
var defaultDataDir = "/var/lib/cni/networks" var defaultDataDir = "/var/lib/cni/networks"
@ -45,7 +46,7 @@ func New(network, dataDir string) (*Store, error) {
dataDir = defaultDataDir dataDir = defaultDataDir
} }
dir := filepath.Join(dataDir, network) dir := filepath.Join(dataDir, network)
if err := os.MkdirAll(dir, 0755); err != nil { if err := os.MkdirAll(dir, 0o755); err != nil {
return nil, err return nil, err
} }
@ -59,7 +60,7 @@ func New(network, dataDir string) (*Store, error) {
func (s *Store) Reserve(id string, ifname string, ip net.IP, rangeID string) (bool, error) { func (s *Store) Reserve(id string, ifname string, ip net.IP, rangeID string) (bool, error) {
fname := GetEscapedPath(s.dataDir, ip.String()) fname := GetEscapedPath(s.dataDir, ip.String())
f, err := os.OpenFile(fname, os.O_RDWR|os.O_EXCL|os.O_CREATE, 0644) f, err := os.OpenFile(fname, os.O_RDWR|os.O_EXCL|os.O_CREATE, 0o644)
if os.IsExist(err) { if os.IsExist(err) {
return false, nil return false, nil
} }
@ -77,7 +78,7 @@ func (s *Store) Reserve(id string, ifname string, ip net.IP, rangeID string) (bo
} }
// store the reserved ip in lastIPFile // store the reserved ip in lastIPFile
ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID) ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID)
err = ioutil.WriteFile(ipfile, []byte(ip.String()), 0644) err = os.WriteFile(ipfile, []byte(ip.String()), 0o644)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -87,25 +88,21 @@ func (s *Store) Reserve(id string, ifname string, ip net.IP, rangeID string) (bo
// LastReservedIP returns the last reserved IP if exists // LastReservedIP returns the last reserved IP if exists
func (s *Store) LastReservedIP(rangeID string) (net.IP, error) { func (s *Store) LastReservedIP(rangeID string) (net.IP, error) {
ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID) ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID)
data, err := ioutil.ReadFile(ipfile) data, err := os.ReadFile(ipfile)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return net.ParseIP(string(data)), nil return net.ParseIP(string(data)), nil
} }
func (s *Store) Release(ip net.IP) error { func (s *Store) FindByKey(match string) (bool, error) {
return os.Remove(GetEscapedPath(s.dataDir, ip.String()))
}
func (s *Store) FindByKey(id string, ifname string, match string) (bool, error) {
found := false found := false
err := filepath.Walk(s.dataDir, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(s.dataDir, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() { if err != nil || info.IsDir() {
return nil return nil
} }
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
return nil return nil
} }
@ -115,33 +112,31 @@ func (s *Store) FindByKey(id string, ifname string, match string) (bool, error)
return nil return nil
}) })
return found, err return found, err
} }
func (s *Store) FindByID(id string, ifname string) bool { func (s *Store) FindByID(id string, ifname string) bool {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
found := false
match := strings.TrimSpace(id) + LineBreak + ifname match := strings.TrimSpace(id) + LineBreak + ifname
found, err := s.FindByKey(id, ifname, match) found, err := s.FindByKey(match)
// Match anything created by this id // Match anything created by this id
if !found && err == nil { if !found && err == nil {
match := strings.TrimSpace(id) match := strings.TrimSpace(id)
found, err = s.FindByKey(id, ifname, match) found, _ = s.FindByKey(match)
} }
return found return found
} }
func (s *Store) ReleaseByKey(id string, ifname string, match string) (bool, error) { func (s *Store) ReleaseByKey(match string) (bool, error) {
found := false found := false
err := filepath.Walk(s.dataDir, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(s.dataDir, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() { if err != nil || info.IsDir() {
return nil return nil
} }
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
return nil return nil
} }
@ -154,20 +149,18 @@ func (s *Store) ReleaseByKey(id string, ifname string, match string) (bool, erro
return nil return nil
}) })
return found, err return found, err
} }
// N.B. This function eats errors to be tolerant and // N.B. This function eats errors to be tolerant and
// release as much as possible // release as much as possible
func (s *Store) ReleaseByID(id string, ifname string) error { func (s *Store) ReleaseByID(id string, ifname string) error {
found := false
match := strings.TrimSpace(id) + LineBreak + ifname match := strings.TrimSpace(id) + LineBreak + ifname
found, err := s.ReleaseByKey(id, ifname, match) found, err := s.ReleaseByKey(match)
// For backwards compatibility, look for files written by a previous version // For backwards compatibility, look for files written by a previous version
if !found && err == nil { if !found && err == nil {
match := strings.TrimSpace(id) match := strings.TrimSpace(id)
found, err = s.ReleaseByKey(id, ifname, match) _, err = s.ReleaseByKey(match)
} }
return err return err
} }
@ -185,7 +178,7 @@ func (s *Store) GetByID(id string, ifname string) []net.IP {
if err != nil || info.IsDir() { if err != nil || info.IsDir() {
return nil return nil
} }
data, err := ioutil.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
return nil return nil
} }
@ -203,7 +196,7 @@ func (s *Store) GetByID(id string, ifname string) []net.IP {
func GetEscapedPath(dataDir string, fname string) string { func GetEscapedPath(dataDir string, fname string) string {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
fname = strings.Replace(fname, ":", "_", -1) fname = strings.ReplaceAll(fname, ":", "_")
} }
return filepath.Join(dataDir, fname) return filepath.Join(dataDir, fname)
} }

View File

@ -15,10 +15,10 @@
package disk package disk
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestLock(t *testing.T) { func TestLock(t *testing.T) {

View File

@ -15,9 +15,10 @@
package disk package disk
import ( import (
"github.com/alexflint/go-filemutex"
"os" "os"
"path" "path"
"github.com/alexflint/go-filemutex"
) )
// FileLock wraps os.File to be used as a lock using flock // FileLock wraps os.File to be used as a lock using flock

View File

@ -15,23 +15,22 @@
package disk package disk
import ( import (
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("Lock Operations", func() { var _ = Describe("Lock Operations", func() {
It("locks a file path", func() { It("locks a file path", func() {
dir, err := ioutil.TempDir("", "") dir, err := os.MkdirTemp("", "")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
// create a dummy file to lock // create a dummy file to lock
path := filepath.Join(dir, "x") path := filepath.Join(dir, "x")
f, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0666) f, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0o666)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
err = f.Close() err = f.Close()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@ -47,7 +46,7 @@ var _ = Describe("Lock Operations", func() {
}) })
It("locks a folder path", func() { It("locks a folder path", func() {
dir, err := ioutil.TempDir("", "") dir, err := os.MkdirTemp("", "")
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(dir) defer os.RemoveAll(dir)

View File

@ -22,7 +22,6 @@ type Store interface {
Close() error Close() error
Reserve(id string, ifname string, ip net.IP, rangeID string) (bool, error) Reserve(id string, ifname string, ip net.IP, rangeID string) (bool, error)
LastReservedIP(rangeID string) (net.IP, error) LastReservedIP(rangeID string) (net.IP, error)
Release(ip net.IP) error
ReleaseByID(id string, ifname string) error ReleaseByID(id string, ifname string) error
GetByID(id string, ifname string) []net.IP GetByID(id string, ifname string) []net.IP
} }

View File

@ -45,7 +45,7 @@ func (s *FakeStore) Close() error {
return nil return nil
} }
func (s *FakeStore) Reserve(id string, ifname string, ip net.IP, rangeID string) (bool, error) { func (s *FakeStore) Reserve(id string, _ string, ip net.IP, rangeID string) (bool, error) {
key := ip.String() key := ip.String()
if _, ok := s.ipMap[key]; !ok { if _, ok := s.ipMap[key]; !ok {
s.ipMap[key] = id s.ipMap[key] = id
@ -63,12 +63,7 @@ func (s *FakeStore) LastReservedIP(rangeID string) (net.IP, error) {
return ip, nil return ip, nil
} }
func (s *FakeStore) Release(ip net.IP) error { func (s *FakeStore) ReleaseByID(id string, _ string) error {
delete(s.ipMap, ip.String())
return nil
}
func (s *FakeStore) ReleaseByID(id string, ifname string) error {
toDelete := []string{} toDelete := []string{}
for k, v := range s.ipMap { for k, v := range s.ipMap {
if v == id { if v == id {
@ -81,7 +76,7 @@ func (s *FakeStore) ReleaseByID(id string, ifname string) error {
return nil return nil
} }
func (s *FakeStore) GetByID(id string, ifname string) []net.IP { func (s *FakeStore) GetByID(id string, _ string) []net.IP {
var ips []net.IP var ips []net.IP
for k, v := range s.ipMap { for k, v := range s.ipMap {
if v == id { if v == id {

View File

@ -15,12 +15,12 @@
package main package main
import ( import (
"io/ioutil"
"os" "os"
"github.com/containernetworking/cni/pkg/types" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/containernetworking/cni/pkg/types"
) )
var _ = Describe("parsing resolv.conf", func() { var _ = Describe("parsing resolv.conf", func() {
@ -64,7 +64,7 @@ options four
}) })
func parse(contents string) (*types.DNS, error) { func parse(contents string) (*types.DNS, error) {
f, err := ioutil.TempFile("", "host_local_resolv") f, err := os.CreateTemp("", "host_local_resolv")
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -15,10 +15,10 @@
package main package main
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestHostLocal(t *testing.T) { func TestHostLocal(t *testing.T) {

View File

@ -16,20 +16,19 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"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/100" types100 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/testutils" "github.com/containernetworking/plugins/pkg/testutils"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/disk" "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/disk"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
) )
const LineBreak = "\r\n" const LineBreak = "\r\n"
@ -43,7 +42,7 @@ var _ = Describe("host-local Operations", func() {
BeforeEach(func() { BeforeEach(func() {
var err error var err error
tmpDir, err = ioutil.TempDir("", "host-local_test") tmpDir, err = os.MkdirTemp("", "host-local_test")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
tmpDir = filepath.ToSlash(tmpDir) tmpDir = filepath.ToSlash(tmpDir)
}) })
@ -58,7 +57,7 @@ var _ = Describe("host-local Operations", func() {
ver := ver ver := ver
It(fmt.Sprintf("[%s] allocates and releases addresses with ADD/DEL", ver), func() { It(fmt.Sprintf("[%s] allocates and releases addresses with ADD/DEL", ver), func() {
err := ioutil.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0644) err := os.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0o644)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
conf := fmt.Sprintf(`{ conf := fmt.Sprintf(`{
@ -115,7 +114,7 @@ var _ = Describe("host-local Operations", func() {
Gateway: net.ParseIP("2001:db8:1::1"), Gateway: net.ParseIP("2001:db8:1::1"),
}, },
)) ))
Expect(len(result.IPs)).To(Equal(2)) Expect(result.IPs).To(HaveLen(2))
for _, expectedRoute := range []*types.Route{ for _, expectedRoute := range []*types.Route{
{Dst: mustCIDR("0.0.0.0/0"), GW: nil}, {Dst: mustCIDR("0.0.0.0/0"), GW: nil},
@ -134,22 +133,22 @@ var _ = Describe("host-local Operations", func() {
} }
ipFilePath1 := filepath.Join(tmpDir, "mynet", "10.1.2.2") ipFilePath1 := filepath.Join(tmpDir, "mynet", "10.1.2.2")
contents, err := ioutil.ReadFile(ipFilePath1) contents, err := os.ReadFile(ipFilePath1)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal(args.ContainerID + LineBreak + ifname)) Expect(string(contents)).To(Equal(args.ContainerID + LineBreak + ifname))
ipFilePath2 := filepath.Join(tmpDir, disk.GetEscapedPath("mynet", "2001:db8:1::2")) ipFilePath2 := filepath.Join(tmpDir, disk.GetEscapedPath("mynet", "2001:db8:1::2"))
contents, err = ioutil.ReadFile(ipFilePath2) contents, err = os.ReadFile(ipFilePath2)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal(args.ContainerID + LineBreak + ifname)) Expect(string(contents)).To(Equal(args.ContainerID + LineBreak + ifname))
lastFilePath1 := filepath.Join(tmpDir, "mynet", "last_reserved_ip.0") lastFilePath1 := filepath.Join(tmpDir, "mynet", "last_reserved_ip.0")
contents, err = ioutil.ReadFile(lastFilePath1) contents, err = os.ReadFile(lastFilePath1)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal("10.1.2.2")) Expect(string(contents)).To(Equal("10.1.2.2"))
lastFilePath2 := filepath.Join(tmpDir, "mynet", "last_reserved_ip.1") lastFilePath2 := filepath.Join(tmpDir, "mynet", "last_reserved_ip.1")
contents, err = ioutil.ReadFile(lastFilePath2) contents, err = os.ReadFile(lastFilePath2)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal("2001:db8:1::2")) Expect(string(contents)).To(Equal("2001:db8:1::2"))
// Release the IP // Release the IP
@ -167,7 +166,7 @@ var _ = Describe("host-local Operations", func() {
It(fmt.Sprintf("[%s] allocates and releases addresses on specific interface with ADD/DEL", ver), func() { It(fmt.Sprintf("[%s] allocates and releases addresses on specific interface with ADD/DEL", ver), func() {
const ifname1 string = "eth1" const ifname1 string = "eth1"
err := ioutil.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0644) err := os.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0o644)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
conf0 := fmt.Sprintf(`{ conf0 := fmt.Sprintf(`{
@ -239,12 +238,12 @@ var _ = Describe("host-local Operations", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
ipFilePath0 := filepath.Join(tmpDir, "mynet0", "10.1.2.2") ipFilePath0 := filepath.Join(tmpDir, "mynet0", "10.1.2.2")
contents, err := ioutil.ReadFile(ipFilePath0) contents, err := os.ReadFile(ipFilePath0)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal(args0.ContainerID + LineBreak + ifname)) Expect(string(contents)).To(Equal(args0.ContainerID + LineBreak + ifname))
ipFilePath1 := filepath.Join(tmpDir, "mynet1", "10.2.2.2") ipFilePath1 := filepath.Join(tmpDir, "mynet1", "10.2.2.2")
contents, err = ioutil.ReadFile(ipFilePath1) contents, err = os.ReadFile(ipFilePath1)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal(args1.ContainerID + LineBreak + ifname1)) Expect(string(contents)).To(Equal(args1.ContainerID + LineBreak + ifname1))
@ -257,7 +256,7 @@ var _ = Describe("host-local Operations", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
// reread ipFilePath1, ensure that ifname1 didn't get deleted // reread ipFilePath1, ensure that ifname1 didn't get deleted
contents, err = ioutil.ReadFile(ipFilePath1) contents, err = os.ReadFile(ipFilePath1)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal(args1.ContainerID + LineBreak + ifname1)) Expect(string(contents)).To(Equal(args1.ContainerID + LineBreak + ifname1))
@ -311,7 +310,7 @@ var _ = Describe("host-local Operations", func() {
result0, err := types100.GetResult(r0) result0, err := types100.GetResult(r0)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(result0.IPs)).Should(Equal(1)) Expect(result0.IPs).Should(HaveLen(1))
Expect(result0.IPs[0].Address.String()).Should(Equal("10.1.2.2/24")) Expect(result0.IPs[0].Address.String()).Should(Equal("10.1.2.2/24"))
// Allocate the IP with the same container ID // Allocate the IP with the same container ID
@ -331,7 +330,7 @@ var _ = Describe("host-local Operations", func() {
result1, err := types100.GetResult(r1) result1, err := types100.GetResult(r1)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(result1.IPs)).Should(Equal(1)) Expect(result1.IPs).Should(HaveLen(1))
Expect(result1.IPs[0].Address.String()).Should(Equal("10.1.2.3/24")) Expect(result1.IPs[0].Address.String()).Should(Equal("10.1.2.3/24"))
// Allocate the IP with the same container ID again // Allocate the IP with the same container ID again
@ -357,7 +356,7 @@ var _ = Describe("host-local Operations", func() {
}) })
It(fmt.Sprintf("[%s] verify DEL works on backwards compatible allocate", ver), func() { It(fmt.Sprintf("[%s] verify DEL works on backwards compatible allocate", ver), func() {
err := ioutil.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0644) err := os.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0o644)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
conf := fmt.Sprintf(`{ conf := fmt.Sprintf(`{
@ -395,10 +394,10 @@ var _ = Describe("host-local Operations", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
ipFilePath := filepath.Join(tmpDir, "mynet", "10.1.2.2") ipFilePath := filepath.Join(tmpDir, "mynet", "10.1.2.2")
contents, err := ioutil.ReadFile(ipFilePath) contents, err := os.ReadFile(ipFilePath)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal(args.ContainerID + LineBreak + ifname)) Expect(string(contents)).To(Equal(args.ContainerID + LineBreak + ifname))
err = ioutil.WriteFile(ipFilePath, []byte(strings.TrimSpace(args.ContainerID)), 0644) err = os.WriteFile(ipFilePath, []byte(strings.TrimSpace(args.ContainerID)), 0o644)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = testutils.CmdDelWithArgs(args, func() error { err = testutils.CmdDelWithArgs(args, func() error {
@ -466,7 +465,7 @@ var _ = Describe("host-local Operations", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
ipFilePath := filepath.Join(tmpDir, "mynet", result.IPs[0].Address.IP.String()) ipFilePath := filepath.Join(tmpDir, "mynet", result.IPs[0].Address.IP.String())
contents, err := ioutil.ReadFile(ipFilePath) contents, err := os.ReadFile(ipFilePath)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal("dummy" + LineBreak + ifname)) Expect(string(contents)).To(Equal("dummy" + LineBreak + ifname))
@ -505,7 +504,7 @@ var _ = Describe("host-local Operations", func() {
return cmdAdd(args) return cmdAdd(args)
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(strings.Index(string(out), "Error retriving last reserved ip")).To(Equal(-1)) Expect(strings.Index(string(out), "Error retrieving last reserved ip")).To(Equal(-1))
}) })
It(fmt.Sprintf("[%s] allocates a custom IP when requested by config args", ver), func() { It(fmt.Sprintf("[%s] allocates a custom IP when requested by config args", ver), func() {
@ -547,7 +546,7 @@ var _ = Describe("host-local Operations", func() {
}) })
It(fmt.Sprintf("[%s] allocates custom IPs from multiple ranges", ver), func() { It(fmt.Sprintf("[%s] allocates custom IPs from multiple ranges", ver), func() {
err := ioutil.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0644) err := os.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0o644)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
conf := fmt.Sprintf(`{ conf := fmt.Sprintf(`{
@ -595,7 +594,7 @@ var _ = Describe("host-local Operations", func() {
}) })
It(fmt.Sprintf("[%s] allocates custom IPs from multiple protocols", ver), func() { It(fmt.Sprintf("[%s] allocates custom IPs from multiple protocols", ver), func() {
err := ioutil.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0644) err := os.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0o644)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
conf := fmt.Sprintf(`{ conf := fmt.Sprintf(`{

View File

@ -19,14 +19,13 @@ import (
"net" "net"
"strings" "strings"
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/disk"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" 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"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/disk"
) )
func main() { func main() {
@ -34,7 +33,6 @@ func main() {
} }
func cmdCheck(args *skel.CmdArgs) error { func cmdCheck(args *skel.CmdArgs) error {
ipamConf, _, err := allocator.LoadIPAMConfig(args.StdinData, args.Args) ipamConf, _, err := allocator.LoadIPAMConfig(args.StdinData, args.Args)
if err != nil { if err != nil {
return err return err
@ -48,8 +46,8 @@ func cmdCheck(args *skel.CmdArgs) error {
} }
defer store.Close() defer store.Close()
containerIpFound := store.FindByID(args.ContainerID, args.IfName) containerIPFound := store.FindByID(args.ContainerID, args.IfName)
if containerIpFound == false { if !containerIPFound {
return fmt.Errorf("host-local: Failed to find address added by container %v", args.ContainerID) return fmt.Errorf("host-local: Failed to find address added by container %v", args.ContainerID)
} }
@ -84,7 +82,7 @@ func cmdAdd(args *skel.CmdArgs) error {
// Store all requested IPs in a map, so we can easily remove ones we use // Store all requested IPs in a map, so we can easily remove ones we use
// and error if some remain // and error if some remain
requestedIPs := map[string]net.IP{} //net.IP cannot be a key requestedIPs := map[string]net.IP{} // net.IP cannot be a key
for _, ip := range ipamConf.IPArgs { for _, ip := range ipamConf.IPArgs {
requestedIPs[ip.String()] = ip requestedIPs[ip.String()] = ip

View File

@ -276,7 +276,7 @@ func cmdAdd(args *skel.CmdArgs) error {
return types.PrintResult(result, confVersion) return types.PrintResult(result, confVersion)
} }
func cmdDel(args *skel.CmdArgs) error { func cmdDel(_ *skel.CmdArgs) error {
// Nothing required because of no resource allocation in static plugin. // Nothing required because of no resource allocation in static plugin.
return nil return nil
} }

View File

@ -17,7 +17,7 @@ package main_test
import ( import (
"testing" "testing"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )

View File

@ -19,13 +19,13 @@ import (
"net" "net"
"strings" "strings"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
types100 "github.com/containernetworking/cni/pkg/types/100" types100 "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/gomega"
) )
var _ = Describe("static Operations", func() { var _ = Describe("static Operations", func() {
@ -97,7 +97,7 @@ var _ = Describe("static Operations", func() {
Gateway: net.ParseIP("3ffe:ffff:0::1"), Gateway: net.ParseIP("3ffe:ffff:0::1"),
}, },
)) ))
Expect(len(result.IPs)).To(Equal(2)) Expect(result.IPs).To(HaveLen(2))
Expect(result.Routes).To(Equal([]*types.Route{ Expect(result.Routes).To(Equal([]*types.Route{
{Dst: mustCIDR("0.0.0.0/0")}, {Dst: mustCIDR("0.0.0.0/0")},
@ -206,7 +206,7 @@ var _ = Describe("static Operations", func() {
Gateway: net.ParseIP("10.10.0.254"), Gateway: net.ParseIP("10.10.0.254"),
})) }))
Expect(len(result.IPs)).To(Equal(1)) Expect(result.IPs).To(HaveLen(1))
Expect(result.Routes).To(Equal([]*types.Route{ Expect(result.Routes).To(Equal([]*types.Route{
{Dst: mustCIDR("0.0.0.0/0")}, {Dst: mustCIDR("0.0.0.0/0")},
@ -272,7 +272,7 @@ var _ = Describe("static Operations", func() {
Gateway: nil, Gateway: nil,
})) }))
Expect(len(result.IPs)).To(Equal(2)) Expect(result.IPs).To(HaveLen(2))
// Release the IP // Release the IP
err = testutils.CmdDelWithArgs(args, func() error { err = testutils.CmdDelWithArgs(args, func() error {
@ -337,7 +337,7 @@ var _ = Describe("static Operations", func() {
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
}, },
)) ))
Expect(len(result.IPs)).To(Equal(2)) Expect(result.IPs).To(HaveLen(2))
Expect(result.Routes).To(Equal([]*types.Route{ Expect(result.Routes).To(Equal([]*types.Route{
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, {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")}, {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
@ -407,7 +407,7 @@ var _ = Describe("static Operations", func() {
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
}, },
)) ))
Expect(len(result.IPs)).To(Equal(2)) Expect(result.IPs).To(HaveLen(2))
Expect(result.Routes).To(Equal([]*types.Route{ Expect(result.Routes).To(Equal([]*types.Route{
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, {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")}, {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},
@ -482,7 +482,7 @@ var _ = Describe("static Operations", func() {
Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), Address: mustCIDR("3ffe:ffff:0:01ff::1/64"),
}, },
)) ))
Expect(len(result.IPs)).To(Equal(2)) Expect(result.IPs).To(HaveLen(2))
Expect(result.Routes).To(Equal([]*types.Route{ Expect(result.Routes).To(Equal([]*types.Route{
{Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, {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")}, {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")},

View File

@ -6,6 +6,7 @@ plugins/main/loopback
plugins/main/macvlan plugins/main/macvlan
plugins/main/ptp plugins/main/ptp
plugins/main/vlan plugins/main/vlan
plugins/main/dummy
plugins/meta/portmap plugins/meta/portmap
plugins/meta/tuning plugins/meta/tuning
plugins/meta/bandwidth plugins/meta/bandwidth

View File

@ -21,6 +21,7 @@ import (
"net" "net"
"os" "os"
"runtime" "runtime"
"sort"
"syscall" "syscall"
"time" "time"
@ -55,6 +56,8 @@ type NetConf struct {
HairpinMode bool `json:"hairpinMode"` HairpinMode bool `json:"hairpinMode"`
PromiscMode bool `json:"promiscMode"` PromiscMode bool `json:"promiscMode"`
Vlan int `json:"vlan"` Vlan int `json:"vlan"`
VlanTrunk []*VlanTrunk `json:"vlanTrunk,omitempty"`
PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
MacSpoofChk bool `json:"macspoofchk,omitempty"` MacSpoofChk bool `json:"macspoofchk,omitempty"`
EnableDad bool `json:"enabledad,omitempty"` EnableDad bool `json:"enabledad,omitempty"`
@ -66,6 +69,13 @@ type NetConf struct {
} `json:"runtimeConfig,omitempty"` } `json:"runtimeConfig,omitempty"`
mac string mac string
vlans []int
}
type VlanTrunk struct {
MinID *int `json:"minID,omitempty"`
MaxID *int `json:"maxID,omitempty"`
ID *int `json:"id,omitempty"`
} }
type BridgeArgs struct { type BridgeArgs struct {
@ -94,6 +104,8 @@ func init() {
func loadNetConf(bytes []byte, envArgs string) (*NetConf, string, error) { func loadNetConf(bytes []byte, envArgs string) (*NetConf, string, error) {
n := &NetConf{ n := &NetConf{
BrName: defaultBrName, BrName: defaultBrName,
// Set default value equal to true to maintain existing behavior.
PreserveDefaultVlan: true,
} }
if err := json.Unmarshal(bytes, n); err != nil { if err := json.Unmarshal(bytes, n); err != nil {
return nil, "", fmt.Errorf("failed to load netconf: %v", err) return nil, "", fmt.Errorf("failed to load netconf: %v", err)
@ -101,6 +113,17 @@ func loadNetConf(bytes []byte, envArgs string) (*NetConf, string, error) {
if n.Vlan < 0 || n.Vlan > 4094 { if n.Vlan < 0 || n.Vlan > 4094 {
return nil, "", fmt.Errorf("invalid VLAN ID %d (must be between 0 and 4094)", n.Vlan) return nil, "", fmt.Errorf("invalid VLAN ID %d (must be between 0 and 4094)", n.Vlan)
} }
var err error
n.vlans, err = collectVlanTrunk(n.VlanTrunk)
if err != nil {
// fail to parsing
return nil, "", err
}
// Currently bridge CNI only support access port(untagged only) or trunk port(tagged only)
if n.Vlan > 0 && n.vlans != nil {
return nil, "", errors.New("cannot set vlan and vlanTrunk at the same time")
}
if envArgs != "" { if envArgs != "" {
e := MacEnvArgs{} e := MacEnvArgs{}
@ -124,12 +147,66 @@ func loadNetConf(bytes []byte, envArgs string) (*NetConf, string, error) {
return n, n.CNIVersion, nil return n, n.CNIVersion, nil
} }
// This method is copied from https://github.com/k8snetworkplumbingwg/ovs-cni/blob/v0.27.2/pkg/plugin/plugin.go
func collectVlanTrunk(vlanTrunk []*VlanTrunk) ([]int, error) {
if vlanTrunk == nil {
return nil, nil
}
vlanMap := make(map[int]struct{})
for _, item := range vlanTrunk {
var minID int
var maxID int
var ID int
switch {
case item.MinID != nil && item.MaxID != nil:
minID = *item.MinID
if minID <= 0 || minID > 4094 {
return nil, errors.New("incorrect trunk minID parameter")
}
maxID = *item.MaxID
if maxID <= 0 || maxID > 4094 {
return nil, errors.New("incorrect trunk maxID parameter")
}
if maxID < minID {
return nil, errors.New("minID is greater than maxID in trunk parameter")
}
for v := minID; v <= maxID; v++ {
vlanMap[v] = struct{}{}
}
case item.MinID == nil && item.MaxID != nil:
return nil, errors.New("minID and maxID should be configured simultaneously, minID is missing")
case item.MinID != nil && item.MaxID == nil:
return nil, errors.New("minID and maxID should be configured simultaneously, maxID is missing")
}
// single vid
if item.ID != nil {
ID = *item.ID
if ID <= 0 || ID > 4094 {
return nil, errors.New("incorrect trunk id parameter")
}
vlanMap[ID] = struct{}{}
}
}
if len(vlanMap) == 0 {
return nil, nil
}
vlans := make([]int, 0, len(vlanMap))
for k := range vlanMap {
vlans = append(vlans, k)
}
sort.Slice(vlans, func(i int, j int) bool { return vlans[i] < vlans[j] })
return vlans, nil
}
// calcGateways processes the results from the IPAM plugin and does the // calcGateways processes the results from the IPAM plugin and does the
// following for each IP family: // following for each IP family:
// - Calculates and compiles a list of gateway addresses // - Calculates and compiles a list of gateway addresses
// - Adds a default route if needed // - Adds a default route if needed
func calcGateways(result *current.Result, n *NetConf) (*gwInfo, *gwInfo, error) { func calcGateways(result *current.Result, n *NetConf) (*gwInfo, *gwInfo, error) {
gwsV4 := &gwInfo{} gwsV4 := &gwInfo{}
gwsV6 := &gwInfo{} gwsV6 := &gwInfo{}
@ -300,8 +377,8 @@ func ensureBridge(brName string, mtu int, promiscMode, vlanFiltering bool) (*net
return br, nil return br, nil
} }
func ensureVlanInterface(br *netlink.Bridge, vlanId int) (netlink.Link, error) { func ensureVlanInterface(br *netlink.Bridge, vlanID int, preserveDefaultVlan bool) (netlink.Link, error) {
name := fmt.Sprintf("%s.%d", br.Name, vlanId) name := fmt.Sprintf("%s.%d", br.Name, vlanID)
brGatewayVeth, err := netlink.LinkByName(name) brGatewayVeth, err := netlink.LinkByName(name)
if err != nil { if err != nil {
@ -314,7 +391,7 @@ func ensureVlanInterface(br *netlink.Bridge, vlanId int) (netlink.Link, error) {
return nil, fmt.Errorf("faild to find host namespace: %v", err) return nil, fmt.Errorf("faild to find host namespace: %v", err)
} }
_, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanId, "") _, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanID, nil, preserveDefaultVlan, "")
if err != nil { if err != nil {
return nil, fmt.Errorf("faild to create vlan gateway %q: %v", name, err) return nil, fmt.Errorf("faild to create vlan gateway %q: %v", name, err)
} }
@ -333,7 +410,7 @@ func ensureVlanInterface(br *netlink.Bridge, vlanId int) (netlink.Link, error) {
return brGatewayVeth, nil return brGatewayVeth, nil
} }
func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int, mac string) (*current.Interface, *current.Interface, error) { func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int, vlans []int, preserveDefaultVlan bool, mac string) (*current.Interface, *current.Interface, error) {
contIface := &current.Interface{} contIface := &current.Interface{}
hostIface := &current.Interface{} hostIface := &current.Interface{}
@ -370,6 +447,14 @@ func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairp
return nil, nil, fmt.Errorf("failed to setup hairpin mode for %v: %v", hostVeth.Attrs().Name, err) return nil, nil, fmt.Errorf("failed to setup hairpin mode for %v: %v", hostVeth.Attrs().Name, err)
} }
if (vlanID != 0 || len(vlans) > 0) && !preserveDefaultVlan {
err = removeDefaultVlan(hostVeth)
if err != nil {
return nil, nil, fmt.Errorf("failed to remove default vlan on interface %q: %v", hostIface.Name, err)
}
}
// Currently bridge CNI only support access port(untagged only) or trunk port(tagged only)
if vlanID != 0 { if vlanID != 0 {
err = netlink.BridgeVlanAdd(hostVeth, uint16(vlanID), true, true, false, true) err = netlink.BridgeVlanAdd(hostVeth, uint16(vlanID), true, true, false, true)
if err != nil { if err != nil {
@ -377,9 +462,35 @@ func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairp
} }
} }
for _, v := range vlans {
err = netlink.BridgeVlanAdd(hostVeth, uint16(v), false, false, false, true)
if err != nil {
return nil, nil, fmt.Errorf("failed to setup vlan tag on interface %q: %w", hostIface.Name, err)
}
}
return hostIface, contIface, nil return hostIface, contIface, nil
} }
func removeDefaultVlan(hostVeth netlink.Link) error {
vlanInfo, err := netlink.BridgeVlanList()
if err != nil {
return err
}
brVlanInfo, ok := vlanInfo[int32(hostVeth.Attrs().Index)]
if ok {
for _, info := range brVlanInfo {
err = netlink.BridgeVlanDel(hostVeth, info.Vid, false, false, false, true)
if err != nil {
return err
}
}
}
return nil
}
func calcGatewayIP(ipn *net.IPNet) net.IP { func calcGatewayIP(ipn *net.IPNet) net.IP {
nid := ipn.IP.Mask(ipn.Mask) nid := ipn.IP.Mask(ipn.Mask)
return ip.NextIP(nid) return ip.NextIP(nid)
@ -387,7 +498,7 @@ func calcGatewayIP(ipn *net.IPNet) net.IP {
func setupBridge(n *NetConf) (*netlink.Bridge, *current.Interface, error) { func setupBridge(n *NetConf) (*netlink.Bridge, *current.Interface, error) {
vlanFiltering := false vlanFiltering := false
if n.Vlan != 0 { if n.Vlan != 0 || n.VlanTrunk != nil {
vlanFiltering = true vlanFiltering = true
} }
// create bridge if necessary // create bridge if necessary
@ -410,7 +521,7 @@ func enableIPForward(family int) error {
} }
func cmdAdd(args *skel.CmdArgs) error { func cmdAdd(args *skel.CmdArgs) error {
var success bool = false success := false
n, cniVersion, err := loadNetConf(args.StdinData, args.Args) n, cniVersion, err := loadNetConf(args.StdinData, args.Args)
if err != nil { if err != nil {
@ -424,7 +535,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
if n.HairpinMode && n.PromiscMode { if n.HairpinMode && n.PromiscMode {
return fmt.Errorf("cannot set hairpin mode and promiscuous mode at the same time.") return fmt.Errorf("cannot set hairpin mode and promiscuous mode at the same time")
} }
br, brInterface, err := setupBridge(n) br, brInterface, err := setupBridge(n)
@ -438,7 +549,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
defer netns.Close() defer netns.Close()
hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan, n.mac) hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan, n.vlans, n.PreserveDefaultVlan, n.mac)
if err != nil { if err != nil {
return err return err
} }
@ -489,6 +600,7 @@ func cmdAdd(args *skel.CmdArgs) error {
result.IPs = ipamResult.IPs result.IPs = ipamResult.IPs
result.Routes = ipamResult.Routes result.Routes = ipamResult.Routes
result.DNS = ipamResult.DNS
if len(result.IPs) == 0 { if len(result.IPs) == 0 {
return errors.New("IPAM plugin returned missing IP config") return errors.New("IPAM plugin returned missing IP config")
@ -511,32 +623,11 @@ func cmdAdd(args *skel.CmdArgs) error {
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1") _, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
// Add the IP to the interface // Add the IP to the interface
if err := ipam.ConfigureIface(args.IfName, result); err != nil { return ipam.ConfigureIface(args.IfName, result)
return err
}
return nil
}); err != nil { }); err != nil {
return err return err
} }
// check bridge port state
retries := []int{0, 50, 500, 1000, 1000}
for idx, sleep := range retries {
time.Sleep(time.Duration(sleep) * time.Millisecond)
hostVeth, err := netlink.LinkByName(hostInterface.Name)
if err != nil {
return err
}
if hostVeth.Attrs().OperState == netlink.OperUp {
break
}
if idx == len(retries)-1 {
return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState)
}
}
if n.IsGW { if n.IsGW {
var firstV4Addr net.IP var firstV4Addr net.IP
var vlanInterface *current.Interface var vlanInterface *current.Interface
@ -547,14 +638,16 @@ func cmdAdd(args *skel.CmdArgs) error {
firstV4Addr = gw.IP firstV4Addr = gw.IP
} }
if n.Vlan != 0 { if n.Vlan != 0 {
vlanIface, err := ensureVlanInterface(br, n.Vlan) vlanIface, err := ensureVlanInterface(br, n.Vlan, n.PreserveDefaultVlan)
if err != nil { if err != nil {
return fmt.Errorf("failed to create vlan interface: %v", err) return fmt.Errorf("failed to create vlan interface: %v", err)
} }
if vlanInterface == nil { if vlanInterface == nil {
vlanInterface = &current.Interface{Name: vlanIface.Attrs().Name, vlanInterface = &current.Interface{
Mac: vlanIface.Attrs().HardwareAddr.String()} Name: vlanIface.Attrs().Name,
Mac: vlanIface.Attrs().HardwareAddr.String(),
}
result.Interfaces = append(result.Interfaces, vlanInterface) result.Interfaces = append(result.Interfaces, vlanInterface)
} }
@ -603,6 +696,29 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
} }
var hostVeth netlink.Link
// check bridge port state
retries := []int{0, 50, 500, 1000, 1000}
for idx, sleep := range retries {
time.Sleep(time.Duration(sleep) * time.Millisecond)
hostVeth, err = netlink.LinkByName(hostInterface.Name)
if err != nil {
return err
}
if hostVeth.Attrs().OperState == netlink.OperUp {
break
}
if idx == len(retries)-1 {
return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState)
}
}
// In certain circumstances, the host-side of the veth may change addrs
hostInterface.Mac = hostVeth.Attrs().HardwareAddr.String()
// Refetch the bridge since its MAC address may change when the first // Refetch the bridge since its MAC address may change when the first
// veth is added or after its IP address is set // veth is added or after its IP address is set
br, err = bridgeByName(n.BrName) br, err = bridgeByName(n.BrName)
@ -611,18 +727,29 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
brInterface.Mac = br.Attrs().HardwareAddr.String() brInterface.Mac = br.Attrs().HardwareAddr.String()
result.DNS = n.DNS
// Return an error requested by testcases, if any // Return an error requested by testcases, if any
if debugPostIPAMError != nil { if debugPostIPAMError != nil {
return debugPostIPAMError return debugPostIPAMError
} }
// Use incoming DNS settings if provided, otherwise use the
// settings that were already configued by the IPAM plugin
if dnsConfSet(n.DNS) {
result.DNS = n.DNS
}
success = true success = true
return types.PrintResult(result, cniVersion) return types.PrintResult(result, cniVersion)
} }
func dnsConfSet(dnsConf types.DNS) bool {
return dnsConf.Nameservers != nil ||
dnsConf.Search != nil ||
dnsConf.Options != nil ||
dnsConf.Domain != ""
}
func cmdDel(args *skel.CmdArgs) error { func cmdDel(args *skel.CmdArgs) error {
n, _, err := loadNetConf(args.StdinData, args.Args) n, _, err := loadNetConf(args.StdinData, args.Args)
if err != nil { if err != nil {
@ -631,14 +758,17 @@ func cmdDel(args *skel.CmdArgs) error {
isLayer3 := n.IPAM.Type != "" isLayer3 := n.IPAM.Type != ""
ipamDel := func() error {
if isLayer3 { if isLayer3 {
if err := ipam.ExecDel(n.IPAM.Type, args.StdinData); err != nil { if err := ipam.ExecDel(n.IPAM.Type, args.StdinData); err != nil {
return err return err
} }
} }
return nil
}
if args.Netns == "" { if args.Netns == "" {
return nil return ipamDel()
} }
// There is a netns so try to clean up. Delete can be called multiple times // There is a netns so try to clean up. Delete can be called multiple times
@ -660,11 +790,16 @@ func cmdDel(args *skel.CmdArgs) error {
// https://github.com/kubernetes/kubernetes/issues/43014#issuecomment-287164444 // https://github.com/kubernetes/kubernetes/issues/43014#issuecomment-287164444
_, ok := err.(ns.NSPathNotExistErr) _, ok := err.(ns.NSPathNotExistErr)
if ok { if ok {
return nil return ipamDel()
} }
return err return err
} }
// call ipam.ExecDel after clean up device in netns
if err := ipamDel(); err != nil {
return err
}
if n.MacSpoofChk { if n.MacSpoofChk {
sc := link.NewSpoofChecker("", "", uniqueID(args.ContainerID, args.IfName)) sc := link.NewSpoofChecker("", "", uniqueID(args.ContainerID, args.IfName))
if err := sc.Teardown(); err != nil { if err := sc.Teardown(); err != nil {
@ -698,7 +833,6 @@ type cniBridgeIf struct {
} }
func validateInterface(intf current.Interface, expectInSb bool) (cniBridgeIf, netlink.Link, error) { func validateInterface(intf current.Interface, expectInSb bool) (cniBridgeIf, netlink.Link, error) {
ifFound := cniBridgeIf{found: false} ifFound := cniBridgeIf{found: false}
if intf.Name == "" { if intf.Name == "" {
return ifFound, nil, fmt.Errorf("Interface name missing ") return ifFound, nil, fmt.Errorf("Interface name missing ")
@ -723,7 +857,6 @@ func validateInterface(intf current.Interface, expectInSb bool) (cniBridgeIf, ne
} }
func validateCniBrInterface(intf current.Interface, n *NetConf) (cniBridgeIf, error) { func validateCniBrInterface(intf current.Interface, n *NetConf) (cniBridgeIf, error) {
brFound, link, err := validateInterface(intf, false) brFound, link, err := validateInterface(intf, false)
if err != nil { if err != nil {
return brFound, err return brFound, err
@ -755,7 +888,6 @@ func validateCniBrInterface(intf current.Interface, n *NetConf) (cniBridgeIf, er
} }
func validateCniVethInterface(intf *current.Interface, brIf cniBridgeIf, contIf cniBridgeIf) (cniBridgeIf, error) { func validateCniVethInterface(intf *current.Interface, brIf cniBridgeIf, contIf cniBridgeIf) (cniBridgeIf, error) {
vethFound, link, err := validateInterface(*intf, false) vethFound, link, err := validateInterface(*intf, false)
if err != nil { if err != nil {
return vethFound, err return vethFound, err
@ -799,7 +931,6 @@ func validateCniVethInterface(intf *current.Interface, brIf cniBridgeIf, contIf
} }
func validateCniContainerInterface(intf current.Interface) (cniBridgeIf, error) { func validateCniContainerInterface(intf current.Interface) (cniBridgeIf, error) {
vethFound, link, err := validateInterface(intf, true) vethFound, link, err := validateInterface(intf, true)
if err != nil { if err != nil {
return vethFound, err return vethFound, err
@ -828,7 +959,6 @@ func validateCniContainerInterface(intf current.Interface) (cniBridgeIf, error)
} }
func cmdCheck(args *skel.CmdArgs) error { func cmdCheck(args *skel.CmdArgs) error {
n, _, err := loadNetConf(args.StdinData, args.Args) n, _, err := loadNetConf(args.StdinData, args.Args)
if err != nil { if err != nil {
return err return err
@ -935,7 +1065,7 @@ func cmdCheck(args *skel.CmdArgs) error {
} }
// Check prevResults for ips, routes and dns against values found in the container // Check prevResults for ips, routes and dns against values found in the container
if err := netns.Do(func(_ ns.NetNS) error { return netns.Do(func(_ ns.NetNS) error {
err = ip.ValidateExpectedInterfaceIPs(args.IfName, result.IPs) err = ip.ValidateExpectedInterfaceIPs(args.IfName, result.IPs)
if err != nil { if err != nil {
return err return err
@ -946,11 +1076,7 @@ func cmdCheck(args *skel.CmdArgs) error {
return err return err
} }
return nil return nil
}); err != nil { })
return err
}
return nil
} }
func uniqueID(containerID, cniIface string) string { func uniqueID(containerID, cniIface string) string {

View File

@ -15,13 +15,26 @@
package main package main
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var (
resolvConf string
err error
) )
func TestBridge(t *testing.T) { func TestBridge(t *testing.T) {
RegisterFailHandler(Fail) RegisterFailHandler(Fail)
resolvConf, err = newResolvConf()
Expect(err).NotTo(HaveOccurred())
RunSpecs(t, "plugins/main/bridge") RunSpecs(t, "plugins/main/bridge")
} }
var _ = AfterSuite(func() {
deleteResolvConf(resolvConf)
})

View File

@ -17,13 +17,15 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"strings" "strings"
"github.com/coreos/go-iptables/iptables" "github.com/coreos/go-iptables/iptables"
"github.com/networkplumbing/go-nft/nft" "github.com/networkplumbing/go-nft/nft"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
@ -33,18 +35,14 @@ import (
"github.com/containernetworking/plugins/pkg/ip" "github.com/containernetworking/plugins/pkg/ip"
"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/vishvananda/netlink"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator" "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
) )
const ( const (
BRNAME = "bridge0" BRNAME = "bridge0"
BRNAMEVLAN = "bridge0.100" BRNAMEVLAN = "bridge0.100"
IFNAME = "eth0" IFNAME = "eth0"
NAMESERVER = "192.0.2.0"
) )
type Net struct { type Net struct {
@ -53,10 +51,11 @@ type Net struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
BrName string `json:"bridge"` BrName string `json:"bridge"`
IPAM *allocator.IPAMConfig `json:"ipam"` IPAM *allocator.IPAMConfig `json:"ipam"`
//RuntimeConfig struct { // The capability arg // RuntimeConfig struct { // The capability arg
// IPRanges []RangeSet `json:"ipRanges,omitempty"` // IPRanges []RangeSet `json:"ipRanges,omitempty"`
//} `json:"runtimeConfig,omitempty"` // Args *struct {
//Args *struct { // } `json:"runtimeConfig,omitempty"`
// A *IPAMArgs `json:"cni"` // A *IPAMArgs `json:"cni"`
DNS types.DNS `json:"dns"` DNS types.DNS `json:"dns"`
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
@ -70,10 +69,13 @@ type testCase struct {
subnet string // Single subnet config: Subnet CIDR subnet string // Single subnet config: Subnet CIDR
gateway string // Single subnet config: Gateway gateway string // Single subnet config: Gateway
ranges []rangeInfo // Ranges list (multiple subnets config) ranges []rangeInfo // Ranges list (multiple subnets config)
resolvConf string // host-local resolvConf file path
isGW bool isGW bool
isLayer2 bool isLayer2 bool
expGWCIDRs []string // Expected gateway addresses in CIDR form expGWCIDRs []string // Expected gateway addresses in CIDR form
vlan int vlan int
vlanTrunk []*VlanTrunk
removeDefaultVlan bool
ipMasq bool ipMasq bool
macspoofchk bool macspoofchk bool
AddErr020 string AddErr020 string
@ -129,6 +131,26 @@ const (
vlan = `, vlan = `,
"vlan": %d` "vlan": %d`
vlanTrunkStartStr = `,
"vlanTrunk": [`
vlanTrunk = `
{
"id": %d
}`
vlanTrunkRange = `
{
"minID": %d,
"maxID": %d
}`
vlanTrunkEndStr = `
]`
preserveDefaultVlan = `,
"preserveDefaultVlan": false`
netDefault = `, netDefault = `,
"isDefaultGateway": true` "isDefaultGateway": true`
@ -139,6 +161,9 @@ const (
ipamDataDirStr = `, ipamDataDirStr = `,
"dataDir": "%s"` "dataDir": "%s"`
ipamResolvConfStr = `,
"resolvConf": "%s"`
ipMasqConfStr = `, ipMasqConfStr = `,
"ipMasq": %t` "ipMasq": %t`
@ -188,7 +213,28 @@ func (tc testCase) netConfJSON(dataDir string) string {
conf := fmt.Sprintf(netConfStr, tc.cniVersion, BRNAME) conf := fmt.Sprintf(netConfStr, tc.cniVersion, BRNAME)
if tc.vlan != 0 { if tc.vlan != 0 {
conf += fmt.Sprintf(vlan, tc.vlan) conf += fmt.Sprintf(vlan, tc.vlan)
if tc.removeDefaultVlan {
conf += preserveDefaultVlan
} }
}
if tc.isLayer2 && tc.vlanTrunk != nil {
conf += vlanTrunkStartStr
for i, vlan := range tc.vlanTrunk {
if i > 0 {
conf += ","
}
if vlan.ID != nil {
conf += fmt.Sprintf(vlanTrunk, *vlan.ID)
}
if vlan.MinID != nil && vlan.MaxID != nil {
conf += fmt.Sprintf(vlanTrunkRange, *vlan.MinID, *vlan.MaxID)
}
}
conf += vlanTrunkEndStr
}
if tc.ipMasq { if tc.ipMasq {
conf += tc.ipMasqConfig() conf += tc.ipMasqConfig()
} }
@ -215,6 +261,9 @@ func (tc testCase) netConfJSON(dataDir string) string {
if tc.ranges != nil { if tc.ranges != nil {
conf += tc.rangesConfig() conf += tc.rangesConfig()
} }
if tc.resolvConf != "" {
conf += tc.resolvConfConfig()
}
conf += ipamEndStr conf += ipamEndStr
} }
} else { } else {
@ -252,13 +301,33 @@ func (tc testCase) rangesConfig() string {
return conf + rangesEndStr return conf + rangesEndStr
} }
func (tc testCase) resolvConfConfig() string {
conf := fmt.Sprintf(ipamResolvConfStr, tc.resolvConf)
return conf
}
func newResolvConf() (string, error) {
f, err := os.CreateTemp("", "host_local_resolv")
if err != nil {
return "", err
}
defer f.Close()
name := f.Name()
_, err = f.WriteString(fmt.Sprintf("nameserver %s", NAMESERVER))
return name, err
}
func deleteResolvConf(path string) error {
return os.Remove(path)
}
var counter uint var counter uint
// createCmdArgs generates network configuration and creates command // createCmdArgs generates network configuration and creates command
// arguments for a test case. // arguments for a test case.
func (tc testCase) createCmdArgs(targetNS ns.NetNS, dataDir string) *skel.CmdArgs { func (tc testCase) createCmdArgs(targetNS ns.NetNS, dataDir string) *skel.CmdArgs {
conf := tc.netConfJSON(dataDir) conf := tc.netConfJSON(dataDir)
//defer func() { counter += 1 }() // defer func() { counter += 1 }()
return &skel.CmdArgs{ return &skel.CmdArgs{
ContainerID: fmt.Sprintf("dummy-%d", counter), ContainerID: fmt.Sprintf("dummy-%d", counter),
Netns: targetNS.Path(), Netns: targetNS.Path(),
@ -270,18 +339,17 @@ func (tc testCase) createCmdArgs(targetNS ns.NetNS, dataDir string) *skel.CmdArg
// createCheckCmdArgs generates network configuration and creates command // createCheckCmdArgs generates network configuration and creates command
// arguments for a Check test case. // arguments for a Check test case.
func (tc testCase) createCheckCmdArgs(targetNS ns.NetNS, config *Net, dataDir string) *skel.CmdArgs { func (tc testCase) createCheckCmdArgs(targetNS ns.NetNS, config *Net) *skel.CmdArgs {
conf, err := json.Marshal(config) conf, err := json.Marshal(config)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// TODO Don't we need to use the same counter as before? // TODO Don't we need to use the same counter as before?
//defer func() { counter += 1 }() // defer func() { counter += 1 }()
return &skel.CmdArgs{ return &skel.CmdArgs{
ContainerID: fmt.Sprintf("dummy-%d", counter), ContainerID: fmt.Sprintf("dummy-%d", counter),
Netns: targetNS.Path(), Netns: targetNS.Path(),
IfName: IFNAME, IfName: IFNAME,
StdinData: []byte(conf), StdinData: conf,
} }
} }
@ -369,25 +437,25 @@ func ipVersion(ip net.IP) string {
func countIPAMIPs(path string) (int, error) { func countIPAMIPs(path string) (int, error) {
count := 0 count := 0
files, err := ioutil.ReadDir(path) entries, err := os.ReadDir(path)
if err != nil { if err != nil {
return -1, err return -1, err
} }
for _, file := range files { for _, entry := range entries {
if file.IsDir() { if entry.IsDir() {
continue continue
} }
if net.ParseIP(file.Name()) != nil { if net.ParseIP(entry.Name()) != nil {
count++ count++
} }
} }
return count, nil return count, nil
} }
func checkVlan(vlanId int, bridgeVlanInfo []*nl.BridgeVlanInfo) bool { func checkVlan(vlanID int, bridgeVlanInfo []*nl.BridgeVlanInfo) bool {
for _, vlan := range bridgeVlanInfo { for _, vlan := range bridgeVlanInfo {
if vlan.Vid == uint16(vlanId) { if vlan.Vid == uint16(vlanID) {
return true return true
} }
} }
@ -408,10 +476,12 @@ type testerBase struct {
vethName string vethName string
} }
type testerV10x testerBase type (
type testerV04x testerBase testerV10x testerBase
type testerV03x testerBase testerV04x testerBase
type testerV01xOr02x testerBase testerV03x testerBase
testerV01xOr02x testerBase
)
func newTesterByVersion(version string, testNS, targetNS ns.NetNS) cmdAddDelTester { func newTesterByVersion(version string, testNS, targetNS ns.NetNS) cmdAddDelTester {
switch { switch {
@ -458,9 +528,9 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
result = resultType.(*types100.Result) result = resultType.(*types100.Result)
if !tc.isLayer2 && tc.vlan != 0 { if !tc.isLayer2 && tc.vlan != 0 {
Expect(len(result.Interfaces)).To(Equal(4)) Expect(result.Interfaces).To(HaveLen(4))
} else { } else {
Expect(len(result.Interfaces)).To(Equal(3)) Expect(result.Interfaces).To(HaveLen(3))
} }
Expect(result.Interfaces[0].Name).To(Equal(BRNAME)) Expect(result.Interfaces[0].Name).To(Equal(BRNAME))
@ -500,13 +570,16 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)] vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
} }
// Check the bridge vlan filtering equals true // Check the bridge vlan filtering equals true
if tc.vlan != 0 { if tc.vlan != 0 || tc.vlanTrunk != nil {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(true)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeTrue())
} else { } else {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(false)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeFalse())
} }
// Ensure bridge has expected gateway address(es) // Ensure bridge has expected gateway address(es)
@ -517,7 +590,7 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL) addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL)
} }
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(BeNumerically(">", 0)) Expect(addrs).ToNot(BeEmpty())
for _, cidr := range tc.expGWCIDRs { for _, cidr := range tc.expGWCIDRs {
ip, subnet, err := net.ParseCIDR(cidr) ip, subnet, err := net.ParseCIDR(cidr)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -531,16 +604,16 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
break break
} }
} }
Expect(found).To(Equal(true), fmt.Sprintf("failed to find %s", cidr)) Expect(found).To(BeTrue(), fmt.Sprintf("failed to find %s", cidr))
} }
// Check for the veth link in the main namespace // Check for the veth link in the main namespace
links, err := netlink.LinkList() links, err := netlink.LinkList()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if !tc.isLayer2 && tc.vlan != 0 { if !tc.isLayer2 && tc.vlan != 0 {
Expect(len(links)).To(Equal(5)) // Bridge, Bridge vlan veth, veth, and loopback Expect(links).To(HaveLen(5)) // Bridge, Bridge vlan veth, veth, and loopback
} else { } else {
Expect(len(links)).To(Equal(3)) // Bridge, veth, and loopback Expect(links).To(HaveLen(3)) // Bridge, veth, and loopback
} }
link, err = netlink.LinkByName(result.Interfaces[1].Name) link, err = netlink.LinkByName(result.Interfaces[1].Name)
@ -555,6 +628,28 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
vlans, isExist := interfaceMap[int32(link.Attrs().Index)] vlans, isExist := interfaceMap[int32(link.Attrs().Index)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
}
// check VlanTrunks exist on the veth interface
if tc.vlanTrunk != nil {
interfaceMap, err := netlink.BridgeVlanList()
Expect(err).NotTo(HaveOccurred())
vlans, isExist := interfaceMap[int32(link.Attrs().Index)]
Expect(isExist).To(BeTrue())
for _, vlanEntry := range tc.vlanTrunk {
if vlanEntry.ID != nil {
Expect(checkVlan(*vlanEntry.ID, vlans)).To(BeTrue())
}
if vlanEntry.MinID != nil && vlanEntry.MaxID != nil {
for vid := *vlanEntry.MinID; vid <= *vlanEntry.MaxID; vid++ {
Expect(checkVlan(vid, vlans)).To(BeTrue())
}
}
}
} }
// Check that the bridge has a different mac from the veth // Check that the bridge has a different mac from the veth
@ -565,6 +660,11 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
Expect(link.Attrs().HardwareAddr.String()).NotTo(Equal(bridgeMAC)) Expect(link.Attrs().HardwareAddr.String()).NotTo(Equal(bridgeMAC))
} }
// Check that resolvConf was used properly
if !tc.isLayer2 && tc.resolvConf != "" {
Expect(result.DNS.Nameservers).To(Equal([]string{NAMESERVER}))
}
return nil return nil
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -581,9 +681,9 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs() expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
Expect(len(addrs)).To(Equal(len(expCIDRsV6) + 1)) //add one for the link-local Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
// ready when we read addresses. // ready when we read addresses.
@ -618,7 +718,7 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
break break
} }
} }
Expect(*found).To(Equal(true)) Expect(*found).To(BeTrue())
} }
return nil return nil
@ -628,9 +728,9 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
return result, nil return result, nil
} }
func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, dataDir string) { func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, _ string) {
// Generate network config and command arguments // Generate network config and command arguments
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf, dataDir) tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
// Execute cmdCHECK on the plugin // Execute cmdCHECK on the plugin
err := tester.testNS.Do(func(ns.NetNS) error { err := tester.testNS.Do(func(ns.NetNS) error {
@ -657,9 +757,9 @@ func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, dataDir string) {
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs() expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
Expect(len(addrs)).To(Equal(len(expCIDRsV6) + 1)) //add one for the link-local Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
// ready when we read addresses. // ready when we read addresses.
@ -694,7 +794,7 @@ func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, dataDir string) {
break break
} }
} }
Expect(*found).To(Equal(true)) Expect(*found).To(BeTrue())
} }
return nil return nil
@ -758,9 +858,9 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
result = resultType.(*types040.Result) result = resultType.(*types040.Result)
if !tc.isLayer2 && tc.vlan != 0 { if !tc.isLayer2 && tc.vlan != 0 {
Expect(len(result.Interfaces)).To(Equal(4)) Expect(result.Interfaces).To(HaveLen(4))
} else { } else {
Expect(len(result.Interfaces)).To(Equal(3)) Expect(result.Interfaces).To(HaveLen(3))
} }
Expect(result.Interfaces[0].Name).To(Equal(BRNAME)) Expect(result.Interfaces[0].Name).To(Equal(BRNAME))
@ -800,13 +900,16 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)] vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
} }
// Check the bridge vlan filtering equals true // Check the bridge vlan filtering equals true
if tc.vlan != 0 { if tc.vlan != 0 || tc.vlanTrunk != nil {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(true)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeTrue())
} else { } else {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(false)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeFalse())
} }
// Ensure bridge has expected gateway address(es) // Ensure bridge has expected gateway address(es)
@ -817,7 +920,7 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL) addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL)
} }
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(BeNumerically(">", 0)) Expect(addrs).ToNot(BeEmpty())
for _, cidr := range tc.expGWCIDRs { for _, cidr := range tc.expGWCIDRs {
ip, subnet, err := net.ParseCIDR(cidr) ip, subnet, err := net.ParseCIDR(cidr)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -831,16 +934,16 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
break break
} }
} }
Expect(found).To(Equal(true)) Expect(found).To(BeTrue())
} }
// Check for the veth link in the main namespace // Check for the veth link in the main namespace
links, err := netlink.LinkList() links, err := netlink.LinkList()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if !tc.isLayer2 && tc.vlan != 0 { if !tc.isLayer2 && tc.vlan != 0 {
Expect(len(links)).To(Equal(5)) // Bridge, Bridge vlan veth, veth, and loopback Expect(links).To(HaveLen(5)) // Bridge, Bridge vlan veth, veth, and loopback
} else { } else {
Expect(len(links)).To(Equal(3)) // Bridge, veth, and loopback Expect(links).To(HaveLen(3)) // Bridge, veth, and loopback
} }
link, err = netlink.LinkByName(result.Interfaces[1].Name) link, err = netlink.LinkByName(result.Interfaces[1].Name)
@ -855,6 +958,28 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
vlans, isExist := interfaceMap[int32(link.Attrs().Index)] vlans, isExist := interfaceMap[int32(link.Attrs().Index)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
}
// check VlanTrunks exist on the veth interface
if tc.vlanTrunk != nil {
interfaceMap, err := netlink.BridgeVlanList()
Expect(err).NotTo(HaveOccurred())
vlans, isExist := interfaceMap[int32(link.Attrs().Index)]
Expect(isExist).To(BeTrue())
for _, vlanEntry := range tc.vlanTrunk {
if vlanEntry.ID != nil {
Expect(checkVlan(*vlanEntry.ID, vlans)).To(BeTrue())
}
if vlanEntry.MinID != nil && vlanEntry.MaxID != nil {
for vid := *vlanEntry.MinID; vid <= *vlanEntry.MaxID; vid++ {
Expect(checkVlan(vid, vlans)).To(BeTrue())
}
}
}
} }
// Check that the bridge has a different mac from the veth // Check that the bridge has a different mac from the veth
@ -881,9 +1006,9 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs() expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
Expect(len(addrs)).To(Equal(len(expCIDRsV6) + 1)) //add one for the link-local Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
// ready when we read addresses. // ready when we read addresses.
@ -918,7 +1043,7 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
break break
} }
} }
Expect(*found).To(Equal(true)) Expect(*found).To(BeTrue())
} }
return nil return nil
@ -928,9 +1053,9 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
return result, nil return result, nil
} }
func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, dataDir string) { func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, _ string) {
// Generate network config and command arguments // Generate network config and command arguments
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf, dataDir) tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
// Execute cmdCHECK on the plugin // Execute cmdCHECK on the plugin
err := tester.testNS.Do(func(ns.NetNS) error { err := tester.testNS.Do(func(ns.NetNS) error {
@ -957,9 +1082,9 @@ func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, dataDir string) {
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs() expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
Expect(len(addrs)).To(Equal(len(expCIDRsV6) + 1)) //add one for the link-local Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
// ready when we read addresses. // ready when we read addresses.
@ -994,7 +1119,7 @@ func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, dataDir string) {
break break
} }
} }
Expect(*found).To(Equal(true)) Expect(*found).To(BeTrue())
} }
return nil return nil
@ -1058,9 +1183,9 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
result = resultType.(*types040.Result) result = resultType.(*types040.Result)
if !tc.isLayer2 && tc.vlan != 0 { if !tc.isLayer2 && tc.vlan != 0 {
Expect(len(result.Interfaces)).To(Equal(4)) Expect(result.Interfaces).To(HaveLen(4))
} else { } else {
Expect(len(result.Interfaces)).To(Equal(3)) Expect(result.Interfaces).To(HaveLen(3))
} }
Expect(result.Interfaces[0].Name).To(Equal(BRNAME)) Expect(result.Interfaces[0].Name).To(Equal(BRNAME))
@ -1100,13 +1225,16 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)] vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
} }
// Check the bridge vlan filtering equals true // Check the bridge vlan filtering equals true
if tc.vlan != 0 { if tc.vlan != 0 || tc.vlanTrunk != nil {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(true)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeTrue())
} else { } else {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(false)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeFalse())
} }
// Ensure bridge has expected gateway address(es) // Ensure bridge has expected gateway address(es)
@ -1117,7 +1245,7 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL) addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL)
} }
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(BeNumerically(">", 0)) Expect(addrs).ToNot(BeEmpty())
for _, cidr := range tc.expGWCIDRs { for _, cidr := range tc.expGWCIDRs {
ip, subnet, err := net.ParseCIDR(cidr) ip, subnet, err := net.ParseCIDR(cidr)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -1131,16 +1259,16 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
break break
} }
} }
Expect(found).To(Equal(true)) Expect(found).To(BeTrue())
} }
// Check for the veth link in the main namespace // Check for the veth link in the main namespace
links, err := netlink.LinkList() links, err := netlink.LinkList()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if !tc.isLayer2 && tc.vlan != 0 { if !tc.isLayer2 && tc.vlan != 0 {
Expect(len(links)).To(Equal(5)) // Bridge, Bridge vlan veth, veth, and loopback Expect(links).To(HaveLen(5)) // Bridge, Bridge vlan veth, veth, and loopback
} else { } else {
Expect(len(links)).To(Equal(3)) // Bridge, veth, and loopback Expect(links).To(HaveLen(3)) // Bridge, veth, and loopback
} }
link, err = netlink.LinkByName(result.Interfaces[1].Name) link, err = netlink.LinkByName(result.Interfaces[1].Name)
@ -1155,6 +1283,28 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
vlans, isExist := interfaceMap[int32(link.Attrs().Index)] vlans, isExist := interfaceMap[int32(link.Attrs().Index)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
}
// check VlanTrunks exist on the veth interface
if tc.vlanTrunk != nil {
interfaceMap, err := netlink.BridgeVlanList()
Expect(err).NotTo(HaveOccurred())
vlans, isExist := interfaceMap[int32(link.Attrs().Index)]
Expect(isExist).To(BeTrue())
for _, vlanEntry := range tc.vlanTrunk {
if vlanEntry.ID != nil {
Expect(checkVlan(*vlanEntry.ID, vlans)).To(BeTrue())
}
if vlanEntry.MinID != nil && vlanEntry.MaxID != nil {
for vid := *vlanEntry.MinID; vid <= *vlanEntry.MaxID; vid++ {
Expect(checkVlan(vid, vlans)).To(BeTrue())
}
}
}
} }
// Check that the bridge has a different mac from the veth // Check that the bridge has a different mac from the veth
@ -1181,7 +1331,7 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs() expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
@ -1217,7 +1367,7 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
break break
} }
} }
Expect(*found).To(Equal(true)) Expect(*found).To(BeTrue())
} }
return nil return nil
@ -1226,11 +1376,10 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) (types.Result,
return result, nil return result, nil
} }
func (tester *testerV03x) cmdCheckTest(tc testCase, conf *Net, dataDir string) { func (tester *testerV03x) cmdCheckTest(_ testCase, _ *Net, _ string) {
return
} }
func (tester *testerV03x) cmdDelTest(tc testCase, dataDir string) { func (tester *testerV03x) cmdDelTest(_ testCase, _ string) {
err := tester.testNS.Do(func(ns.NetNS) error { err := tester.testNS.Do(func(ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
@ -1327,13 +1476,16 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)] vlans, isExist := interfaceMap[int32(peerLink.Attrs().Index)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
} }
// Check the bridge vlan filtering equals true // Check the bridge vlan filtering equals true
if tc.vlan != 0 { if tc.vlan != 0 {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(true)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeTrue())
} else { } else {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(false)) Expect(*link.(*netlink.Bridge).VlanFiltering).To(BeFalse())
} }
// Ensure bridge has expected gateway address(es) // Ensure bridge has expected gateway address(es)
@ -1344,7 +1496,7 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL) addrs, err = netlink.AddrList(vlanLink, netlink.FAMILY_ALL)
} }
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(BeNumerically(">", 0)) Expect(addrs).ToNot(BeEmpty())
for _, cidr := range tc.expGWCIDRs { for _, cidr := range tc.expGWCIDRs {
ip, subnet, err := net.ParseCIDR(cidr) ip, subnet, err := net.ParseCIDR(cidr)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -1358,7 +1510,7 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
break break
} }
} }
Expect(found).To(Equal(true)) Expect(found).To(BeTrue())
} }
// Check for the veth link in the main namespace; can't // Check for the veth link in the main namespace; can't
@ -1367,9 +1519,9 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
links, err := netlink.LinkList() links, err := netlink.LinkList()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if !tc.isLayer2 && tc.vlan != 0 { if !tc.isLayer2 && tc.vlan != 0 {
Expect(len(links)).To(Equal(5)) // Bridge, Bridge vlan veth, veth, and loopback Expect(links).To(HaveLen(5)) // Bridge, Bridge vlan veth, veth, and loopback
} else { } else {
Expect(len(links)).To(Equal(3)) // Bridge, veth, and loopback Expect(links).To(HaveLen(3)) // Bridge, veth, and loopback
} }
// Grab the vlan map in the host NS for checking later // Grab the vlan map in the host NS for checking later
@ -1400,7 +1552,7 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs() expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
@ -1436,7 +1588,7 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
break break
} }
} }
Expect(*found).To(Equal(true)) Expect(*found).To(BeTrue())
} }
// Validate VLAN in the host NS. Since 0.1.0/0.2.0 don't return // Validate VLAN in the host NS. Since 0.1.0/0.2.0 don't return
@ -1449,6 +1601,9 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
vlans, isExist := hostNSVlanMap[int32(peerIndex)] vlans, isExist := hostNSVlanMap[int32(peerIndex)]
Expect(isExist).To(BeTrue()) Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue()) Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
if tc.removeDefaultVlan {
Expect(vlans).To(HaveLen(1))
}
} }
return nil return nil
@ -1457,22 +1612,22 @@ func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) (types.Re
return nil, nil return nil, nil
} }
func (tester *testerV01xOr02x) cmdCheckTest(tc testCase, conf *Net, dataDir string) { func (tester *testerV01xOr02x) cmdCheckTest(_ testCase, _ *Net, _ string) {
return
} }
func (tester *testerV01xOr02x) cmdDelTest(tc testCase, dataDir string) { func (tester *testerV01xOr02x) cmdDelTest(tc testCase, _ string) {
err := tester.testNS.Do(func(ns.NetNS) error { err := tester.testNS.Do(func(ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
err := testutils.CmdDelWithArgs(tester.args, func() error { err := testutils.CmdDelWithArgs(tester.args, func() error {
return cmdDel(tester.args) return cmdDel(tester.args)
}) })
if expect020DelError(tc) { switch {
case expect020DelError(tc):
Expect(err).To(MatchError(tc.DelErr020)) Expect(err).To(MatchError(tc.DelErr020))
} else if expect010DelError(tc) { case expect010DelError(tc):
Expect(err).To(MatchError(tc.DelErr010)) Expect(err).To(MatchError(tc.DelErr010))
} else { default:
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
return nil return nil
@ -1545,7 +1700,6 @@ func buildOneConfig(name, cniVersion string, orig *Net, prevResult types.Result)
} }
return conf, nil return conf, nil
} }
func cmdAddDelCheckTest(origNS, targetNS ns.NetNS, tc testCase, dataDir string) { func cmdAddDelCheckTest(origNS, targetNS ns.NetNS, tc testCase, dataDir string) {
@ -1595,7 +1749,7 @@ var _ = Describe("bridge Operations", func() {
targetNS, err = testutils.NewNS() targetNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
dataDir, err = ioutil.TempDir("", "bridge_test") dataDir, err = os.MkdirTemp("", "bridge_test")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Do not emulate an error, each test will set this if needed // Do not emulate an error, each test will set this if needed
@ -1610,6 +1764,61 @@ var _ = Describe("bridge Operations", func() {
Expect(testutils.UnmountNS(targetNS)).To(Succeed()) Expect(testutils.UnmountNS(targetNS)).To(Succeed())
}) })
var (
correctID int = 10
correctMinID int = 100
correctMaxID int = 105
incorrectMinID int = 1000
incorrectMaxID int = 100
overID int = 5000
negativeID int = -1
)
DescribeTable(
"collectVlanTrunk succeeds",
func(vlanTrunks []*VlanTrunk, expectedVIDs []int) {
Expect(collectVlanTrunk(vlanTrunks)).To(ConsistOf(expectedVIDs))
},
Entry("when provided an empty VLAN trunk configuration", []*VlanTrunk{}, nil),
Entry("when provided a VLAN trunk configuration with both min / max range", []*VlanTrunk{
{
MinID: &correctMinID,
MaxID: &correctMaxID,
},
}, []int{100, 101, 102, 103, 104, 105}),
Entry("when provided a VLAN trunk configuration with id only", []*VlanTrunk{
{
ID: &correctID,
},
}, []int{10}),
Entry("when provided a VLAN trunk configuration with id and range", []*VlanTrunk{
{
ID: &correctID,
},
{
MinID: &correctMinID,
MaxID: &correctMaxID,
},
}, []int{10, 100, 101, 102, 103, 104, 105}),
)
DescribeTable(
"collectVlanTrunk failed",
func(vlanTrunks []*VlanTrunk, expectedError error) {
_, err := collectVlanTrunk(vlanTrunks)
Expect(err).To(MatchError(expectedError))
},
Entry("when not passed the maxID", []*VlanTrunk{{MinID: &correctMinID}}, fmt.Errorf("minID and maxID should be configured simultaneously, maxID is missing")),
Entry("when not passed the minID", []*VlanTrunk{{MaxID: &correctMaxID}}, fmt.Errorf("minID and maxID should be configured simultaneously, minID is missing")),
Entry("when the minID is negative", []*VlanTrunk{{MinID: &negativeID, MaxID: &correctMaxID}}, fmt.Errorf("incorrect trunk minID parameter")),
Entry("when the minID is larger than 4094", []*VlanTrunk{{MinID: &overID, MaxID: &correctMaxID}}, fmt.Errorf("incorrect trunk minID parameter")),
Entry("when the maxID is larger than 4094", []*VlanTrunk{{MinID: &correctMinID, MaxID: &overID}}, fmt.Errorf("incorrect trunk maxID parameter")),
Entry("when the maxID is negative", []*VlanTrunk{{MinID: &correctMinID, MaxID: &overID}}, fmt.Errorf("incorrect trunk maxID parameter")),
Entry("when the ID is larger than 4094", []*VlanTrunk{{ID: &overID}}, fmt.Errorf("incorrect trunk id parameter")),
Entry("when the ID is negative", []*VlanTrunk{{ID: &negativeID}}, fmt.Errorf("incorrect trunk id parameter")),
Entry("when the maxID is smaller than minID", []*VlanTrunk{{MinID: &incorrectMinID, MaxID: &incorrectMaxID}}, fmt.Errorf("minID is greater than maxID in trunk parameter")),
)
for _, ver := range testutils.AllSpecVersions { for _, ver := range testutils.AllSpecVersions {
// Redefine ver inside for scope so real value is picked up by each dynamically defined It() // 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. // See Gingkgo's "Patterns for dynamically generating tests" documentation.
@ -1706,6 +1915,12 @@ var _ = Describe("bridge Operations", func() {
AddErr010: "CNI version 0.1.0 does not support more than 1 address per family", AddErr010: "CNI version 0.1.0 does not support more than 1 address per family",
DelErr010: "CNI version 0.1.0 does not support more than 1 address per family", DelErr010: "CNI version 0.1.0 does not support more than 1 address per family",
}, },
{
// with resolvConf DNS settings
subnet: "10.1.2.0/24",
expGWCIDRs: []string{"10.1.2.1/24"},
resolvConf: resolvConf,
},
} { } {
tc := tc tc := tc
i := i i := i
@ -1736,6 +1951,37 @@ var _ = Describe("bridge Operations", func() {
cmdAddDelTest(originalNS, targetNS, tc, dataDir) cmdAddDelTest(originalNS, targetNS, tc, dataDir)
}) })
// TODO find some way to put pointer
It(fmt.Sprintf("[%s] configures and deconfigures a l2 bridge with vlan id 100, vlanTrunk 101,200~210 using ADD/DEL", ver), func() {
id, minID, maxID := 101, 200, 210
tc := testCase{
cniVersion: ver,
isLayer2: true,
vlanTrunk: []*VlanTrunk{
{ID: &id},
{
MinID: &minID,
MaxID: &maxID,
},
},
AddErr020: "cannot convert: no valid IP addresses",
AddErr010: "cannot convert: no valid IP addresses",
}
cmdAddDelTest(originalNS, targetNS, tc, dataDir)
})
It(fmt.Sprintf("[%s] configures and deconfigures a l2 bridge with vlan id 100 and no default vlan using ADD/DEL", ver), func() {
tc := testCase{
cniVersion: ver,
isLayer2: true,
vlan: 100,
removeDefaultVlan: true,
AddErr020: "cannot convert: no valid IP addresses",
AddErr010: "cannot convert: no valid IP addresses",
}
cmdAddDelTest(originalNS, targetNS, tc, dataDir)
})
for i, tc := range []testCase{ for i, tc := range []testCase{
{ {
// IPv4 only // IPv4 only
@ -1786,6 +2032,11 @@ var _ = Describe("bridge Operations", func() {
tc.cniVersion = ver tc.cniVersion = ver
cmdAddDelTest(originalNS, targetNS, tc, dataDir) cmdAddDelTest(originalNS, targetNS, tc, dataDir)
}) })
It(fmt.Sprintf("[%s] (%d) configures and deconfigures a bridge, veth with default route and vlanID 100 and no default vlan with ADD/DEL", ver, i), func() {
tc.cniVersion = ver
tc.removeDefaultVlan = true
cmdAddDelTest(originalNS, targetNS, tc, dataDir)
})
} }
for i, tc := range []testCase{ for i, tc := range []testCase{
@ -1893,7 +2144,7 @@ var _ = Describe("bridge Operations", func() {
checkBridgeIPs := func(cidr0, cidr1 string) { checkBridgeIPs := func(cidr0, cidr1 string) {
addrs, err := netlink.AddrList(bridge, family) addrs, err := netlink.AddrList(bridge, family)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(expNumAddrs)) Expect(addrs).To(HaveLen(expNumAddrs))
addr := addrs[0].IPNet.String() addr := addrs[0].IPNet.String()
Expect(addr).To(Equal(cidr0)) Expect(addr).To(Equal(cidr0))
if cidr1 != "" { if cidr1 != "" {
@ -1903,7 +2154,7 @@ var _ = Describe("bridge Operations", func() {
} }
// Check if ForceAddress has default value // Check if ForceAddress has default value
Expect(conf.ForceAddress).To(Equal(false)) Expect(conf.ForceAddress).To(BeFalse())
// Set first address on bridge // Set first address on bridge
err = ensureAddr(bridge, family, &gwnFirst, conf.ForceAddress) err = ensureAddr(bridge, family, &gwnFirst, conf.ForceAddress)
@ -1951,8 +2202,6 @@ var _ = Describe("bridge Operations", func() {
It(fmt.Sprintf("[%s] ensure promiscuous mode on bridge", ver), func() { It(fmt.Sprintf("[%s] ensure promiscuous mode on bridge", ver), func() {
const IFNAME = "bridge0" const IFNAME = "bridge0"
const EXPECTED_IP = "10.0.0.0/8"
const CHANGED_EXPECTED_IP = "10.1.2.3/16"
conf := &NetConf{ conf := &NetConf{
NetConf: types.NetConf{ NetConf: types.NetConf{
@ -1974,9 +2223,9 @@ var _ = Describe("bridge Operations", func() {
_, _, err := setupBridge(conf) _, _, err := setupBridge(conf)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Check if ForceAddress has default value // Check if ForceAddress has default value
Expect(conf.ForceAddress).To(Equal(false)) Expect(conf.ForceAddress).To(BeFalse())
//Check if promiscuous mode is set correctly // Check if promiscuous mode is set correctly
link, err := netlink.LinkByName("bridge0") link, err := netlink.LinkByName("bridge0")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -2241,7 +2490,7 @@ var _ = Describe("bridge Operations", func() {
for _, test := range tests { for _, test := range tests {
_, _, err := loadNetConf([]byte(test.netConfJSON("")), "") _, _, err := loadNetConf([]byte(test.netConfJSON("")), "")
if test.err == nil { if test.err == nil {
Expect(err).To(BeNil()) Expect(err).ToNot(HaveOccurred())
} else { } else {
Expect(err).To(Equal(test.err)) Expect(err).To(Equal(test.err))
} }

View File

@ -0,0 +1,39 @@
---
title: dummy plugin
description: "plugins/main/dummy/README.md"
date: 2022-05-12
toc: true
draft: true
weight: 200
---
## Overview
dummy is a useful feature for routing packets through the Linux kernel without transmitting.
Like loopback, it is a purely virtual interface that allows packets to be routed to a designated IP address. Unlike loopback, the IP address can be arbitrary and is not restricted to the `127.0.0.0/8` range.
## Example configuration
```json
{
"name": "mynet",
"type": "dummy",
"ipam": {
"type": "host-local",
"subnet": "10.1.2.0/24"
}
}
```
## Network configuration reference
* `name` (string, required): the name of the network.
* `type` (string, required): "dummy".
* `ipam` (dictionary, required): IPAM configuration to be used for this network.
## Notes
* `dummy` does not transmit packets.
Therefore the container will not be able to reach any external network.
This solution is designed to be used in conjunction with other CNI plugins (e.g., `bridge`) to provide an internal non-loopback address for applications to use.

292
plugins/main/dummy/dummy.go Normal file
View File

@ -0,0 +1,292 @@
// Copyright 2022 Arista Networks
//
// 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 main
import (
"encoding/json"
"errors"
"fmt"
"net"
"github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/cni/pkg/version"
"github.com/containernetworking/plugins/pkg/ip"
"github.com/containernetworking/plugins/pkg/ipam"
"github.com/containernetworking/plugins/pkg/ns"
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
)
func parseNetConf(bytes []byte) (*types.NetConf, error) {
conf := &types.NetConf{}
if err := json.Unmarshal(bytes, conf); err != nil {
return nil, fmt.Errorf("failed to parse network config: %v", err)
}
return conf, nil
}
func createDummy(ifName string, netns ns.NetNS) (*current.Interface, error) {
dummy := &current.Interface{}
dm := &netlink.Dummy{
LinkAttrs: netlink.LinkAttrs{
Name: ifName,
Namespace: netlink.NsFd(int(netns.Fd())),
},
}
if err := netlink.LinkAdd(dm); err != nil {
return nil, fmt.Errorf("failed to create dummy: %v", err)
}
dummy.Name = ifName
err := netns.Do(func(_ ns.NetNS) error {
// Re-fetch interface to get all properties/attributes
contDummy, err := netlink.LinkByName(ifName)
if err != nil {
return fmt.Errorf("failed to fetch dummy%q: %v", ifName, err)
}
dummy.Mac = contDummy.Attrs().HardwareAddr.String()
dummy.Sandbox = netns.Path()
return nil
})
if err != nil {
return nil, err
}
return dummy, nil
}
func cmdAdd(args *skel.CmdArgs) error {
conf, err := parseNetConf(args.StdinData)
if err != nil {
return err
}
if conf.IPAM.Type == "" {
return errors.New("dummy interface requires an IPAM configuration")
}
netns, err := ns.GetNS(args.Netns)
if err != nil {
return fmt.Errorf("failed to open netns %q: %v", netns, err)
}
defer netns.Close()
dummyInterface, err := createDummy(args.IfName, netns)
if err != nil {
return err
}
// Delete link if err to avoid link leak in this ns
defer func() {
if err != nil {
netns.Do(func(_ ns.NetNS) error {
return ip.DelLinkByName(args.IfName)
})
}
}()
r, err := ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
if err != nil {
return err
}
// defer ipam deletion to avoid ip leak
defer func() {
if err != nil {
ipam.ExecDel(conf.IPAM.Type, args.StdinData)
}
}()
// convert IPAMResult to current Result type
result, err := current.NewResultFromResult(r)
if err != nil {
return err
}
if len(result.IPs) == 0 {
return errors.New("IPAM plugin returned missing IP config")
}
for _, ipc := range result.IPs {
// all addresses apply to the container dummy interface
ipc.Interface = current.Int(0)
}
result.Interfaces = []*current.Interface{dummyInterface}
err = netns.Do(func(_ ns.NetNS) error {
return ipam.ConfigureIface(args.IfName, result)
})
if err != nil {
return err
}
return types.PrintResult(result, conf.CNIVersion)
}
func cmdDel(args *skel.CmdArgs) error {
conf, err := parseNetConf(args.StdinData)
if err != nil {
return err
}
if err = ipam.ExecDel(conf.IPAM.Type, args.StdinData); err != nil {
return err
}
if args.Netns == "" {
return nil
}
err = ns.WithNetNSPath(args.Netns, func(ns.NetNS) error {
err = ip.DelLinkByName(args.IfName)
if err != nil && err == ip.ErrLinkNotFound {
return nil
}
return err
})
if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
// so don't return an error if the device is already removed.
// https://github.com/kubernetes/kubernetes/issues/43014#issuecomment-287164444
_, ok := err.(ns.NSPathNotExistErr)
if ok {
return nil
}
return err
}
return nil
}
func main() {
skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, bv.BuildString("dummy"))
}
func cmdCheck(args *skel.CmdArgs) error {
conf, err := parseNetConf(args.StdinData)
if err != nil {
return err
}
if conf.IPAM.Type == "" {
return errors.New("dummy interface requires an IPAM configuration")
}
netns, err := ns.GetNS(args.Netns)
if err != nil {
return fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
}
defer netns.Close()
// run the IPAM plugin and get back the config to apply
err = ipam.ExecCheck(conf.IPAM.Type, args.StdinData)
if err != nil {
return err
}
if conf.RawPrevResult == nil {
return fmt.Errorf("dummy: Required prevResult missing")
}
if err := version.ParsePrevResult(conf); err != nil {
return err
}
// Convert whatever the IPAM result was into the current Result type
result, err := current.NewResultFromResult(conf.PrevResult)
if err != nil {
return err
}
var contMap current.Interface
// Find interfaces for name whe know, that of dummy device inside container
for _, intf := range result.Interfaces {
if args.IfName == intf.Name {
if args.Netns == intf.Sandbox {
contMap = *intf
continue
}
}
}
// The namespace must be the same as what was configured
if args.Netns != contMap.Sandbox {
return fmt.Errorf("Sandbox in prevResult %s doesn't match configured netns: %s",
contMap.Sandbox, args.Netns)
}
//
// Check prevResults for ips, routes and dns against values found in the container
if err := netns.Do(func(_ ns.NetNS) error {
// Check interface against values found in the container
err := validateCniContainerInterface(contMap)
if err != nil {
return err
}
err = ip.ValidateExpectedInterfaceIPs(args.IfName, result.IPs)
if err != nil {
return err
}
return nil
}); err != nil {
return err
}
return nil
}
func validateCniContainerInterface(intf current.Interface) error {
var link netlink.Link
var err error
if intf.Name == "" {
return fmt.Errorf("Container interface name missing in prevResult: %v", intf.Name)
}
link, err = netlink.LinkByName(intf.Name)
if err != nil {
return fmt.Errorf("Container Interface name in prevResult: %s not found", intf.Name)
}
if intf.Sandbox == "" {
return fmt.Errorf("Error: Container interface %s should not be in host namespace", link.Attrs().Name)
}
_, isDummy := link.(*netlink.Dummy)
if !isDummy {
return fmt.Errorf("Error: Container interface %s not of type dummy", link.Attrs().Name)
}
if intf.Mac != "" {
if intf.Mac != link.Attrs().HardwareAddr.String() {
return fmt.Errorf("Interface %s Mac %s doesn't match container Mac: %s", intf.Name, intf.Mac, link.Attrs().HardwareAddr)
}
}
if link.Attrs().Flags&net.FlagUp != net.FlagUp {
return fmt.Errorf("Interface %s is down", intf.Name)
}
return nil
}

View File

@ -0,0 +1,40 @@
// Copyright 2022 Arista Networks
//
// 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 main_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
)
var pathToLoPlugin string
func TestLoopback(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "plugins/main/dummy")
}
var _ = BeforeSuite(func() {
var err error
pathToLoPlugin, err = gexec.Build("github.com/containernetworking/plugins/plugins/main/dummy")
Expect(err).NotTo(HaveOccurred())
})
var _ = AfterSuite(func() {
gexec.CleanupBuildArtifacts()
})

View File

@ -0,0 +1,385 @@
// Copyright 2022 Arista Networks
//
// 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 main
import (
"encoding/json"
"errors"
"fmt"
"net"
"os"
"strings"
"syscall"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
types020 "github.com/containernetworking/cni/pkg/types/020"
types040 "github.com/containernetworking/cni/pkg/types/040"
types100 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
)
const MASTER_NAME = "eth0"
type Net struct {
Name string `json:"name"`
CNIVersion string `json:"cniVersion"`
Type string `json:"type,omitempty"`
IPAM *allocator.IPAMConfig `json:"ipam"`
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
PrevResult types100.Result `json:"-"`
}
func buildOneConfig(netName string, cniVersion 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
}
// Ensure every config uses the same name and version
config := make(map[string]interface{})
confBytes, err := json.Marshal(orig)
if err != nil {
return nil, err
}
err = json.Unmarshal(confBytes, &config)
if err != nil {
return nil, fmt.Errorf("unmarshal existing network bytes: %s", err)
}
for key, value := range inject {
config[key] = value
}
newBytes, err := json.Marshal(config)
if err != nil {
return nil, err
}
conf := &Net{}
if err := json.Unmarshal(newBytes, &conf); err != nil {
return nil, fmt.Errorf("error parsing configuration: %s", err)
}
return conf, nil
}
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
testerV04x testerBase
testerV03x testerBase
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(r.Interfaces).To(HaveLen(1))
Expect(r.Interfaces[0].Name).To(Equal(name))
Expect(r.IPs).To(HaveLen(1))
return r.Interfaces[0].Mac
}
func verify0403(result types.Result, name string) string {
r, err := types040.GetResult(result)
Expect(err).NotTo(HaveOccurred())
Expect(r.Interfaces).To(HaveLen(1))
Expect(r.Interfaces[0].Name).To(Equal(name))
Expect(r.IPs).To(HaveLen(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, _ 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("dummy Operations", func() {
var originalNS, targetNS ns.NetNS
var dataDir string
BeforeEach(func() {
// Create a new NetNS so we don't modify the host
var err error
originalNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred())
targetNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred())
dataDir, err = os.MkdirTemp("", "dummy_test")
Expect(err).NotTo(HaveOccurred())
err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
// Add master
err = netlink.LinkAdd(&netlink.Dummy{
LinkAttrs: netlink.LinkAttrs{
Name: MASTER_NAME,
},
})
Expect(err).NotTo(HaveOccurred())
m, err := netlink.LinkByName(MASTER_NAME)
Expect(err).NotTo(HaveOccurred())
err = netlink.LinkSetUp(m)
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
})
AfterEach(func() {
Expect(os.RemoveAll(dataDir)).To(Succeed())
Expect(originalNS.Close()).To(Succeed())
Expect(testutils.UnmountNS(originalNS)).To(Succeed())
Expect(targetNS.Close()).To(Succeed())
Expect(testutils.UnmountNS(targetNS)).To(Succeed())
})
for _, ver := range testutils.AllSpecVersions {
// 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
It(fmt.Sprintf("[%s] creates an dummy link in a non-default namespace", ver), func() {
// Create dummy in other namespace
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
_, err := createDummy("foobar0", targetNS)
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
// Make sure dummy 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"))
return nil
})
Expect(err).NotTo(HaveOccurred())
})
It(fmt.Sprintf("[%s] configures and deconfigures a dummy link with ADD/CHECK/DEL", ver), func() {
const IFNAME = "dummy0"
conf := fmt.Sprintf(`{
"cniVersion": "%s",
"name": "dummyTestv4",
"type": "dummy",
"ipam": {
"type": "host-local",
"subnet": "10.1.2.0/24",
"dataDir": "%s"
}
}`, ver, dataDir)
args := &skel.CmdArgs{
ContainerID: "contDummy",
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 dummy 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(addrs).To(HaveLen(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("dummyTestv4", ver, n, result)
Expect(err).NotTo(HaveOccurred())
confString, err := json.Marshal(newConf)
Expect(err).NotTo(HaveOccurred())
args.StdinData = confString
// CNI Check dummy 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)
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 dummy 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
})
Expect(err).NotTo(HaveOccurred())
})
It(fmt.Sprintf("[%s] fails to create dummy link with no ipam", ver), func() {
var err error
const confFmt = `{
"cniVersion": "%s",
"name": "mynet",
"type": "dummy"
}`
args := &skel.CmdArgs{
ContainerID: "dummyCont",
Netns: "/var/run/netns/test",
IfName: "dummy0",
StdinData: []byte(fmt.Sprintf(confFmt, ver)),
}
_ = originalNS.Do(func(netNS ns.NetNS) error {
defer GinkgoRecover()
_, _, err = testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).To(Equal(errors.New("dummy interface requires an IPAM configuration")))
return nil
})
})
}
})

View File

@ -19,7 +19,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
@ -32,21 +31,18 @@ import (
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" 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"
"github.com/containernetworking/plugins/pkg/ns" "github.com/containernetworking/plugins/pkg/ns"
bv "github.com/containernetworking/plugins/pkg/utils/buildversion" bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
) )
var ( var sysBusPCI = "/sys/bus/pci/devices"
sysBusPCI = "/sys/bus/pci/devices"
)
// Array of different linux drivers bound to network device needed for DPDK // Array of different linux drivers bound to network device needed for DPDK
var userspaceDrivers = []string{"vfio-pci", "uio_pci_generic", "igb_uio"} var userspaceDrivers = []string{"vfio-pci", "uio_pci_generic", "igb_uio"}
//NetConf for host-device config, look the README to learn how to use those parameters // NetConf for host-device config, look the README to learn how to use those parameters
type NetConf struct { type NetConf struct {
types.NetConf types.NetConf
Device string `json:"device"` // Device-Name, something like eth0 or can0 etc. Device string `json:"device"` // Device-Name, something like eth0 or can0 etc.
@ -162,10 +158,7 @@ func cmdAdd(args *skel.CmdArgs) error {
if !cfg.DPDKMode { if !cfg.DPDKMode {
err = containerNs.Do(func(_ ns.NetNS) error { err = containerNs.Do(func(_ ns.NetNS) error {
if err := ipam.ConfigureIface(args.IfName, newResult); err != nil { return ipam.ConfigureIface(args.IfName, newResult)
return err
}
return nil
}) })
if err != nil { if err != nil {
return err return err
@ -326,10 +319,11 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to list node links: %v", err) return nil, fmt.Errorf("failed to list node links: %v", err)
} }
switch {
if len(devname) > 0 { case len(devname) > 0:
return netlink.LinkByName(devname) return netlink.LinkByName(devname)
} else if len(hwaddr) > 0 { case len(hwaddr) > 0:
hwAddr, err := net.ParseMAC(hwaddr) hwAddr, err := net.ParseMAC(hwaddr)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse MAC address %q: %v", hwaddr, err) return nil, fmt.Errorf("failed to parse MAC address %q: %v", hwaddr, err)
@ -340,26 +334,26 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
return link, nil return link, nil
} }
} }
} else if len(kernelpath) > 0 { case len(kernelpath) > 0:
if !filepath.IsAbs(kernelpath) || !strings.HasPrefix(kernelpath, "/sys/devices/") { if !filepath.IsAbs(kernelpath) || !strings.HasPrefix(kernelpath, "/sys/devices/") {
return nil, fmt.Errorf("kernel device path %q must be absolute and begin with /sys/devices/", kernelpath) return nil, fmt.Errorf("kernel device path %q must be absolute and begin with /sys/devices/", kernelpath)
} }
netDir := filepath.Join(kernelpath, "net") netDir := filepath.Join(kernelpath, "net")
files, err := ioutil.ReadDir(netDir) entries, err := os.ReadDir(netDir)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to find network devices at %q", netDir) return nil, fmt.Errorf("failed to find network devices at %q", netDir)
} }
// Grab the first device from eg /sys/devices/pci0000:00/0000:00:19.0/net // Grab the first device from eg /sys/devices/pci0000:00/0000:00:19.0/net
for _, file := range files { for _, entry := range entries {
// Make sure it's really an interface // Make sure it's really an interface
for _, l := range links { for _, l := range links {
if file.Name() == l.Attrs().Name { if entry.Name() == l.Attrs().Name {
return l, nil return l, nil
} }
} }
} }
} else if len(pciaddr) > 0 { case len(pciaddr) > 0:
netDir := filepath.Join(sysBusPCI, pciaddr, "net") netDir := filepath.Join(sysBusPCI, pciaddr, "net")
if _, err := os.Lstat(netDir); err != nil { if _, err := os.Lstat(netDir); err != nil {
virtioNetDir := filepath.Join(sysBusPCI, pciaddr, "virtio*", "net") virtioNetDir := filepath.Join(sysBusPCI, pciaddr, "virtio*", "net")
@ -369,12 +363,12 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
} }
netDir = matches[0] netDir = matches[0]
} }
fInfo, err := ioutil.ReadDir(netDir) entries, err := os.ReadDir(netDir)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read net directory %s: %q", netDir, err) return nil, fmt.Errorf("failed to read net directory %s: %q", netDir, err)
} }
if len(fInfo) > 0 { if len(entries) > 0 {
return netlink.LinkByName(fInfo[0].Name()) return netlink.LinkByName(entries[0].Name())
} }
return nil, fmt.Errorf("failed to find device name for pci address %s", pciaddr) return nil, fmt.Errorf("failed to find device name for pci address %s", pciaddr)
} }
@ -387,7 +381,6 @@ func main() {
} }
func cmdCheck(args *skel.CmdArgs) error { func cmdCheck(args *skel.CmdArgs) error {
cfg, err := loadConf(args.StdinData) cfg, err := loadConf(args.StdinData)
if err != nil { if err != nil {
return err return err
@ -444,7 +437,6 @@ func cmdCheck(args *skel.CmdArgs) error {
// //
// Check prevResults for ips, routes and dns against values found in the container // Check prevResults for ips, routes and dns against values found in the container
if err := netns.Do(func(_ ns.NetNS) error { if err := netns.Do(func(_ ns.NetNS) error {
// Check interface against values found in the container // Check interface against values found in the container
err := validateCniContainerInterface(contMap) err := validateCniContainerInterface(contMap)
if err != nil { if err != nil {
@ -470,7 +462,6 @@ func cmdCheck(args *skel.CmdArgs) error {
} }
func validateCniContainerInterface(intf current.Interface) error { func validateCniContainerInterface(intf current.Interface) error {
var link netlink.Link var link netlink.Link
var err error var err error

View File

@ -15,10 +15,10 @@
package main package main
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestVlan(t *testing.T) { func TestVlan(t *testing.T) {

View File

@ -17,13 +17,16 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"math/rand" "math/rand"
"net" "net"
"os" "os"
"path" "path"
"strings" "strings"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
types040 "github.com/containernetworking/cni/pkg/types/040" types040 "github.com/containernetworking/cni/pkg/types/040"
@ -31,10 +34,6 @@ import (
"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"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
) )
type Net struct { type Net struct {
@ -87,14 +86,14 @@ func canonicalizeIP(ip *net.IP) error {
// LoadIPAMConfig creates IPAMConfig using json encoded configuration provided // LoadIPAMConfig creates IPAMConfig using json encoded configuration provided
// as `bytes`. At the moment values provided in envArgs are ignored so there // as `bytes`. At the moment values provided in envArgs are ignored so there
// is no possibility to overload the json configuration using envArgs // is no possibility to overload the json configuration using envArgs
func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) { func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, error) {
n := Net{} n := Net{}
if err := json.Unmarshal(bytes, &n); err != nil { if err := json.Unmarshal(bytes, &n); err != nil {
return nil, "", err return nil, err
} }
if n.IPAM == nil { if n.IPAM == nil {
return nil, "", fmt.Errorf("IPAM config missing 'ipam' key") return nil, fmt.Errorf("IPAM config missing 'ipam' key")
} }
// Validate all ranges // Validate all ranges
@ -104,13 +103,13 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
for i := range n.IPAM.Addresses { for i := range n.IPAM.Addresses {
ip, addr, err := net.ParseCIDR(n.IPAM.Addresses[i].AddressStr) ip, addr, err := net.ParseCIDR(n.IPAM.Addresses[i].AddressStr)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("invalid CIDR %s: %s", n.IPAM.Addresses[i].AddressStr, err) return nil, fmt.Errorf("invalid CIDR %s: %s", n.IPAM.Addresses[i].AddressStr, err)
} }
n.IPAM.Addresses[i].Address = *addr n.IPAM.Addresses[i].Address = *addr
n.IPAM.Addresses[i].Address.IP = ip n.IPAM.Addresses[i].Address.IP = ip
if err := canonicalizeIP(&n.IPAM.Addresses[i].Address.IP); err != nil { if err := canonicalizeIP(&n.IPAM.Addresses[i].Address.IP); err != nil {
return nil, "", fmt.Errorf("invalid address %d: %s", i, err) return nil, fmt.Errorf("invalid address %d: %s", i, err)
} }
if n.IPAM.Addresses[i].Address.IP.To4() != nil { if n.IPAM.Addresses[i].Address.IP.To4() != nil {
@ -124,7 +123,7 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
e := IPAMEnvArgs{} e := IPAMEnvArgs{}
err := types.LoadArgs(envArgs, &e) err := types.LoadArgs(envArgs, &e)
if err != nil { if err != nil {
return nil, "", err return nil, err
} }
if e.IP != "" { if e.IP != "" {
@ -133,7 +132,7 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
ip, subnet, err := net.ParseCIDR(ipstr) ip, subnet, err := net.ParseCIDR(ipstr)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("invalid CIDR %s: %s", ipstr, err) return nil, fmt.Errorf("invalid CIDR %s: %s", ipstr, err)
} }
addr := Address{Address: net.IPNet{IP: ip, Mask: subnet.Mask}} addr := Address{Address: net.IPNet{IP: ip, Mask: subnet.Mask}}
@ -150,7 +149,7 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
for _, item := range strings.Split(string(e.GATEWAY), ",") { for _, item := range strings.Split(string(e.GATEWAY), ",") {
gwip := net.ParseIP(strings.TrimSpace(item)) gwip := net.ParseIP(strings.TrimSpace(item))
if gwip == nil { if gwip == nil {
return nil, "", fmt.Errorf("invalid gateway address: %s", item) return nil, fmt.Errorf("invalid gateway address: %s", item)
} }
for i := range n.IPAM.Addresses { for i := range n.IPAM.Addresses {
@ -165,14 +164,14 @@ 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 {
if ok, _ := version.GreaterThanOrEqualTo(n.CNIVersion, "0.3.0"); !ok { if ok, _ := version.GreaterThanOrEqualTo(n.CNIVersion, "0.3.0"); !ok {
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)
} }
} }
// Copy net name into IPAM so not to drag Net struct around // Copy net name into IPAM so not to drag Net struct around
n.IPAM.Name = n.Name n.IPAM.Name = n.Name
return n.IPAM, n.CNIVersion, nil return n.IPAM, nil
} }
func buildOneConfig(name, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) { func buildOneConfig(name, cniVersion string, orig *Net, prevResult types.Result) (*Net, error) {
@ -215,7 +214,6 @@ func buildOneConfig(name, cniVersion string, orig *Net, prevResult types.Result)
} }
return conf, nil return conf, nil
} }
type tester interface { type tester interface {
@ -225,9 +223,11 @@ type tester interface {
type testerBase struct{} type testerBase struct{}
type testerV10x testerBase type (
type testerV04x testerBase testerV10x testerBase
type testerV03x testerBase testerV04x testerBase
testerV03x testerBase
)
func newTesterByVersion(version string) tester { func newTesterByVersion(version string) tester {
switch { switch {
@ -260,8 +260,8 @@ func (t *testerV10x) expectDpdkInterfaceIP(result types.Result, ipAddress string
// check that the result was sane // check that the result was sane
res, err := types100.NewResultFromResult(result) res, err := types100.NewResultFromResult(result)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(res.Interfaces)).To(Equal(0)) Expect(res.Interfaces).To(BeEmpty())
Expect(len(res.IPs)).To(Equal(1)) Expect(res.IPs).To(HaveLen(1))
Expect(res.IPs[0].Address.String()).To(Equal(ipAddress)) Expect(res.IPs[0].Address.String()).To(Equal(ipAddress))
} }
@ -282,8 +282,8 @@ func (t *testerV04x) expectDpdkInterfaceIP(result types.Result, ipAddress string
// check that the result was sane // check that the result was sane
res, err := types040.NewResultFromResult(result) res, err := types040.NewResultFromResult(result)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(res.Interfaces)).To(Equal(0)) Expect(res.Interfaces).To(BeEmpty())
Expect(len(res.IPs)).To(Equal(1)) Expect(res.IPs).To(HaveLen(1))
Expect(res.IPs[0].Address.String()).To(Equal(ipAddress)) Expect(res.IPs[0].Address.String()).To(Equal(ipAddress))
} }
@ -304,8 +304,8 @@ func (t *testerV03x) expectDpdkInterfaceIP(result types.Result, ipAddress string
// check that the result was sane // check that the result was sane
res, err := types040.NewResultFromResult(result) res, err := types040.NewResultFromResult(result)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(res.Interfaces)).To(Equal(0)) Expect(res.Interfaces).To(BeEmpty())
Expect(len(res.IPs)).To(Equal(1)) Expect(res.IPs).To(HaveLen(1))
Expect(res.IPs[0].Address.String()).To(Equal(ipAddress)) Expect(res.IPs[0].Address.String()).To(Equal(ipAddress))
} }
@ -665,11 +665,11 @@ var _ = Describe("base functionality", func() {
Expect(link.Attrs().HardwareAddr).To(Equal(origLink.Attrs().HardwareAddr)) Expect(link.Attrs().HardwareAddr).To(Equal(origLink.Attrs().HardwareAddr))
Expect(link.Attrs().Flags & net.FlagUp).To(Equal(net.FlagUp)) Expect(link.Attrs().Flags & net.FlagUp).To(Equal(net.FlagUp))
//get the IP address of the interface in the target namespace // get the IP address of the interface in the target namespace
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
addr := addrs[0].IPNet.String() addr := addrs[0].IPNet.String()
//assert that IP address is what we set // assert that IP address is what we set
Expect(addr).To(Equal(targetIP)) Expect(addr).To(Equal(targetIP))
return nil return nil
@ -712,7 +712,6 @@ var _ = Describe("base functionality", func() {
} }
_, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) }) _, _, err := testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
Expect(err).To(MatchError(`specify either "device", "hwaddr", "kernelpath" or "pciBusID"`)) Expect(err).To(MatchError(`specify either "device", "hwaddr", "kernelpath" or "pciBusID"`))
}) })
It(fmt.Sprintf("[%s] works with a valid config without IPAM", ver), func() { It(fmt.Sprintf("[%s] works with a valid config without IPAM", ver), func() {
@ -869,7 +868,7 @@ var _ = Describe("base functionality", func() {
err = json.Unmarshal([]byte(conf), &n) err = json.Unmarshal([]byte(conf), &n)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
n.IPAM, _, err = LoadIPAMConfig([]byte(conf), "") n.IPAM, err = LoadIPAMConfig([]byte(conf), "")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if testutils.SpecVersionHasCHECK(ver) { if testutils.SpecVersionHasCHECK(ver) {
@ -962,11 +961,11 @@ var _ = Describe("base functionality", func() {
Expect(link.Attrs().HardwareAddr).To(Equal(origLink.Attrs().HardwareAddr)) Expect(link.Attrs().HardwareAddr).To(Equal(origLink.Attrs().HardwareAddr))
Expect(link.Attrs().Flags & net.FlagUp).To(Equal(net.FlagUp)) Expect(link.Attrs().Flags & net.FlagUp).To(Equal(net.FlagUp))
//get the IP address of the interface in the target namespace // get the IP address of the interface in the target namespace
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
addr := addrs[0].IPNet.String() addr := addrs[0].IPNet.String()
//assert that IP address is what we set // assert that IP address is what we set
Expect(addr).To(Equal(targetIP)) Expect(addr).To(Equal(targetIP))
return nil return nil
@ -985,7 +984,7 @@ var _ = Describe("base functionality", func() {
err = json.Unmarshal([]byte(conf), &n) err = json.Unmarshal([]byte(conf), &n)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
n.IPAM, _, err = LoadIPAMConfig([]byte(conf), "") n.IPAM, err = LoadIPAMConfig([]byte(conf), "")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if testutils.SpecVersionHasCHECK(ver) { if testutils.SpecVersionHasCHECK(ver) {
@ -1161,14 +1160,14 @@ type fakeFilesystem struct {
func (fs *fakeFilesystem) use() func() { func (fs *fakeFilesystem) use() func() {
// create the new fake fs root dir in /tmp/sriov... // create the new fake fs root dir in /tmp/sriov...
tmpDir, err := ioutil.TempDir("", "sriov") tmpDir, err := os.MkdirTemp("", "sriov")
if err != nil { if err != nil {
panic(fmt.Errorf("error creating fake root dir: %s", err.Error())) panic(fmt.Errorf("error creating fake root dir: %s", err.Error()))
} }
fs.rootDir = tmpDir fs.rootDir = tmpDir
for _, dir := range fs.dirs { for _, dir := range fs.dirs {
err := os.MkdirAll(path.Join(fs.rootDir, dir), 0755) err := os.MkdirAll(path.Join(fs.rootDir, dir), 0o755)
if err != nil { if err != nil {
panic(fmt.Errorf("error creating fake directory: %s", err.Error())) panic(fmt.Errorf("error creating fake directory: %s", err.Error()))
} }

View File

@ -26,7 +26,6 @@ import (
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" 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"
"github.com/containernetworking/plugins/pkg/ns" "github.com/containernetworking/plugins/pkg/ns"
@ -39,6 +38,7 @@ type NetConf struct {
Master string `json:"master"` Master string `json:"master"`
Mode string `json:"mode"` Mode string `json:"mode"`
MTU int `json:"mtu"` MTU int `json:"mtu"`
LinkContNs bool `json:"linkInContainer,omitempty"`
} }
func init() { func init() {
@ -48,9 +48,9 @@ func init() {
runtime.LockOSThread() runtime.LockOSThread()
} }
func loadConf(bytes []byte, cmdCheck bool) (*NetConf, string, error) { func loadConf(args *skel.CmdArgs, cmdCheck bool) (*NetConf, string, error) {
n := &NetConf{} n := &NetConf{}
if err := json.Unmarshal(bytes, n); err != nil { if err := json.Unmarshal(args.StdinData, n); err != nil {
return nil, "", fmt.Errorf("failed to load netconf: %v", err) return nil, "", fmt.Errorf("failed to load netconf: %v", err)
} }
@ -73,8 +73,8 @@ func loadConf(bytes []byte, cmdCheck bool) (*NetConf, string, error) {
} }
if n.Master == "" { if n.Master == "" {
if result == nil { if result == nil {
defaultRouteInterface, err := getDefaultRouteInterfaceName() var defaultRouteInterface string
defaultRouteInterface, err = getNamespacedDefaultRouteInterfaceName(args.Netns, n.LinkContNs)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -124,7 +124,15 @@ func createIpvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Interf
return nil, err return nil, err
} }
m, err := netlink.LinkByName(conf.Master) var m netlink.Link
if conf.LinkContNs {
err = netns.Do(func(_ ns.NetNS) error {
m, err = netlink.LinkByName(conf.Master)
return err
})
} else {
m, err = netlink.LinkByName(conf.Master)
}
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to lookup master %q: %v", conf.Master, err) return nil, fmt.Errorf("failed to lookup master %q: %v", conf.Master, err)
} }
@ -146,9 +154,15 @@ func createIpvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Interf
Mode: mode, Mode: mode,
} }
if conf.LinkContNs {
err = netns.Do(func(_ ns.NetNS) error {
return netlink.LinkAdd(mv)
})
} else {
if err := netlink.LinkAdd(mv); err != nil { if err := netlink.LinkAdd(mv); err != nil {
return nil, fmt.Errorf("failed to create ipvlan: %v", err) return nil, fmt.Errorf("failed to create ipvlan: %v", err)
} }
}
err = netns.Do(func(_ ns.NetNS) error { err = netns.Do(func(_ ns.NetNS) error {
err := ip.RenameLink(tmpName, ifName) err := ip.RenameLink(tmpName, ifName)
@ -193,8 +207,31 @@ func getDefaultRouteInterfaceName() (string, error) {
return "", fmt.Errorf("no default route interface found") return "", fmt.Errorf("no default route interface found")
} }
func getNamespacedDefaultRouteInterfaceName(namespace string, inContainer bool) (string, error) {
if !inContainer {
return getDefaultRouteInterfaceName()
}
netns, err := ns.GetNS(namespace)
if err != nil {
return "", fmt.Errorf("failed to open netns %q: %v", netns, err)
}
defer netns.Close()
var defaultRouteInterface string
err = netns.Do(func(_ ns.NetNS) error {
defaultRouteInterface, err = getDefaultRouteInterfaceName()
if err != nil {
return err
}
return nil
})
if err != nil {
return "", err
}
return defaultRouteInterface, nil
}
func cmdAdd(args *skel.CmdArgs) error { func cmdAdd(args *skel.CmdArgs) error {
n, cniVersion, err := loadConf(args.StdinData, false) n, cniVersion, err := loadConf(args, false)
if err != nil { if err != nil {
return err return err
} }
@ -257,10 +294,7 @@ func cmdAdd(args *skel.CmdArgs) error {
err = netns.Do(func(_ ns.NetNS) error { err = netns.Do(func(_ ns.NetNS) error {
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1") _, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
if err := ipam.ConfigureIface(args.IfName, result); err != nil { return ipam.ConfigureIface(args.IfName, result)
return err
}
return nil
}) })
if err != nil { if err != nil {
return err return err
@ -272,7 +306,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
func cmdDel(args *skel.CmdArgs) error { func cmdDel(args *skel.CmdArgs) error {
n, _, err := loadConf(args.StdinData, false) n, _, err := loadConf(args, false)
if err != nil { if err != nil {
return err return err
} }
@ -319,8 +353,7 @@ func main() {
} }
func cmdCheck(args *skel.CmdArgs) error { func cmdCheck(args *skel.CmdArgs) error {
n, _, err := loadConf(args, true)
n, _, err := loadConf(args.StdinData, true)
if err != nil { if err != nil {
return err return err
} }
@ -369,16 +402,23 @@ func cmdCheck(args *skel.CmdArgs) error {
contMap.Sandbox, args.Netns) contMap.Sandbox, args.Netns)
} }
m, err := netlink.LinkByName(n.Master) if n.LinkContNs {
err = netns.Do(func(_ ns.NetNS) error {
_, err = netlink.LinkByName(n.Master)
return err
})
} else {
_, err = netlink.LinkByName(n.Master)
}
if err != nil { if err != nil {
return fmt.Errorf("failed to lookup master %q: %v", n.Master, err) return fmt.Errorf("failed to lookup master %q: %v", n.Master, err)
} }
// Check prevResults for ips, routes and dns against values found in the container // Check prevResults for ips, routes and dns against values found in the container
if err := netns.Do(func(_ ns.NetNS) error { if err := netns.Do(func(_ ns.NetNS) error {
// Check interface against values found in the container // Check interface against values found in the container
err := validateCniContainerInterface(contMap, m.Attrs().Index, n.Mode) err := validateCniContainerInterface(contMap, n.Mode)
if err != nil { if err != nil {
return err return err
} }
@ -400,8 +440,7 @@ func cmdCheck(args *skel.CmdArgs) error {
return nil return nil
} }
func validateCniContainerInterface(intf current.Interface, masterIndex int, modeExpected string) error { func validateCniContainerInterface(intf current.Interface, modeExpected string) error {
var link netlink.Link var link netlink.Link
var err error var err error
@ -422,6 +461,9 @@ func validateCniContainerInterface(intf current.Interface, masterIndex int, mode
} }
mode, err := modeFromString(modeExpected) mode, err := modeFromString(modeExpected)
if err != nil {
return err
}
if ipv.Mode != mode { if ipv.Mode != mode {
currString, err := modeToString(ipv.Mode) currString, err := modeToString(ipv.Mode)
if err != nil { if err != nil {

View File

@ -15,10 +15,10 @@
package main package main
import ( import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
) )
func TestIpvlan(t *testing.T) { func TestIpvlan(t *testing.T) {

View File

@ -17,28 +17,29 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"strings" "strings"
"syscall" "syscall"
"github.com/containernetworking/cni/pkg/skel" . "github.com/onsi/ginkgo/v2"
"github.com/containernetworking/cni/pkg/types" . "github.com/onsi/gomega"
"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/testutils"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
types020 "github.com/containernetworking/cni/pkg/types/020"
types040 "github.com/containernetworking/cni/pkg/types/040"
types100 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator" "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
) )
const MASTER_NAME = "eth0" const (
MASTER_NAME = "eth0"
MASTER_NAME_INCONTAINER = "eth1"
)
type Net struct { type Net struct {
Name string `json:"name"` Name string `json:"name"`
@ -50,6 +51,7 @@ type Net struct {
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 types100.Result `json:"-"` PrevResult types100.Result `json:"-"`
LinkContNs bool `json:"linkInContainer"`
} }
func buildOneConfig(cniVersion string, master string, orig *Net, prevResult types.Result) (*Net, error) { func buildOneConfig(cniVersion string, master string, orig *Net, prevResult types.Result) (*Net, error) {
@ -91,7 +93,6 @@ func buildOneConfig(cniVersion string, master string, orig *Net, prevResult type
} }
return conf, nil return conf, nil
} }
func ipvlanAddCheckDelTest(conf, masterName string, originalNS, targetNS ns.NetNS) { func ipvlanAddCheckDelTest(conf, masterName string, originalNS, targetNS ns.NetNS) {
@ -140,7 +141,7 @@ func ipvlanAddCheckDelTest(conf, masterName string, originalNS, targetNS ns.NetN
addrs, err := netlink.AddrList(link, syscall.AF_INET) addrs, err := netlink.AddrList(link, syscall.AF_INET)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(1)) Expect(addrs).To(HaveLen(1))
return nil return nil
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -205,9 +206,11 @@ type tester interface {
type testerBase struct{} type testerBase struct{}
type testerV10x testerBase type (
type testerV04x testerBase testerV10x testerBase
type testerV02x testerBase testerV04x testerBase
testerV02x testerBase
)
func newTesterByVersion(version string) tester { func newTesterByVersion(version string) tester {
switch { switch {
@ -227,9 +230,9 @@ func (t *testerV10x) verifyResult(result types.Result, name string) string {
r, err := types100.GetResult(result) r, err := types100.GetResult(result)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(r.Interfaces)).To(Equal(1)) Expect(r.Interfaces).To(HaveLen(1))
Expect(r.Interfaces[0].Name).To(Equal(name)) Expect(r.Interfaces[0].Name).To(Equal(name))
Expect(len(r.IPs)).To(Equal(1)) Expect(r.IPs).To(HaveLen(1))
return r.Interfaces[0].Mac return r.Interfaces[0].Mac
} }
@ -239,15 +242,15 @@ func (t *testerV04x) verifyResult(result types.Result, name string) string {
r, err := types040.GetResult(result) r, err := types040.GetResult(result)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(r.Interfaces)).To(Equal(1)) Expect(r.Interfaces).To(HaveLen(1))
Expect(r.Interfaces[0].Name).To(Equal(name)) Expect(r.Interfaces[0].Name).To(Equal(name))
Expect(len(r.IPs)).To(Equal(1)) Expect(r.IPs).To(HaveLen(1))
return r.Interfaces[0].Mac return r.Interfaces[0].Mac
} }
// verifyResult minimally verifies the Result and returns the interface's MAC address // verifyResult minimally verifies the Result and returns the interface's MAC address
func (t *testerV02x) verifyResult(result types.Result, name string) string { func (t *testerV02x) verifyResult(result types.Result, _ string) string {
r, err := types020.GetResult(result) r, err := types020.GetResult(result)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -272,7 +275,7 @@ var _ = Describe("ipvlan Operations", func() {
targetNS, err = testutils.NewNS() targetNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
dataDir, err = ioutil.TempDir("", "ipvlan_test") dataDir, err = os.MkdirTemp("", "ipvlan_test")
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = originalNS.Do(func(ns.NetNS) error { err = originalNS.Do(func(ns.NetNS) error {
@ -290,6 +293,22 @@ var _ = Describe("ipvlan Operations", func() {
return nil return nil
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = targetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
// Add master
err = netlink.LinkAdd(&netlink.Dummy{
LinkAttrs: netlink.LinkAttrs{
Name: MASTER_NAME_INCONTAINER,
},
})
Expect(err).NotTo(HaveOccurred())
_, err = netlink.LinkByName(MASTER_NAME_INCONTAINER)
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
}) })
AfterEach(func() { AfterEach(func() {
@ -302,10 +321,17 @@ var _ = Describe("ipvlan Operations", func() {
Expect(testutils.UnmountNS(targetNS)).To(Succeed()) Expect(testutils.UnmountNS(targetNS)).To(Succeed())
}) })
for _, ver := range testutils.AllSpecVersions { for _, inContainer := range []bool{false, true} {
masterInterface := MASTER_NAME
if inContainer {
masterInterface = MASTER_NAME_INCONTAINER
}
// for _, ver := range testutils.AllSpecVersions {
for _, ver := range [...]string{"1.0.0"} {
// Redefine ver inside for scope so real value is picked up by each dynamically defined It() // 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. // See Gingkgo's "Patterns for dynamically generating tests" documentation.
ver := ver ver := ver
isInContainer := inContainer // Tests need a local var with constant value
It(fmt.Sprintf("[%s] creates an ipvlan link in a non-default namespace", ver), func() { It(fmt.Sprintf("[%s] creates an ipvlan link in a non-default namespace", ver), func() {
conf := &NetConf{ conf := &NetConf{
@ -314,9 +340,10 @@ var _ = Describe("ipvlan Operations", func() {
Name: "testConfig", Name: "testConfig",
Type: "ipvlan", Type: "ipvlan",
}, },
Master: MASTER_NAME, Master: masterInterface,
Mode: "l2", Mode: "l2",
MTU: 1500, MTU: 1500,
LinkContNs: isInContainer,
} }
err := originalNS.Do(func(ns.NetNS) error { err := originalNS.Do(func(ns.NetNS) error {
@ -347,12 +374,13 @@ var _ = Describe("ipvlan Operations", func() {
"name": "mynet", "name": "mynet",
"type": "ipvlan", "type": "ipvlan",
"master": "%s", "master": "%s",
"linkInContainer": %t,
"ipam": { "ipam": {
"type": "host-local", "type": "host-local",
"subnet": "10.1.2.0/24", "subnet": "10.1.2.0/24",
"dataDir": "%s" "dataDir": "%s"
} }
}`, ver, MASTER_NAME, dataDir) }`, ver, masterInterface, isInContainer, dataDir)
ipvlanAddCheckDelTest(conf, "", originalNS, targetNS) ipvlanAddCheckDelTest(conf, "", originalNS, targetNS)
}) })
@ -363,6 +391,7 @@ var _ = Describe("ipvlan Operations", func() {
"cniVersion": "%s", "cniVersion": "%s",
"name": "mynet", "name": "mynet",
"type": "ipvlan", "type": "ipvlan",
"linkInContainer": %t,
"prevResult": { "prevResult": {
"interfaces": [ "interfaces": [
{ {
@ -379,9 +408,9 @@ var _ = Describe("ipvlan Operations", func() {
], ],
"routes": [] "routes": []
} }
}`, ver, MASTER_NAME) }`, ver, isInContainer, masterInterface)
ipvlanAddCheckDelTest(conf, MASTER_NAME, originalNS, targetNS) ipvlanAddCheckDelTest(conf, masterInterface, originalNS, targetNS)
}) })
} }
@ -391,12 +420,13 @@ var _ = Describe("ipvlan Operations", func() {
"name": "mynet", "name": "mynet",
"type": "ipvlan", "type": "ipvlan",
"master": "%s", "master": "%s",
"linkInContainer": %t,
"ipam": { "ipam": {
"type": "host-local", "type": "host-local",
"subnet": "10.1.2.0/24", "subnet": "10.1.2.0/24",
"dataDir": "%s" "dataDir": "%s"
} }
}`, ver, MASTER_NAME, dataDir) }`, ver, masterInterface, isInContainer, dataDir)
args := &skel.CmdArgs{ args := &skel.CmdArgs{
ContainerID: "dummy", ContainerID: "dummy",
@ -422,24 +452,29 @@ var _ = Describe("ipvlan Operations", func() {
"cniVersion": "%s", "cniVersion": "%s",
"name": "mynet", "name": "mynet",
"type": "ipvlan", "type": "ipvlan",
"linkInContainer": %t,
"ipam": { "ipam": {
"type": "host-local", "type": "host-local",
"subnet": "10.1.2.0/24", "subnet": "10.1.2.0/24",
"dataDir": "%s" "dataDir": "%s"
} }
}`, ver, dataDir) }`, ver, isInContainer, dataDir)
// Make MASTER_NAME as default route interface // Make MASTER_NAME as default route interface
err := originalNS.Do(func(ns.NetNS) error { currentNs := originalNS
if isInContainer {
currentNs = targetNS
}
err := currentNs.Do(func(ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
link, err := netlink.LinkByName(MASTER_NAME) link, err := netlink.LinkByName(masterInterface)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = netlink.LinkSetUp(link) err = netlink.LinkSetUp(link)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
var address = &net.IPNet{IP: net.IPv4(192, 0, 0, 1), Mask: net.CIDRMask(24, 32)} address := &net.IPNet{IP: net.IPv4(192, 0, 0, 1), Mask: net.CIDRMask(24, 32)}
var addr = &netlink.Addr{IPNet: address} addr := &netlink.Addr{IPNet: address}
err = netlink.AddrAdd(link, addr) err = netlink.AddrAdd(link, addr)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -456,7 +491,8 @@ var _ = Describe("ipvlan Operations", func() {
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
ipvlanAddCheckDelTest(conf, MASTER_NAME, originalNS, targetNS) ipvlanAddCheckDelTest(conf, masterInterface, originalNS, targetNS)
}) })
} }
}
}) })

View File

@ -26,7 +26,6 @@ import (
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" 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"
bv "github.com/containernetworking/plugins/pkg/utils/buildversion" bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
) )
@ -112,7 +111,7 @@ func cmdAdd(args *skel.CmdArgs) error {
r := &current.Result{ r := &current.Result{
CNIVersion: conf.CNIVersion, CNIVersion: conf.CNIVersion,
Interfaces: []*current.Interface{ Interfaces: []*current.Interface{
&current.Interface{ {
Name: args.IfName, Name: args.IfName,
Mac: "00:00:00:00:00:00", Mac: "00:00:00:00:00:00",
Sandbox: args.Netns, Sandbox: args.Netns,

View File

@ -15,12 +15,11 @@
package main_test package main_test
import ( import (
"github.com/onsi/gomega/gexec"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing" "testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
) )
var pathToLoPlugin string var pathToLoPlugin string

View File

@ -20,12 +20,13 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/containernetworking/plugins/pkg/ns" . "github.com/onsi/ginkgo/v2"
"github.com/containernetworking/plugins/pkg/testutils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec" "github.com/onsi/gomega/gexec"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"
) )
func generateConfig(cniVersion string) *strings.Reader { func generateConfig(cniVersion string) *strings.Reader {

Some files were not shown because too many files have changed in this diff Show More